Unverified Commit c2c879a1 authored by Hong Minhee's avatar Hong Minhee
Browse files

Update docs and demo

parent 1bd31544
Loading
Loading
Loading
Loading
+23 −6
Original line number Diff line number Diff line
@@ -45,9 +45,15 @@ that the `Federation` object uses to store several kinds of cache data and
to maintain the queue of outgoing activities.

`KvStore` is an abstract interface that represents a key-value store.
Currently, there is only one implementation of `KvStore`, which is the
`MemoryKvStore` class, but you can define your own `KvStore` implementation
if you want to use a different key-value store.
Currently, there are two implementations of `KvStore`, which are the
`MemoryKvStore` and `DenoKvStore` classes.  The `MemoryKvStore` class is for
testing and development purposes, and the `DenoKvStore` class is Deno KV-backed
implementation for production use (as you can guess from the name, it is only
available in Deno runtime).  However, you can define your own `KvStore`
implementation if you want to use a different key-value store.[^1]

[^1]: We are welcome to contributions of `KvStore` implementations for other
      key-value stores.

### `kvPrefixes`

@@ -71,9 +77,20 @@ If you don't provide this option, activities will not be queued and will
be sent immediately.

`MessageQueue` is an abstract interface that represents a message queue.
Currently, there is only one implementation of `MessageQueue`, which is the
`InProcessMessageQueue` class, but you can define your own `MessageQueue`
implementation if you want to use a different message queue.
Currently, there are only two implementations of `MessageQueue`, which are
the `InProcessMessageQueue` and `DenoKvMessageQueue` classes.
The `InProcessMessageQueue` class is for testing and development purposes,
and the `DenoKvMessageQueue` class is a Deno KV-backed implementation for
production use (as you can guess from the name, it is only available in Deno
runtime).  However, you can define your own `MessageQueue` implementation if
you want to use a different message queue.[^1]

> [!IMPORTANT]
> While the `queue` option is optional, it is highly recommended to provide
> a message queue implementation in production environments.  If you don't
> provide a message queue implementation, activities will not be queued and
> will be sent immediately.  This can make delivery of activities unreliable
> and can cause performance issues.

### `documentLoader`

+31 −27
Original line number Diff line number Diff line
@@ -145,10 +145,10 @@ ActivityPub activities and actors. Let's modify the server script to use the
`Federation` object:

~~~~ typescript
import { Federation } from "@fedify/fedify";
import { Federation, MemoryKvStore } from "@fedify/fedify";

const federation = new Federation<void>({
  kv: await Deno.openKv(),
  kv: new MemoryKvStore(),
});
~~~~

@@ -156,23 +156,12 @@ In the above code, we import the `Federation` object from the Fedify framework
and create a new `Federation` object.  We pass an object to the
`new Federation()` constructor, which is the configuration object.
The `kv` property is a key-value store that is used to store several internal
data of the `Federation` object.  We use the [`Deno.openKv()`] function to open
data of the `Federation` object.  We use the `MemoryKvStore` to open
a key-value store.

> [!NOTE]
> Since the `Deno.openKv()` function is one of the unstable APIs in Deno as of
> March 2024, you need to specify the `"unstable": ["kv"]` field in
> the *deno.json* file to use the `Deno.openKv()` function.  The *deno.json*
> file should look like this:
>
> ~~~~ json
> {
>   "imports": {
>     "@fedify/fedify": "jsr:@fedify/fedify@^0.3.0"
>   },
>   "unstable": ["kv"]
> }
> ~~~~
> [!IMPORTANT]
> Since `MemoryKvStore` is for testing and development purposes, you should
> use a persistent key-value store like [`DenoKvStore`] for production use.

Then, we pass the incoming `Request` to the `federation.handle()` method:

@@ -217,10 +206,10 @@ like).
Let's create an actor dispatcher for our server:

~~~~ typescript
import { Federation, Person } from "@fedify/fedify";
import { Federation, MemoryKvStore, Person } from "@fedify/fedify";

const federation = new Federation<void>({
  kv: await Deno.openKv(),
  kv: new MemoryKvStore(),
});

