@sdxc/activitypub 0.0.0-pre.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +711 -0
  3. package/dist/collections.d.ts +67 -0
  4. package/dist/collections.js +38 -0
  5. package/dist/conformance.d.ts +80 -0
  6. package/dist/conformance.js +313 -0
  7. package/dist/discovery.d.ts +46 -0
  8. package/dist/discovery.js +105 -0
  9. package/dist/errors.d.ts +115 -0
  10. package/dist/errors.js +124 -0
  11. package/dist/federation.d.ts +281 -0
  12. package/dist/federation.js +513 -0
  13. package/dist/fixtures/gotosocial.d.ts +114 -0
  14. package/dist/fixtures/gotosocial.js +115 -0
  15. package/dist/fixtures/index.d.ts +15 -0
  16. package/dist/fixtures/index.js +50 -0
  17. package/dist/fixtures/mastodon.d.ts +489 -0
  18. package/dist/fixtures/mastodon.js +334 -0
  19. package/dist/fixtures/misskey.d.ts +254 -0
  20. package/dist/fixtures/misskey.js +163 -0
  21. package/dist/fixtures/pixelfed.d.ts +118 -0
  22. package/dist/fixtures/pixelfed.js +126 -0
  23. package/dist/fixtures/shared.d.ts +14 -0
  24. package/dist/fixtures/shared.js +14 -0
  25. package/dist/fixtures/threads.d.ts +82 -0
  26. package/dist/fixtures/threads.js +88 -0
  27. package/dist/index.d.ts +33 -0
  28. package/dist/index.js +22 -0
  29. package/dist/keys.d.ts +100 -0
  30. package/dist/keys.js +147 -0
  31. package/dist/lib/availability.d.ts +37 -0
  32. package/dist/lib/availability.js +52 -0
  33. package/dist/lib/compact.d.ts +145 -0
  34. package/dist/lib/compact.js +514 -0
  35. package/dist/lib/constants.d.ts +35 -0
  36. package/dist/lib/constants.js +65 -0
  37. package/dist/lib/delivery-fan-out.d.ts +72 -0
  38. package/dist/lib/delivery-fan-out.js +202 -0
  39. package/dist/lib/delivery-post.d.ts +108 -0
  40. package/dist/lib/delivery-post.js +318 -0
  41. package/dist/lib/fetch.d.ts +64 -0
  42. package/dist/lib/fetch.js +103 -0
  43. package/dist/lib/inbox-error.d.ts +45 -0
  44. package/dist/lib/inbox-error.js +74 -0
  45. package/dist/lib/inbox-handle.d.ts +119 -0
  46. package/dist/lib/inbox-handle.js +587 -0
  47. package/dist/lib/inbox-receive.d.ts +117 -0
  48. package/dist/lib/inbox-receive.js +233 -0
  49. package/dist/lib/inbox-signature.d.ts +61 -0
  50. package/dist/lib/inbox-signature.js +156 -0
  51. package/dist/lib/inbox-summarize.d.ts +41 -0
  52. package/dist/lib/inbox-summarize.js +97 -0
  53. package/dist/lib/messages.d.ts +36 -0
  54. package/dist/lib/messages.js +35 -0
  55. package/dist/lib/parse.d.ts +42 -0
  56. package/dist/lib/parse.js +348 -0
  57. package/dist/lib/response.d.ts +45 -0
  58. package/dist/lib/response.js +59 -0
  59. package/dist/lib/stringify.d.ts +51 -0
  60. package/dist/lib/stringify.js +122 -0
  61. package/dist/lib/tombstone.d.ts +24 -0
  62. package/dist/lib/tombstone.js +15 -0
  63. package/dist/lib/types.d.ts +249 -0
  64. package/dist/lib/types.js +0 -0
  65. package/dist/memory.d.ts +77 -0
  66. package/dist/memory.js +146 -0
  67. package/dist/remote.d.ts +105 -0
  68. package/dist/remote.js +262 -0
  69. package/dist/store.d.ts +78 -0
  70. package/dist/store.js +8 -0
  71. package/dist/testing.d.ts +12 -0
  72. package/dist/testing.js +10 -0
  73. package/package.json +54 -0