federation.setActorDispatcher("/users/{handle}", async (ctx, handle) => {
@@ -371,7 +360,7 @@ set the `treatHttps` property to `true` in the `Federation` object:

~~~~ typescript
const federation = new Federation<void>({
  kv: await Deno.openKv(),
  kv: new MemoryKvStore(),
  treatHttps: true,  // Treat HTTP requests as HTTPS
});
~~~~
@@ -417,7 +406,7 @@ represents the `Follow` activity. We will use the `Follow` class to handle
incoming follow requests:

~~~~ typescript
import { Federation, Follow, Person } from "@fedify/fedify";
import { Federation, Follow, Person, MemoryKvStore } from "@fedify/fedify";
~~~~

Then, we register an inbox listener for the `Follow` activity:
@@ -493,7 +482,7 @@ Fedify provides helper functions to generate and export/import keys:

~~~~ typescript
import {
  Federation, Follow, Person,
  Federation, Follow, Person, MemoryKvStore,
  // Import helper functions:
  exportJwk, generateCryptoKeyPair, importJwk,
} from "@fedify/fedify";
@@ -513,11 +502,6 @@ should be chained after the `Federation.setActorDispatcher()` method:
~~~~ typescript
const kv = await Deno.openKv();  // Open the key-value store

const federation = new Federation<void>({
  kv,
  treatHttps: true,
});

federation
  .setActorDispatcher("/users/{handle}", async (ctx, handle, key) => {
    if (handle !== "me") return null;
@@ -564,6 +548,26 @@ at the first time and store it in the key-value store. When the actor *me* is
dispatched again, the key pair dispatcher loads the key pair from the key-value
store.

> [!IMPORTANT]
> In the above code, we use the `Deno.openKv()` function to open the key-value
> store, which is persistent.  However, Deno KV is an unstable feature as of
> March 2024, so you need to add the `"unstable": ["kv"]` field to the
> *deno.json* file:
>
> ~~~~ json
> {
>   "imports": {
>     "@fedify/fedify": "jsr:@fedify/fedify@^0.4.0"
>   },
>   "unstable": ["kv"]
> }
> ~~~~

> [!NOTE]
> Although we use the Deno KV database in this tutorial, you can use any
> other your favorite database to store the key pair.  The key-value store
> is just an example.

Restart the server and make an HTTP request to the actor *me* using `curl`.
Now you should see the actor *me* with the public key in the response:

+1 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@
    "activitypub",
    "codegen",
    "deno",
    "denokv",
    "docloader",
    "fedify",
    "fediverse",
+5 −7
Original line number Diff line number Diff line
import { Temporal } from "@js-temporal/polyfill";
import { parse } from "@std/semver";
import { dirname, join } from "@std/path";
import {
  Federation,
  InProcessMessageQueue,
  MemoryKvStore,
} from "@fedify/fedify/federation";
import { Federation } from "@fedify/fedify/federation";
import {
  Accept,
  Activity,
@@ -19,6 +15,7 @@ import {
  Person,
  Undo,
} from "@fedify/fedify/vocab";
import { DenoKvMessageQueue, DenoKvStore } from "@fedify/fedify/x/denokv";
import { getBlog } from "../models/blog.ts";
import { addComment, Comment, getComments } from "../models/comment.ts";
import {
@@ -28,15 +25,16 @@ import {
  removeFollower,
} from "../models/follower.ts";
import { countPosts, getPosts, toArticle } from "../models/post.ts";
import { openKv } from "../models/kv.ts";

// The `Federation<TContextData>` object is a registry that registers
// federation-related callbacks:
export const federation = new Federation<void>({
  // The following key-value storage is used for internal cache:
  kv: new MemoryKvStore(),
  kv: new DenoKvStore(await openKv()),

  // The following message queue is used for maintaining outgoing activities:
  queue: new InProcessMessageQueue(),
  queue: new DenoKvMessageQueue(await openKv()),

  // The following option is useful for local development, as Fresh's dev
  // server does not support HTTPS:
+2 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
    "@js-temporal/polyfill": "npm:@js-temporal/polyfill@^0.4.4",
    "@phensley/language-tag": "npm:@phensley/language-tag@^1.8.0",
    "@std/assert": "jsr:@std/assert@^0.220.1",
    "@std/async/delay": "jsr:@std/async@^0.220.1/delay",
    "@std/bytes": "jsr:@std/bytes@^0.220.1",
    "@std/collections": "jsr:@std/collections@^0.220.1",
    "@std/encoding": "jsr:@std/encoding@^0.220.1",
@@ -37,6 +38,7 @@
    "@preact/signals": "https://esm.sh/*@preact/signals@1.2.2",
    "@preact/signals-core": "https://esm.sh/*@preact/signals-core@1.5.1",
    "@std/dotenv/load": "jsr:@std/dotenv@^0.220.1/load",
    "@fedify/fedify/x/denokv": "../../x/denokv.ts",
    "markdown-it": "npm:markdown-it@^14.0.0",
    "preact": "https://esm.sh/preact@10.19.6",
    "preact/": "https://esm.sh/preact@10.19.6/",
Loading