package/dist/keys.d.ts ADDED
@@ -0,0 +1,100 @@
1
+ /**
2
+ * The signing keys of a local actor: generating the RSA pair once, importing the stored
3
+ * private key with its public half derived from it, and the `publicKey` member an actor
4
+ * document publishes, plus importing a remote actor's published key for verification.
5
+ *
6
+ * @author [Sergio Xalambrí](https://sergiodxa.com)
7
+ * @copyright Sergio Xalambrí 2026
8
+ */
9
+ import type { Result } from "@sdxc/result";
10
+ import { CryptoError } from "@sdxc/crypto";
11
+ import type { ActivityPub } from "./lib/types.js";
12
+ /**
13
+ * The keys a local actor signs with: the RSA pair every HTTP signature from the actor uses,
14
+ * and the `publicKey` member its actor document publishes so remote servers can verify them.
15
+ */
16
+ export declare class ActorKeys {
17
+ /** The actor's id. */
18
+ readonly actor: string;
19
+ /** `id` is `<actor>#main-key`, the `keyId` every HTTP signature from the actor names. */
20
+ readonly rsa: ActorKeys.Rsa;
21
+ /** Present once FEP-8b32 proofs are enabled. */
22
+ readonly ed25519: ActorKeys.Ed25519 | null;
23
+ /**
24
+ * @param init - The actor and keys already imported; `ActorKeys.import` builds them from
25
+ * a stored PEM.
26
+ */
27
+ constructor(init: ActorKeys.Init);
28
+ /**
29
+ * Generates an RSA 2048 key pair for an actor. Run it once and store `privateKeyPem` as
30
+ * a secret: every follower verifies against the published half, so a new pair means an
31
+ * actor `Update` delivered to all of them.
32
+ *
33
+ * @returns Both halves as PEM, or a `CryptoError` when Web Crypto refuses.
34
+ * @example let generated = await ActorKeys.generate();
35
+ */
36
+ static generate(): Promise<Result<ActorKeys.Generated, CryptoError>>;
37
+ /**
38
+ * Imports an actor's stored private key. The public half is derived from the private
39
+ * key's JWK, so only one secret is stored and the published key always matches the
40
+ * signing one. The imported private key stays inside Web Crypto, unextractable.
41
+ *
42
+ * @param options - The actor's id and its PKCS#8 PEM.
43
+ * @returns The keys, or an `InvalidKeyError` for a PEM that is not a PKCS#8 RSA key.
44
+ * @example let keys = await ActorKeys.import({ actor: ACTOR_ID, privateKeyPem: env.ACTIVITYPUB_PRIVATE_KEY });
45
+ */
46
+ static import(options: ActorKeys.ImportOptions): Promise<Result<ActorKeys, CryptoError>>;
47
+ /** The `keyId` signatures name, `<actor>#main-key`, which is where Mastodon looks. */
48
+ get id(): string;
49
+ /**
50
+ * The `publicKey` member of the actor document, under `<actor>#main-key` with `owner`
51
+ * naming the actor, which is where Mastodon looks for the key a signature names.
52
+ *
53
+ * @example let actor = { ...ACTOR, publicKey: keys.publicKey };
54
+ */
55
+ get publicKey(): ActivityPub.PublicKey;
56
+ }
57
+ export declare namespace ActorKeys {
58
+ /** A freshly generated pair, armored for storage as secrets. */
59
+ interface Generated {
60
+ /** PKCS#8; the only value that must stay secret, and what `ActorKeys.import` reads. */
61
+ privateKeyPem: string;
62
+ /** SPKI, as an actor's `publicKey.publicKeyPem` publishes it. */
63
+ publicKeyPem: string;
64
+ }
65
+ /** What `ActorKeys.import` reads. */
66
+ interface ImportOptions {
67
+ /** The actor's id, which names the key `<actor>#main-key`. */
68
+ actor: string;
69
+ /** PKCS#8 PEM, as `ActorKeys.generate` produced it. */
70
+ privateKeyPem: string;
71
+ }
72
+ /** The RSA half every HTTP signature uses. */
73
+ interface Rsa {
74
+ id: string;
75
+ privateKey: CryptoKey;
76
+ publicKeyPem: string;
77
+ }
78
+ /** The Ed25519 key FEP-8b32 proofs are signed with. */
79
+ interface Ed25519 {
80
+ id: string;
81
+ privateKey: CryptoKey;
82
+ publicKeyMultibase: string;
83
+ }
84
+ /** Keys already imported into Web Crypto. */
85
+ interface Init {
86
+ actor: string;
87
+ rsa: Rsa;
88
+ /** @default null */
89
+ ed25519?: Ed25519 | null;
90
+ }
91
+ }
92
+ /**
93
+ * Imports a remote actor's `publicKeyPem` for verifying its signatures. SPKI RSA keys
94
+ * import as RSASSA-PKCS1-v1_5 SHA-256 and SPKI Ed25519 keys as Ed25519, the two kinds
95
+ * servers publish there.
96
+ *
97
+ * @param pem - The SPKI PEM a remote actor published.
98
+ * @returns A verify-only key, or an `InvalidKeyError` for anything else.
99
+ */
100
+ export declare function importPublicKey(pem: string): Promise<Result<CryptoKey, CryptoError>>;
package/dist/keys.js ADDED
@@ -0,0 +1,147 @@
1
+ import { CryptoError, InvalidKeyError, Pem } from "@sdxc/crypto";
2
+ import { failure, isFailure, success } from "@sdxc/result";
3
+ /** RSASSA-PKCS1-v1_5 over SHA-256, the only algorithm every Mastodon version verifies. */
4
+ const RSA_ALGORITHM = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" };
5
+ /** Ed25519, which some servers publish under `publicKeyPem` instead of an RSA key. */
6
+ const ED25519_ALGORITHM = { name: "Ed25519" };
7
+ /** The modulus length Mastodon generates, so a key this package makes looks like theirs. */
8
+ const RSA_MODULUS_LENGTH = 2048;
9
+ /** The PEM label of a PKCS#8 private key. */
10
+ const PRIVATE_KEY_LABEL = "PRIVATE KEY";
11
+ /** The PEM label of an SPKI public key, which is what `publicKeyPem` carries. */
12
+ const PUBLIC_KEY_LABEL = "PUBLIC KEY";
13
+ /** The fragment Mastodon puts its key under, and where it looks for one on an actor. */
14
+ const MAIN_KEY_FRAGMENT = "#main-key";
15
+ /**
16
+ * The keys a local actor signs with: the RSA pair every HTTP signature from the actor uses,
17
+ * and the `publicKey` member its actor document publishes so remote servers can verify them.
18
+ */
19
+ export class ActorKeys {
20
+ /** The actor's id. */
21
+ actor;
22
+ /** `id` is `<actor>#main-key`, the `keyId` every HTTP signature from the actor names. */
23
+ rsa;
24
+ /** Present once FEP-8b32 proofs are enabled. */
25
+ ed25519;
26
+ /**
27
+ * @param init - The actor and keys already imported; `ActorKeys.import` builds them from
28
+ * a stored PEM.
29
+ */
30
+ constructor(init) {
31
+ this.actor = init.actor;
32
+ this.rsa = init.rsa;
33
+ this.ed25519 = init.ed25519 ?? null;
34
+ }
35
+ /**
36
+ * Generates an RSA 2048 key pair for an actor. Run it once and store `privateKeyPem` as
37
+ * a secret: every follower verifies against the published half, so a new pair means an
38
+ * actor `Update` delivered to all of them.
39
+ *
40
+ * @returns Both halves as PEM, or a `CryptoError` when Web Crypto refuses.
41
+ * @example let generated = await ActorKeys.generate();
42
+ */
43
+ static async generate() {
44
+ let pair;
45
+ let pkcs8;
46
+ let spki;
47
+ try {
48
+ pair = await crypto.subtle.generateKey({
49
+ ...RSA_ALGORITHM,
50
+ modulusLength: RSA_MODULUS_LENGTH,
51
+ publicExponent: new Uint8Array([1, 0, 1]),
52
+ }, true, ["sign", "verify"]);
53
+ pkcs8 = await crypto.subtle.exportKey("pkcs8", pair.privateKey);
54
+ spki = await crypto.subtle.exportKey("spki", pair.publicKey);
55
+ }
56
+ catch (cause) {
57
+ return failure(new CryptoError(`Could not generate an RSA key pair: ${reasonOf(cause)}`));
58
+ }
59
+ let privateKeyPem = Pem.encode(pkcs8, PRIVATE_KEY_LABEL);
60
+ if (isFailure(privateKeyPem))
61
+ return privateKeyPem;
62
+ let publicKeyPem = Pem.encode(spki, PUBLIC_KEY_LABEL);
63
+ if (isFailure(publicKeyPem))
64
+ return publicKeyPem;
65
+ return success({ privateKeyPem: privateKeyPem.data, publicKeyPem: publicKeyPem.data });
66
+ }
67
+ /**
68
+ * Imports an actor's stored private key. The public half is derived from the private
69
+ * key's JWK, so only one secret is stored and the published key always matches the
70
+ * signing one. The imported private key stays inside Web Crypto, unextractable.
71
+ *
72
+ * @param options - The actor's id and its PKCS#8 PEM.
73
+ * @returns The keys, or an `InvalidKeyError` for a PEM that is not a PKCS#8 RSA key.
74
+ * @example let keys = await ActorKeys.import({ actor: ACTOR_ID, privateKeyPem: env.ACTIVITYPUB_PRIVATE_KEY });
75
+ */
76
+ static async import(options) {
77
+ let der = Pem.decode(options.privateKeyPem, PRIVATE_KEY_LABEL);
78
+ if (isFailure(der)) {
79
+ return failure(new InvalidKeyError("the private key must be PKCS#8 PEM (BEGIN PRIVATE KEY)"));
80
+ }
81
+ let privateKey;
82
+ let spki;
83
+ try {
84
+ let extractable = await crypto.subtle.importKey("pkcs8", der.data, RSA_ALGORITHM, true, [
85
+ "sign",
86
+ ]);
87
+ let jwk = await crypto.subtle.exportKey("jwk", extractable);
88
+ let publicKey = await crypto.subtle.importKey("jwk", { kty: "RSA", n: jwk.n, e: jwk.e, alg: "RS256", ext: true }, RSA_ALGORITHM, true, ["verify"]);
89
+ spki = await crypto.subtle.exportKey("spki", publicKey);
90
+ privateKey = await crypto.subtle.importKey("pkcs8", der.data, RSA_ALGORITHM, false, ["sign"]);
91
+ }
92
+ catch (cause) {
93
+ return failure(new InvalidKeyError(`not an RSA private key: ${reasonOf(cause)}`));
94
+ }
95
+ let publicKeyPem = Pem.encode(spki, PUBLIC_KEY_LABEL);
96
+ if (isFailure(publicKeyPem))
97
+ return publicKeyPem;
98
+ return success(new ActorKeys({
99
+ actor: options.actor,
100
+ rsa: {
101
+ id: `${options.actor}${MAIN_KEY_FRAGMENT}`,
102
+ privateKey,
103
+ publicKeyPem: publicKeyPem.data,
104
+ },
105
+ }));
106
+ }
107
+ /** The `keyId` signatures name, `<actor>#main-key`, which is where Mastodon looks. */
108
+ get id() {
109
+ return this.rsa.id;
110
+ }
111
+ /**
112
+ * The `publicKey` member of the actor document, under `<actor>#main-key` with `owner`
113
+ * naming the actor, which is where Mastodon looks for the key a signature names.
114
+ *
115
+ * @example let actor = { ...ACTOR, publicKey: keys.publicKey };
116
+ */
117
+ get publicKey() {
118
+ return { id: this.rsa.id, owner: this.actor, publicKeyPem: this.rsa.publicKeyPem };
119
+ }
120
+ }
121
+ /**
122
+ * Imports a remote actor's `publicKeyPem` for verifying its signatures. SPKI RSA keys
123
+ * import as RSASSA-PKCS1-v1_5 SHA-256 and SPKI Ed25519 keys as Ed25519, the two kinds
124
+ * servers publish there.
125
+ *
126
+ * @param pem - The SPKI PEM a remote actor published.
127
+ * @returns A verify-only key, or an `InvalidKeyError` for anything else.
128
+ */
129
+ export async function importPublicKey(pem) {
130
+ let der = Pem.decode(pem, PUBLIC_KEY_LABEL);
131
+ if (isFailure(der)) {
132
+ return failure(new InvalidKeyError("the public key must be SPKI PEM (BEGIN PUBLIC KEY)"));
133
+ }
134
+ for (let algorithm of [RSA_ALGORITHM, ED25519_ALGORITHM]) {
135
+ try {
136
+ return success(await crypto.subtle.importKey("spki", der.data, algorithm, false, ["verify"]));
137
+ }
138
+ catch {
139
+ continue;
140
+ }
141
+ }
142
+ return failure(new InvalidKeyError("the public key is neither RSA nor Ed25519"));
143
+ }
144
+ /** The message of a thrown value, for an error that wraps it. */
145
+ function reasonOf(cause) {
146
+ return cause instanceof Error ? cause.message : String(cause);
147
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Which remote origins have been failing deliveries, kept in the app's cache so fan-out
3
+ * stops queueing work for a server that has been down for days, and so one inbound
4
+ * activity that verifies from that server makes it reachable again.
5
+ *
6
+ * @author [Sergio Xalambrí](https://sergiodxa.com)
7
+ * @copyright Sergio Xalambrí 2026
8
+ */
9
+ import type { Cache } from "@sdxc/cache";
10
+ /** Failures lasting longer than this make an origin unavailable, the window Mastodon uses. */
11
+ export declare const UNAVAILABLE_AFTER: number;
12
+ /**
13
+ * Records a failed delivery to `origin`. The first failure starts the window and later
14
+ * ones keep it, so the window measures how long the origin has been failing.
15
+ *
16
+ * @param cache - The app's cache.
17
+ * @param origin - The origin of the inbox that failed.
18
+ * @param now - The current time in milliseconds.
19
+ */
20
+ export declare function recordFailure(cache: Cache, origin: string, now?: number): Promise<void>;
21
+ /**
22
+ * Clears the failure window of `origin`, after a delivery succeeded or an activity from it
23
+ * verified. A cache failure leaves the record, which costs at most a skipped delivery.
24
+ *
25
+ * @param cache - The app's cache.
26
+ * @param origin - The origin that answered.
27
+ */
28
+ export declare function recordSuccess(cache: Cache, origin: string): Promise<void>;
29
+ /**
30
+ * Whether `origin` has been failing for longer than {@link UNAVAILABLE_AFTER}. A cache
31
+ * failure reads as available, so a broken cache never stops delivery.
32
+ *
33
+ * @param cache - The app's cache.
34
+ * @param origin - The origin about to receive a delivery.
35
+ * @param now - The current time in milliseconds.
36
+ */
37
+ export declare function isUnavailable(cache: Cache, origin: string, now?: number): Promise<boolean>;
@@ -0,0 +1,52 @@
1
+ import { toMs } from "@sdxc/duration";
2
+ import { isFailure } from "@sdxc/result";
3
+ /** Failures lasting longer than this make an origin unavailable, the window Mastodon uses. */
4
+ export const UNAVAILABLE_AFTER = toMs("7 days");
5
+ /** Outlives the window, so a failing origin is still remembered when it crosses it. */
6
+ const RECORD_TTL = "30 days";
7
+ /** One entry per origin, so every inbox on a server shares its standing. */
8
+ function keyOf(origin) {
9
+ return `activitypub:unavailable:${origin}`;
10
+ }
11
+ /**
12
+ * Records a failed delivery to `origin`. The first failure starts the window and later
13
+ * ones keep it, so the window measures how long the origin has been failing.
14
+ *
15
+ * @param cache - The app's cache.
16
+ * @param origin - The origin of the inbox that failed.
17
+ * @param now - The current time in milliseconds.
18
+ */
19
+ export async function recordFailure(cache, origin, now = Date.now()) {
20
+ let current = await cache.read(keyOf(origin));
21
+ if (isFailure(current))
22
+ return;
23
+ if (current.data !== null && typeof current.data.since === "number")
24
+ return;
25
+ await cache.write(keyOf(origin), { since: now }, { ttl: RECORD_TTL });
26
+ }
27
+ /**
28
+ * Clears the failure window of `origin`, after a delivery succeeded or an activity from it
29
+ * verified. A cache failure leaves the record, which costs at most a skipped delivery.
30
+ *
31
+ * @param cache - The app's cache.
32
+ * @param origin - The origin that answered.
33
+ */
34
+ export async function recordSuccess(cache, origin) {
35
+ await cache.delete(keyOf(origin));
36
+ }
37
+ /**
38
+ * Whether `origin` has been failing for longer than {@link UNAVAILABLE_AFTER}. A cache
39
+ * failure reads as available, so a broken cache never stops delivery.
40
+ *
41
+ * @param cache - The app's cache.
42
+ * @param origin - The origin about to receive a delivery.
43
+ * @param now - The current time in milliseconds.
44
+ */
45
+ export async function isUnavailable(cache, origin, now = Date.now()) {
46
+ let current = await cache.read(keyOf(origin));
47
+ if (isFailure(current) || current.data === null)
48
+ return false;
49
+ if (typeof current.data.since !== "number")
50
+ return false;
51
+ return now - current.data.since > UNAVAILABLE_AFTER;
52
+ }
@@ -0,0 +1,145 @@
1
+ /**
2
+ * The wire variations of compacted ActivityStreams, each read into one shape: single
3
+ * values or arrays, IRIs or embedded objects, plain or language-mapped text, and every
4
+ * spelling of the public collection. JSON-LD is never expanded, so no context is fetched.
5
+ *
6
+ * @author [Sergio Xalambrí](https://sergiodxa.com)
7
+ * @copyright Sergio Xalambrí 2026
8
+ */
9
+ import type { Issue, Schema } from "remix/data-schema";
10
+ import { createSchema } from "remix/data-schema";
11
+ import type { ActivityPub } from "./types.js";
12
+ /** The path and options data-schema hands a validator, read to place nested issues. */
13
+ export type Context = Parameters<Parameters<typeof createSchema>[0]>[1];
14
+ /** A decoded JSON object, read member by member. */
15
+ export type JsonObject = Record<string, unknown>;
16
+ /**
17
+ * Whether a decoded value is a plain JSON object.
18
+ *
19
+ * @param value - Any decoded JSON value.
20
+ */
21
+ export declare function isObject(value: unknown): value is JsonObject;
22
+ /**
23
+ * Runs a schema on a member, so its issues point at that member.
24
+ *
25
+ * @param schema - The member's schema.
26
+ * @param value - The member's value.
27
+ * @param context - The enclosing value's context.
28
+ * @param key - The member name or array index.
29
+ * @template Output - What the schema produces.
30
+ */
31
+ export declare function runAt<Output>(schema: Schema<unknown, Output>, value: unknown, context: Context, key: string | number): {
32
+ value: Output;
33
+ issues?: undefined;
34
+ } | {
35
+ issues: readonly Issue[];
36
+ };
37
+ /**
38
+ * The public collection's IRI for any spelling of it; every other IRI unchanged.
39
+ *
40
+ * @param iri - An addressing entry.
41
+ */
42
+ export declare function normalizePublic(iri: string): string;
43
+ /**
44
+ * An absolute IRI, which a document's `id` must be: every ownership check compares its
45
+ * origin, and a relative one has none.
46
+ *
47
+ * @param label - The member, for the message.
48
+ */
49
+ export declare function absoluteIri(label: string): Schema<unknown, string>;
50
+ /**
51
+ * An absolute IRI that may be absent, `null` then.
52
+ *
53
+ * @param label - The member, for the message.
54
+ */
55
+ export declare function optionalAbsoluteIri(label: string): Schema<unknown, string | null>;
56
+ /**
57
+ * A `type` sent as a string or an array, read as one name: the first a caller knows,
58
+ * else the first listed. An `as:` prefix is dropped, since it names the same term.
59
+ *
60
+ * @param known - Type names to prefer when several are listed.
61
+ */
62
+ export declare function documentType(known: ReadonlySet<string>): Schema<unknown, string>;
63
+ /**
64
+ * A list of IRIs sent as one entry or an array, each an IRI or an embedded object, read
65
+ * as the IRIs alone. With `addressing`, every spelling of the public collection reads
66
+ * as `PUBLIC`.
67
+ *
68
+ * @param options - Whether the list addresses an audience.
69
+ */
70
+ export declare function iris(options?: {
71
+ addressing?: boolean;
72
+ }): Schema<unknown, string[]>;
73
+ /**
74
+ * One reference read as its IRI: a string, an embedded object's `id`, a Link's `href`, or
75
+ * the first of an array. Absent reads as `null`; with `required`, absent fails.
76
+ *
77
+ * @param options - Whether the member must be present, and its name for the message.
78
+ */
79
+ export declare function iri(options: {
80
+ required: true;
81
+ label: string;
82
+ }): Schema<unknown, string>;
83
+ export declare function iri(options?: {
84
+ required?: false;
85
+ label?: string;
86
+ }): Schema<unknown, string | null>;
87
+ /** Text that may be absent: a string, or `null` when absent. */
88
+ export declare function text(): Schema<unknown, string | null>;
89
+ /** A language map (`contentMap`, `nameMap`, `summaryMap`), empty when absent. */
90
+ export declare function languageMap(): Schema<unknown, Record<string, string>>;
91
+ /**
92
+ * The plain value of a text member, falling back to the first entry of its language map
93
+ * when a sender sent only the map.
94
+ *
95
+ * @param plain - The plain value.
96
+ * @param map - The language map.
97
+ */
98
+ export declare function withMapFallback(plain: string | null, map: Record<string, string>): string | null;
99
+ /**
100
+ * A `url` sent as a string, a `Link` or an array of them, read as the page a person
101
+ * opens: the first `text/html` link, else the first link. A member that names no link
102
+ * at all reads as `null`.
103
+ */
104
+ export declare function htmlUrl(): Schema<unknown, string | null>;
105
+ /** An ISO 8601 date, `null` when absent. */
106
+ export declare function date(): Schema<unknown, Date | null>;
107
+ /** A boolean flag, `false` when absent. */
108
+ export declare function flag(): Schema<unknown, boolean>;
109
+ /** A count such as `totalItems`, `null` when absent. */
110
+ export declare function count(): Schema<unknown, number | null>;
111
+ /**
112
+ * An image sent as a string URL or an `Image` object (or an array of them), read as an
113
+ * `Image`. A value that names no URL reads as `null`.
114
+ *
115
+ * @param value - The member's value.
116
+ */
117
+ export declare function readImage(value: unknown): ActivityPub.Image | null;
118
+ /** An `icon` or `image`, `null` when absent or naming no URL. */
119
+ export declare function image(): Schema<unknown, ActivityPub.Image | null>;
120
+ /**
121
+ * `tag` entries this package models: hashtags, mentions and custom emoji. Entries of
122
+ * other types, and entries missing what their type requires, are dropped, since a tag
123
+ * decorates an object and never decides whether it can be read.
124
+ */
125
+ export declare function tags(): Schema<unknown, ActivityPub.Tag[]>;
126
+ /**
127
+ * `attachment` entries this package models: media files and profile fields. Other
128
+ * entries are dropped, for the same reason as tags.
129
+ */
130
+ export declare function attachments(): Schema<unknown, ActivityPub.Attachment[]>;
131
+ /**
132
+ * FEP-8b32 proofs, sent as one object or a set. An entry that is not a complete
133
+ * `DataIntegrityProof` is dropped, so verification treats the document as unproven.
134
+ */
135
+ export declare function proofs(): Schema<unknown, ActivityPub.Proof[]>;
136
+ /** FEP-521a `Multikey` entries of `assertionMethod`; other verification methods are dropped. */
137
+ export declare function multikeys(): Schema<unknown, ActivityPub.Multikey[]>;
138
+ /**
139
+ * An actor's `publicKey`, sent as one object or an array whose first complete entry is
140
+ * read. A key present but missing `id`, `owner` or `publicKeyPem` fails, since no
141
+ * signature from the actor could verify against it.
142
+ */
143
+ export declare function publicKey(): Schema<unknown, ActivityPub.PublicKey | null>;
144
+ /** An actor's `endpoints`, whose `sharedInbox` is `null` when absent. */
145
+ export declare function endpoints(): Schema<unknown, ActivityPub.Endpoints>;