@fedify/fedify 2.4.0-dev.1508 → 2.4.0-dev.1531
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.
- package/README.md +0 -4
- package/dist/{assert-DvVHoIZ0.mjs → assert-OguE97r2.mjs} +1 -1
- package/dist/{assert_instance_of-CxoC8bVq.mjs → assert_instance_of-DBC5X09g.mjs} +1 -1
- package/dist/{assert_not_equals-C8vcTTA3.mjs → assert_not_equals-DkVK8oqV.mjs} +1 -1
- package/dist/{assert_rejects-DAdaaIWM.mjs → assert_rejects-DN60FHPX.mjs} +2 -2
- package/dist/{assert_strict_equals-BzqyKuYL.mjs → assert_strict_equals-XEgZAlrj.mjs} +1 -1
- package/dist/{assert_throws-zN79lgIC.mjs → assert_throws-BOkhLGYc.mjs} +1 -1
- package/dist/{builder-DlWCek6Z.mjs → builder-CmQLlEE1.mjs} +3 -23
- package/dist/compat/mod.d.cts +1 -1
- package/dist/compat/mod.d.ts +1 -1
- package/dist/compat/outgoing-jsonld.test.mjs +3 -3
- package/dist/compat/public-audience.test.mjs +3 -3
- package/dist/compat/transformers.test.mjs +5 -5
- package/dist/{context-CYF8X0ft.d.cts → context-BBVLF7lx.d.cts} +272 -543
- package/dist/{context-BF5B4ZDk.d.ts → context-BU6jSQdo.d.ts} +272 -542
- package/dist/{context-BBRTgkrs.mjs → context-DVoTs_wM.mjs} +2 -8
- package/dist/{deno-nexucTAX.mjs → deno-bSDsva_4.mjs} +1 -1
- package/dist/{docloader-DAdEN549.mjs → docloader-DlmmTFJc.mjs} +3 -3
- package/dist/federation/builder.test.mjs +5 -5
- package/dist/federation/circuit-breaker.test.mjs +5 -5
- package/dist/federation/collection.test.mjs +3 -3
- package/dist/federation/handler.test.mjs +13 -13
- package/dist/federation/idempotency.test.mjs +6 -6
- package/dist/federation/inbox.test.mjs +3 -3
- package/dist/federation/keycache.test.mjs +5 -5
- package/dist/federation/kv.test.mjs +3 -3
- package/dist/federation/metrics.test.mjs +4 -4
- package/dist/federation/middleware.test.mjs +19 -200
- package/dist/federation/mod.cjs +259 -3
- package/dist/federation/mod.d.cts +4 -4
- package/dist/federation/mod.d.ts +4 -4
- package/dist/federation/mod.js +257 -1
- package/dist/federation/mq.test.mjs +261 -103
- package/dist/federation/negotiation.test.mjs +4 -4
- package/dist/federation/retry.test.mjs +3 -3
- package/dist/federation/router.test.mjs +5 -5
- package/dist/federation/send.test.mjs +10 -10
- package/dist/federation/temporal.test.mjs +4 -4
- package/dist/federation/webfinger.test.mjs +6 -6
- package/dist/{http-inQqS3yx.mjs → http-DwsK1LoE.mjs} +4 -4
- package/dist/{http-BCj9dlA_.cjs → http-bsrB-Tun.cjs} +1 -1
- package/dist/{http-Dv3147TL.js → http-yVXJ4RhY.js} +1 -1
- package/dist/{key-CGrr6-I2.mjs → key-C0aqQKRk.mjs} +2 -2
- package/dist/{kv-cache-C3qkFkbt.mjs → kv-cache-D3EQwzQ4.mjs} +1 -1
- package/dist/{kv-cache-c8X6svwE.cjs → kv-cache-Dv62PM2B.cjs} +1 -1
- package/dist/{kv-cache-C2oTEXyb.js → kv-cache-M2xxXg9M.js} +1 -1
- package/dist/{ld-fnWaNT8y.mjs → ld-CBIxjtov.mjs} +3 -3
- package/dist/{metrics-C5hMINAa.mjs → metrics-CwNvxtP6.mjs} +1 -1
- package/dist/{middleware-Dl2nyVgB.mjs → middleware-BWi34Ga3.mjs} +46 -306
- package/dist/{middleware-vQ_ZpgcX.js → middleware-BpMbjN9m.js} +31 -679
- package/dist/{middleware-DeVzbg1I.cjs → middleware-C27Pdo18.cjs} +30 -690
- package/dist/{middleware-CQlq6ykI.mjs → middleware-DiTi3jC5.mjs} +1 -1
- package/dist/{mod-BHEB3xhE.d.cts → mod-C0F6kvgS.d.cts} +1 -1
- package/dist/{mod-4WGAuR6X.d.ts → mod-vPYVoa5n.d.ts} +1 -1
- package/dist/mod.cjs +6 -6
- package/dist/mod.d.cts +5 -5
- package/dist/mod.d.ts +5 -5
- package/dist/mod.js +5 -5
- package/dist/{mq-DXMt_qCY.d.cts → mq-D-nlpY04.d.ts} +0 -34
- package/dist/{mq-B5_hohs7.d.ts → mq-D8uSFzxe.d.cts} +0 -34
- package/dist/nodeinfo/client.test.mjs +3 -3
- package/dist/nodeinfo/handler.test.mjs +5 -5
- package/dist/nodeinfo/types.test.mjs +4 -4
- package/dist/otel/exporter.test.mjs +3 -3
- package/dist/{outgoing-jsonld-BNL8AC14.mjs → outgoing-jsonld-L_DbOaFe.mjs} +1 -1
- package/dist/{owner-Bq2eZyO_.mjs → owner-SuWJf5wy.mjs} +2 -2
- package/dist/{proof-Buz7I8wj.cjs → proof-BclG-T7h.cjs} +1 -1
- package/dist/{proof-DZCjcFCd.mjs → proof-CZI5KQdk.mjs} +5 -5
- package/dist/{proof-CTG9azxN.js → proof-DMWr-n3N.js} +1 -1
- package/dist/{send-B253S5gN.mjs → send-1EADALaf.mjs} +3 -3
- package/dist/sig/accept.test.mjs +1 -1
- package/dist/sig/http.test.mjs +8 -8
- package/dist/sig/key.test.mjs +6 -6
- package/dist/sig/ld.test.mjs +7 -7
- package/dist/sig/mod.cjs +2 -2
- package/dist/sig/mod.js +2 -2
- package/dist/sig/owner.test.mjs +6 -6
- package/dist/sig/proof.test.mjs +8 -8
- package/dist/{std__assert-Dh6uLf_q.mjs → std__assert-BBjXFNOb.mjs} +4 -4
- package/dist/{temporal-d6TshGjq.mjs → temporal-GLaGoMUR.mjs} +1 -1
- package/dist/testing/mod.d.mts +8 -1037
- package/dist/testing/mod.mjs +2 -3
- package/dist/utils/docloader.test.mjs +6 -6
- package/dist/utils/kv-cache.test.mjs +1 -1
- package/dist/utils/mod.cjs +1 -1
- package/dist/utils/mod.js +1 -1
- package/package.json +7 -9
- package/dist/codec-CmlPqjNX.mjs +0 -103
- package/dist/federation/tasks/codec.test.d.mts +0 -2
- package/dist/federation/tasks/codec.test.mjs +0 -292
- package/dist/federation/tasks/enqueue.test.d.mts +0 -2
- package/dist/federation/tasks/enqueue.test.mjs +0 -992
- package/dist/federation/tasks/tasks.test.d.mts +0 -2
- package/dist/federation/tasks/tasks.test.mjs +0 -555
- package/dist/mq-03vS-C9P.mjs +0 -276
- package/dist/testing-Dy-WhqpN.mjs +0 -77
- /package/dist/{accept-CgDcxvjV.mjs → accept-CPkZzmGN.mjs} +0 -0
- /package/dist/{activity-listener-BeTGV3wc.mjs → activity-listener-tztVvlNb.mjs} +0 -0
- /package/dist/{assert_equals-PBVKNMJd.mjs → assert_equals-C-ZRDbaf.mjs} +0 -0
- /package/dist/{circuit-breaker-hJBB6jwA.mjs → circuit-breaker-CSWsyoef.mjs} +0 -0
- /package/dist/{client-B_A6mfn3.mjs → client-ByXmQhYD.mjs} +0 -0
- /package/dist/{collection-Dp5ky45w.mjs → collection-Cc3DVAhE.mjs} +0 -0
- /package/dist/{keycache-CaOR6NYg.mjs → keycache-BeU0LCII.mjs} +0 -0
- /package/dist/{keys-CSYsOMFG.mjs → keys-DGu1NFwu.mjs} +0 -0
- /package/dist/{kv-CIvR3Non.mjs → kv-rV3vodCc.mjs} +0 -0
- /package/dist/{negotiation-m_L2nyS3.mjs → negotiation-DDstyBvc.mjs} +0 -0
- /package/dist/{public-audience-c9zmYKgA.mjs → public-audience-Cvbr2Gzt.mjs} +0 -0
- /package/dist/{retry-DI4O-zYl.mjs → retry-CXg_MBI-.mjs} +0 -0
- /package/dist/{types-BFowWFTT.mjs → types-J53Kw7so.mjs} +0 -0
package/dist/testing/mod.mjs
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import "@js-temporal/polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
export { MockQueue, baseOptions, createInboxContext, createOutboxContext, createRequestContext, envelopeSchema, makeSchema, numberSchema, stringSchema, testDefinitions };
|
|
4
|
+
import { i as testDefinitions, n as createOutboxContext, r as createRequestContext, t as createInboxContext } from "../context-DVoTs_wM.mjs";
|
|
5
|
+
export { createInboxContext, createOutboxContext, createRequestContext, testDefinitions };
|
|
@@ -2,12 +2,12 @@ import { Temporal } from "@js-temporal/polyfill";
|
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { t as esm_default } from "../esm-vrlUxr60.mjs";
|
|
5
|
-
import { t as assertEquals } from "../assert_equals-
|
|
6
|
-
import "../std__assert-
|
|
7
|
-
import { t as assertRejects } from "../assert_rejects-
|
|
8
|
-
import { l as verifyRequest } from "../http-
|
|
9
|
-
import { i as rsaPrivateKey2 } from "../keys-
|
|
10
|
-
import { t as getAuthenticatedDocumentLoader } from "../docloader-
|
|
5
|
+
import { t as assertEquals } from "../assert_equals-C-ZRDbaf.mjs";
|
|
6
|
+
import "../std__assert-BBjXFNOb.mjs";
|
|
7
|
+
import { t as assertRejects } from "../assert_rejects-DN60FHPX.mjs";
|
|
8
|
+
import { l as verifyRequest } from "../http-DwsK1LoE.mjs";
|
|
9
|
+
import { i as rsaPrivateKey2 } from "../keys-DGu1NFwu.mjs";
|
|
10
|
+
import { t as getAuthenticatedDocumentLoader } from "../docloader-DlmmTFJc.mjs";
|
|
11
11
|
import { mockDocumentLoader, test } from "@fedify/fixture";
|
|
12
12
|
import { UrlError } from "@fedify/vocab-runtime";
|
|
13
13
|
//#region src/utils/docloader.test.ts
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Temporal } from "@js-temporal/polyfill";
|
|
2
2
|
import { URLPattern } from "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { n as kvCache, t as MockKvStore } from "../kv-cache-
|
|
4
|
+
import { n as kvCache, t as MockKvStore } from "../kv-cache-D3EQwzQ4.mjs";
|
|
5
5
|
import { deepStrictEqual, throws } from "node:assert";
|
|
6
6
|
import { createTestMeterProvider, mockDocumentLoader, test } from "@fedify/fixture";
|
|
7
7
|
import { preloadedContexts } from "@fedify/vocab-runtime";
|
package/dist/utils/mod.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const { Temporal } = require("@js-temporal/polyfill");
|
|
2
2
|
const { URLPattern } = require("urlpattern-polyfill");
|
|
3
3
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
4
|
-
const require_kv_cache = require("../kv-cache-
|
|
4
|
+
const require_kv_cache = require("../kv-cache-Dv62PM2B.cjs");
|
|
5
5
|
exports.getAuthenticatedDocumentLoader = require_kv_cache.getAuthenticatedDocumentLoader;
|
|
6
6
|
exports.kvCache = require_kv_cache.kvCache;
|
package/dist/utils/mod.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Temporal } from "@js-temporal/polyfill";
|
|
2
2
|
import { URLPattern } from "urlpattern-polyfill";
|
|
3
|
-
import { n as getAuthenticatedDocumentLoader, t as kvCache } from "../kv-cache-
|
|
3
|
+
import { n as getAuthenticatedDocumentLoader, t as kvCache } from "../kv-cache-M2xxXg9M.js";
|
|
4
4
|
export { getAuthenticatedDocumentLoader, kvCache };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fedify/fedify",
|
|
3
|
-
"version": "2.4.0-dev.
|
|
3
|
+
"version": "2.4.0-dev.1531+0896bc51",
|
|
4
4
|
"description": "An ActivityPub server framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ActivityPub",
|
|
@@ -143,18 +143,16 @@
|
|
|
143
143
|
"@opentelemetry/sdk-metrics": "2.7.1",
|
|
144
144
|
"@opentelemetry/sdk-trace-base": "^2.7.1",
|
|
145
145
|
"@opentelemetry/semantic-conventions": "^1.40.0",
|
|
146
|
-
"@standard-schema/spec": "^1.1.0",
|
|
147
146
|
"byte-encodings": "^1.0.11",
|
|
148
|
-
"devalue": "^5.8.1",
|
|
149
147
|
"es-toolkit": "1.46.1",
|
|
150
148
|
"json-canon": "^1.0.1",
|
|
151
149
|
"jsonld": "^9.0.0",
|
|
152
150
|
"structured-field-values": "^2.0.4",
|
|
153
151
|
"urlpattern-polyfill": "^10.1.0",
|
|
154
|
-
"@fedify/uri-template": "2.4.0-dev.
|
|
155
|
-
"@fedify/vocab": "2.4.0-dev.
|
|
156
|
-
"@fedify/vocab-runtime": "2.4.0-dev.
|
|
157
|
-
"@fedify/webfinger": "2.4.0-dev.
|
|
152
|
+
"@fedify/uri-template": "2.4.0-dev.1531+0896bc51",
|
|
153
|
+
"@fedify/vocab": "2.4.0-dev.1531+0896bc51",
|
|
154
|
+
"@fedify/vocab-runtime": "2.4.0-dev.1531+0896bc51",
|
|
155
|
+
"@fedify/webfinger": "2.4.0-dev.1531+0896bc51"
|
|
158
156
|
},
|
|
159
157
|
"devDependencies": {
|
|
160
158
|
"@std/assert": "npm:@jsr/std__assert@^0.226.0",
|
|
@@ -166,8 +164,8 @@
|
|
|
166
164
|
"tsx": "^4.21.0",
|
|
167
165
|
"typescript": "^6.0.0",
|
|
168
166
|
"wrangler": "^4.17.0",
|
|
169
|
-
"@fedify/
|
|
170
|
-
"@fedify/
|
|
167
|
+
"@fedify/fixture": "2.0.0",
|
|
168
|
+
"@fedify/vocab-tools": "^2.4.0-dev.1531+0896bc51"
|
|
171
169
|
},
|
|
172
170
|
"scripts": {
|
|
173
171
|
"build:self": "tsdown",
|
package/dist/codec-CmlPqjNX.mjs
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import "@js-temporal/polyfill";
|
|
2
|
-
import "urlpattern-polyfill";
|
|
3
|
-
globalThis.addEventListener = () => {};
|
|
4
|
-
import { Link, Object as Object$1 } from "@fedify/vocab";
|
|
5
|
-
import { parse, stringifyAsync } from "devalue";
|
|
6
|
-
//#region src/federation/tasks/codec.ts
|
|
7
|
-
/**
|
|
8
|
-
* Serializes and deserializes task payloads for the queue, preserving
|
|
9
|
-
* `@fedify/vocab` objects across the wire by reducing them to JSON-LD and
|
|
10
|
-
* rebuilding them on the worker with the bound {@link TaskCodecLoaders}.
|
|
11
|
-
* @internal
|
|
12
|
-
*/
|
|
13
|
-
var TaskCodec = class TaskCodec {
|
|
14
|
-
options;
|
|
15
|
-
constructor(options) {
|
|
16
|
-
this.options = options;
|
|
17
|
-
}
|
|
18
|
-
/** Serializes `data`, encoding any vocabulary object as its JSON-LD. */
|
|
19
|
-
serialize = (data) => stringifyAsync(data, { Vocab: this.#stringifyVocab });
|
|
20
|
-
/** Deserializes `raw`, rebuilding any encoded vocabulary object. */
|
|
21
|
-
deserialize = (raw) => this.#revive(/* @__PURE__ */ new Map())(parse(raw, { Vocab: VocabHolder.from }));
|
|
22
|
-
/** Validates `data` against `schema`, then serializes it. */
|
|
23
|
-
encode = async (schema, data) => this.serialize(await TaskCodec.validate(schema, data));
|
|
24
|
-
/** Deserializes `raw`, then validates the result against `schema`. */
|
|
25
|
-
decode = async (schema, raw) => TaskCodec.validate(schema, await this.deserialize(raw));
|
|
26
|
-
/** Validates `data` against `schema`, returning its parsed output. */
|
|
27
|
-
static validate = async (schema, data) => getValueIfSchema(await schema["~standard"].validate(data));
|
|
28
|
-
#stringifyVocab = (value) => isVocab(value) && this.#toWire(value);
|
|
29
|
-
#toWire = async (value) => ({
|
|
30
|
-
kind: value instanceof Link ? "link" : "object",
|
|
31
|
-
jsonLd: await value.toJsonLd({
|
|
32
|
-
format: "expand",
|
|
33
|
-
...this.options
|
|
34
|
-
})
|
|
35
|
-
});
|
|
36
|
-
#revive = (seen) => {
|
|
37
|
-
const inner = async (node) => {
|
|
38
|
-
if (node === null || typeof node !== "object") return node;
|
|
39
|
-
if (seen.has(node)) return seen.get(node);
|
|
40
|
-
for (const reviver of this.#classRevivers) {
|
|
41
|
-
const out = reviver(seen, inner, node);
|
|
42
|
-
if (out !== void 0) return await out;
|
|
43
|
-
}
|
|
44
|
-
return node;
|
|
45
|
-
};
|
|
46
|
-
return inner;
|
|
47
|
-
};
|
|
48
|
-
#classRevivers = [
|
|
49
|
-
classReviver(isInstanceOf(VocabHolder), ({ kind, jsonLd }) => kind === "link" ? Link.fromJsonLd(jsonLd, this.options) : Object$1.fromJsonLd(jsonLd, this.options), () => {}),
|
|
50
|
-
classReviver(isInstanceOf(Array), () => [], async (revive, node, arr) => {
|
|
51
|
-
for (const item of await Array.fromAsync(node, revive)) arr.push(item);
|
|
52
|
-
}),
|
|
53
|
-
classReviver(isInstanceOf(Map), () => /* @__PURE__ */ new Map(), async (revive, node, map) => {
|
|
54
|
-
for (const [k, v] of node) map.set(await revive(k), await revive(v));
|
|
55
|
-
}),
|
|
56
|
-
classReviver(isInstanceOf(Set), () => /* @__PURE__ */ new Set(), async (revive, node, set) => {
|
|
57
|
-
for (const v of await Array.fromAsync(node, revive)) set.add(v);
|
|
58
|
-
}),
|
|
59
|
-
classReviver(isPlainObject, () => ({}), async (revive, node, obj) => {
|
|
60
|
-
for (const [k, v] of globalThis.Object.entries(node)) obj[k] = await revive(v);
|
|
61
|
-
})
|
|
62
|
-
];
|
|
63
|
-
};
|
|
64
|
-
const isVocab = (value) => value instanceof Object$1 || value instanceof Link;
|
|
65
|
-
const isPlainObject = (value) => value === null || typeof value !== "object" ? false : isObjectPrototype(globalThis.Object.getPrototypeOf(value));
|
|
66
|
-
const isObjectPrototype = (proto) => proto === null || proto === globalThis.Object.prototype;
|
|
67
|
-
const isInstanceOf = (cls) => (v) => v instanceof cls;
|
|
68
|
-
function getValueIfSchema(result) {
|
|
69
|
-
assertSchema(result);
|
|
70
|
-
return result.value;
|
|
71
|
-
}
|
|
72
|
-
function assertSchema(result) {
|
|
73
|
-
if (result.issues && result.issues.length > 0) throw new TypeError(`Task data failed schema validation: ${JSON.stringify(result.issues)}`);
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* A vocabulary object parked by the synchronous decode reviver, held until
|
|
77
|
-
* the async revive pass can `fromJsonLd()` it back into an instance.
|
|
78
|
-
*/
|
|
79
|
-
var VocabHolder = class VocabHolder {
|
|
80
|
-
kind;
|
|
81
|
-
jsonLd;
|
|
82
|
-
constructor(kind, jsonLd) {
|
|
83
|
-
this.kind = kind;
|
|
84
|
-
this.jsonLd = jsonLd;
|
|
85
|
-
}
|
|
86
|
-
static from = ({ kind, jsonLd }) => new VocabHolder(kind, jsonLd);
|
|
87
|
-
};
|
|
88
|
-
/**
|
|
89
|
-
* Ties a container filter to its empty-shell `init` and child-filling `set`
|
|
90
|
-
* through one type parameter—a correlation the heterogeneous reviver list
|
|
91
|
-
* cannot carry, which previously forced `@ts-ignore` at the dispatch site.
|
|
92
|
-
*/
|
|
93
|
-
const classReviver = (filter, init, set) => (seen, revive, node) => {
|
|
94
|
-
if (!filter(node)) return void 0;
|
|
95
|
-
return (async () => {
|
|
96
|
-
const out = await init(node);
|
|
97
|
-
seen.set(node, out);
|
|
98
|
-
await set(revive, node, out);
|
|
99
|
-
return out;
|
|
100
|
-
})();
|
|
101
|
-
};
|
|
102
|
-
//#endregion
|
|
103
|
-
export { TaskCodec as t };
|
|
@@ -1,292 +0,0 @@
|
|
|
1
|
-
import { Temporal } from "@js-temporal/polyfill";
|
|
2
|
-
import "urlpattern-polyfill";
|
|
3
|
-
globalThis.addEventListener = () => {};
|
|
4
|
-
import { t as TaskCodec } from "../../codec-CmlPqjNX.mjs";
|
|
5
|
-
import { Create, Link, Note, Person } from "@fedify/vocab";
|
|
6
|
-
import { mockDocumentLoader, test } from "@fedify/fixture";
|
|
7
|
-
import { deepStrictEqual, ok, rejects, strictEqual } from "node:assert/strict";
|
|
8
|
-
//#region src/federation/tasks/codec.test.ts
|
|
9
|
-
const loaders = {
|
|
10
|
-
contextLoader: mockDocumentLoader,
|
|
11
|
-
documentLoader: mockDocumentLoader
|
|
12
|
-
};
|
|
13
|
-
const codec = new TaskCodec(loaders);
|
|
14
|
-
function makeSchema(check) {
|
|
15
|
-
return { "~standard": {
|
|
16
|
-
version: 1,
|
|
17
|
-
vendor: "fedify-test",
|
|
18
|
-
validate(value) {
|
|
19
|
-
return check(value) ? { value } : { issues: [{ message: "Invalid task data." }] };
|
|
20
|
-
}
|
|
21
|
-
} };
|
|
22
|
-
}
|
|
23
|
-
test("TaskCodec.serialize() / deserialize()", async (t) => {
|
|
24
|
-
const note = new Note({
|
|
25
|
-
id: new URL("https://example.com/notes/1"),
|
|
26
|
-
content: "Hello, world!"
|
|
27
|
-
});
|
|
28
|
-
const person = new Person({
|
|
29
|
-
id: new URL("https://example.com/users/alice"),
|
|
30
|
-
name: "Alice"
|
|
31
|
-
});
|
|
32
|
-
const link = new Link({
|
|
33
|
-
href: new URL("https://example.com/"),
|
|
34
|
-
mediaType: "text/html"
|
|
35
|
-
});
|
|
36
|
-
const create = new Create({
|
|
37
|
-
id: new URL("https://example.com/activities/1"),
|
|
38
|
-
actor: new URL("https://example.com/users/alice"),
|
|
39
|
-
object: note
|
|
40
|
-
});
|
|
41
|
-
await t.step("round-trips a mixed payload", async () => {
|
|
42
|
-
const payload = {
|
|
43
|
-
note,
|
|
44
|
-
when: /* @__PURE__ */ new Date("2026-01-02T03:04:05Z"),
|
|
45
|
-
big: 1234567890123456789n,
|
|
46
|
-
url: new URL("https://example.com/some/path"),
|
|
47
|
-
list: [person, link],
|
|
48
|
-
map: new Map([["create", create], ["n", 42]]),
|
|
49
|
-
set: new Set([
|
|
50
|
-
1,
|
|
51
|
-
2,
|
|
52
|
-
3
|
|
53
|
-
]),
|
|
54
|
-
nested: { create }
|
|
55
|
-
};
|
|
56
|
-
const encoded = await codec.serialize(payload);
|
|
57
|
-
strictEqual(typeof encoded, "string");
|
|
58
|
-
const decoded = await codec.deserialize(encoded);
|
|
59
|
-
ok(decoded.note instanceof Note);
|
|
60
|
-
strictEqual(decoded.note.content?.toString(), "Hello, world!");
|
|
61
|
-
strictEqual(decoded.note.id?.href, "https://example.com/notes/1");
|
|
62
|
-
ok(decoded.when instanceof Date);
|
|
63
|
-
strictEqual(decoded.when.toISOString(), "2026-01-02T03:04:05.000Z");
|
|
64
|
-
strictEqual(decoded.big, 1234567890123456789n);
|
|
65
|
-
ok(decoded.url instanceof URL);
|
|
66
|
-
strictEqual(decoded.url.href, "https://example.com/some/path");
|
|
67
|
-
const list = decoded.list;
|
|
68
|
-
ok(list[0] instanceof Person);
|
|
69
|
-
strictEqual(list[0].name?.toString(), "Alice");
|
|
70
|
-
ok(list[1] instanceof Link);
|
|
71
|
-
strictEqual(list[1].href?.href, "https://example.com/");
|
|
72
|
-
const map = decoded.map;
|
|
73
|
-
ok(map.get("create") instanceof Create);
|
|
74
|
-
strictEqual(map.get("n"), 42);
|
|
75
|
-
deepStrictEqual(decoded.set, new Set([
|
|
76
|
-
1,
|
|
77
|
-
2,
|
|
78
|
-
3
|
|
79
|
-
]));
|
|
80
|
-
const nested = decoded.nested;
|
|
81
|
-
ok(nested.create instanceof Create);
|
|
82
|
-
const nestedObject = await nested.create.getObject({
|
|
83
|
-
documentLoader: mockDocumentLoader,
|
|
84
|
-
contextLoader: mockDocumentLoader
|
|
85
|
-
});
|
|
86
|
-
ok(nestedObject instanceof Note);
|
|
87
|
-
strictEqual(nestedObject.content?.toString(), "Hello, world!");
|
|
88
|
-
});
|
|
89
|
-
await t.step("encodes vocab objects in expand form (no @context)", async () => {
|
|
90
|
-
ok(!(await codec.serialize({ note })).includes("@context"));
|
|
91
|
-
});
|
|
92
|
-
await t.step("leaves a non-vocab payload untouched", async () => {
|
|
93
|
-
const payload = {
|
|
94
|
-
text: "plain",
|
|
95
|
-
n: 1,
|
|
96
|
-
flag: true,
|
|
97
|
-
nothing: null,
|
|
98
|
-
when: /* @__PURE__ */ new Date("2026-06-10T00:00:00Z"),
|
|
99
|
-
list: [
|
|
100
|
-
1,
|
|
101
|
-
"two",
|
|
102
|
-
3n
|
|
103
|
-
]
|
|
104
|
-
};
|
|
105
|
-
const encoded = await codec.serialize(payload);
|
|
106
|
-
deepStrictEqual(await codec.deserialize(encoded), payload);
|
|
107
|
-
});
|
|
108
|
-
await t.step("throws on a malformed wire string", async () => {
|
|
109
|
-
await rejects(async () => await codec.deserialize("garbage"));
|
|
110
|
-
});
|
|
111
|
-
await t.step("preserves circular and repeated references", async () => {
|
|
112
|
-
const shared = new Note({ content: "shared" });
|
|
113
|
-
const payload = {
|
|
114
|
-
name: "root",
|
|
115
|
-
notes: [shared, shared]
|
|
116
|
-
};
|
|
117
|
-
payload.self = payload;
|
|
118
|
-
const encoded = await codec.serialize(payload);
|
|
119
|
-
const decoded = await codec.deserialize(encoded);
|
|
120
|
-
strictEqual(decoded.self, decoded);
|
|
121
|
-
ok(decoded.notes[0] instanceof Note);
|
|
122
|
-
strictEqual(decoded.notes[0], decoded.notes[1]);
|
|
123
|
-
strictEqual(decoded.notes[0].content?.toString(), "shared");
|
|
124
|
-
});
|
|
125
|
-
await t.step("preserves a cycle through an array", async () => {
|
|
126
|
-
const list = ["head"];
|
|
127
|
-
list.push(list);
|
|
128
|
-
const encoded = await codec.serialize({ list });
|
|
129
|
-
const decoded = await codec.deserialize(encoded);
|
|
130
|
-
strictEqual(decoded.list[0], "head");
|
|
131
|
-
strictEqual(decoded.list[1], decoded.list);
|
|
132
|
-
});
|
|
133
|
-
await t.step("preserves cycles re-entering at a Map and a Set", async () => {
|
|
134
|
-
const set = /* @__PURE__ */ new Set();
|
|
135
|
-
set.add({ set });
|
|
136
|
-
const map = /* @__PURE__ */ new Map();
|
|
137
|
-
map.set("entry", { map });
|
|
138
|
-
const encoded = await codec.serialize({
|
|
139
|
-
set,
|
|
140
|
-
map
|
|
141
|
-
});
|
|
142
|
-
const decoded = await codec.deserialize(encoded);
|
|
143
|
-
const [member] = decoded.set;
|
|
144
|
-
strictEqual(member.set, decoded.set);
|
|
145
|
-
strictEqual(decoded.map.get("entry")?.map, decoded.map);
|
|
146
|
-
});
|
|
147
|
-
await t.step("revives a vocab object nested in a null-prototype object", async () => {
|
|
148
|
-
const nullProto = Object.create(null);
|
|
149
|
-
nullProto.note = note;
|
|
150
|
-
const encoded = await codec.serialize({ wrap: nullProto });
|
|
151
|
-
const decoded = await codec.deserialize(encoded);
|
|
152
|
-
ok(decoded.wrap.note instanceof Note);
|
|
153
|
-
strictEqual(decoded.wrap.note.content?.toString(), "Hello, world!");
|
|
154
|
-
});
|
|
155
|
-
await t.step("revives a payload nested far deeper than any fixed depth cap", async () => {
|
|
156
|
-
const depth = 1e3;
|
|
157
|
-
let payload = new Note({ content: "deep" });
|
|
158
|
-
for (let i = 0; i < depth; i++) payload = i % 2 === 0 ? { inner: payload } : [payload];
|
|
159
|
-
const encoded = await codec.serialize(payload);
|
|
160
|
-
let decoded = await codec.deserialize(encoded);
|
|
161
|
-
for (let i = depth - 1; i >= 0; i--) decoded = i % 2 === 0 ? decoded.inner : decoded[0];
|
|
162
|
-
ok(decoded instanceof Note);
|
|
163
|
-
strictEqual(decoded.content?.toString(), "deep");
|
|
164
|
-
});
|
|
165
|
-
await t.step("round-trips an array too large to spread into push()", async () => {
|
|
166
|
-
const length = 2e5;
|
|
167
|
-
const payload = { big: Array.from({ length }, (_, i) => i) };
|
|
168
|
-
const encoded = await codec.serialize(payload);
|
|
169
|
-
const decoded = await codec.deserialize(encoded);
|
|
170
|
-
strictEqual(decoded.big.length, length);
|
|
171
|
-
strictEqual(decoded.big[0], 0);
|
|
172
|
-
strictEqual(decoded.big[length - 1], length - 1);
|
|
173
|
-
});
|
|
174
|
-
await t.step({
|
|
175
|
-
name: "round-trips Temporal values",
|
|
176
|
-
ignore: "Bun" in globalThis,
|
|
177
|
-
async fn() {
|
|
178
|
-
const payload = {
|
|
179
|
-
instant: Temporal.Instant.from("2026-01-02T03:04:05Z"),
|
|
180
|
-
duration: Temporal.Duration.from({
|
|
181
|
-
hours: 1,
|
|
182
|
-
minutes: 30
|
|
183
|
-
})
|
|
184
|
-
};
|
|
185
|
-
const encoded = await codec.serialize(payload);
|
|
186
|
-
const decoded = await codec.deserialize(encoded);
|
|
187
|
-
ok(decoded.instant instanceof Temporal.Instant);
|
|
188
|
-
ok(decoded.instant.equals(payload.instant));
|
|
189
|
-
ok(decoded.duration instanceof Temporal.Duration);
|
|
190
|
-
strictEqual(decoded.duration.toString(), payload.duration.toString());
|
|
191
|
-
}
|
|
192
|
-
});
|
|
193
|
-
});
|
|
194
|
-
test("TaskCodec (one instance reused across decodes)", async (t) => {
|
|
195
|
-
await t.step("two sequential decodes stay independent", async () => {
|
|
196
|
-
const codec = new TaskCodec(loaders);
|
|
197
|
-
const first = await codec.serialize({ note: new Note({ content: "A" }) });
|
|
198
|
-
const second = await codec.serialize({ note: new Note({ content: "B" }) });
|
|
199
|
-
const a = await codec.deserialize(first);
|
|
200
|
-
const b = await codec.deserialize(second);
|
|
201
|
-
ok(a.note instanceof Note);
|
|
202
|
-
ok(b.note instanceof Note);
|
|
203
|
-
strictEqual(a.note.content?.toString(), "A");
|
|
204
|
-
strictEqual(b.note.content?.toString(), "B");
|
|
205
|
-
});
|
|
206
|
-
});
|
|
207
|
-
test("TaskCodec.validate()", async (t) => {
|
|
208
|
-
const schema = makeSchema((data) => typeof data === "object" && data != null && data.note instanceof Note && typeof data.title === "string");
|
|
209
|
-
await t.step("accepts a payload with a vocab instanceof leaf", async () => {
|
|
210
|
-
const payload = {
|
|
211
|
-
note: new Note({ content: "Hi" }),
|
|
212
|
-
title: "greeting"
|
|
213
|
-
};
|
|
214
|
-
deepStrictEqual(await TaskCodec.validate(schema, payload), payload);
|
|
215
|
-
});
|
|
216
|
-
await t.step("rejects a wrong-shaped payload", async () => {
|
|
217
|
-
await rejects(() => TaskCodec.validate(schema, {
|
|
218
|
-
note: "not a Note",
|
|
219
|
-
title: 42
|
|
220
|
-
}), {
|
|
221
|
-
name: "TypeError",
|
|
222
|
-
message: /Task data failed schema validation/
|
|
223
|
-
});
|
|
224
|
-
});
|
|
225
|
-
await t.step("supports async validation", async () => {
|
|
226
|
-
const asyncSchema = { "~standard": {
|
|
227
|
-
version: 1,
|
|
228
|
-
vendor: "fedify-test",
|
|
229
|
-
validate: (value) => Promise.resolve(typeof value === "number" ? { value } : { issues: [{ message: "not a number" }] })
|
|
230
|
-
} };
|
|
231
|
-
strictEqual(await TaskCodec.validate(asyncSchema, 42), 42);
|
|
232
|
-
await rejects(() => TaskCodec.validate(asyncSchema, "nope"));
|
|
233
|
-
});
|
|
234
|
-
await t.step("round-trip then validate (same schema on both sides)", async () => {
|
|
235
|
-
const payload = {
|
|
236
|
-
note: new Note({ content: "Hi" }),
|
|
237
|
-
title: "greeting"
|
|
238
|
-
};
|
|
239
|
-
const encoded = await codec.serialize(payload);
|
|
240
|
-
const decoded = await codec.deserialize(encoded);
|
|
241
|
-
const validated = await TaskCodec.validate(schema, decoded);
|
|
242
|
-
ok(validated.note instanceof Note);
|
|
243
|
-
strictEqual(validated.title, "greeting");
|
|
244
|
-
strictEqual(validated.note.content?.toString(), "Hi");
|
|
245
|
-
});
|
|
246
|
-
});
|
|
247
|
-
test("TaskCodec.encode() / decode()", async (t) => {
|
|
248
|
-
const schema = makeSchema((data) => typeof data === "object" && data != null && data.note instanceof Note && typeof data.title === "string");
|
|
249
|
-
await t.step("encode() validates then serializes; decode() round-trips", async () => {
|
|
250
|
-
const payload = {
|
|
251
|
-
note: new Note({ content: "Hi" }),
|
|
252
|
-
title: "greeting"
|
|
253
|
-
};
|
|
254
|
-
const wire = await codec.encode(schema, payload);
|
|
255
|
-
strictEqual(typeof wire, "string");
|
|
256
|
-
const back = await codec.decode(schema, wire);
|
|
257
|
-
ok(back.note instanceof Note);
|
|
258
|
-
strictEqual(back.note.content?.toString(), "Hi");
|
|
259
|
-
strictEqual(back.title, "greeting");
|
|
260
|
-
});
|
|
261
|
-
await t.step("encode() rejects a wrong-shaped payload", async () => {
|
|
262
|
-
await rejects(() => codec.encode(schema, {
|
|
263
|
-
note: "nope",
|
|
264
|
-
title: 42
|
|
265
|
-
}), {
|
|
266
|
-
name: "TypeError",
|
|
267
|
-
message: /Task data failed schema validation/
|
|
268
|
-
});
|
|
269
|
-
});
|
|
270
|
-
await t.step("decode() re-validates and rejects a drifted payload", async () => {
|
|
271
|
-
const loose = makeSchema((_data) => true);
|
|
272
|
-
const wire = await codec.encode(loose, { note: "not a note" });
|
|
273
|
-
await rejects(() => codec.decode(schema, wire), {
|
|
274
|
-
name: "TypeError",
|
|
275
|
-
message: /Task data failed schema validation/
|
|
276
|
-
});
|
|
277
|
-
});
|
|
278
|
-
await t.step("a non-idempotent (transforming) schema fails to round-trip", async () => {
|
|
279
|
-
const transforming = { "~standard": {
|
|
280
|
-
version: 1,
|
|
281
|
-
vendor: "fedify-test",
|
|
282
|
-
validate: (value) => typeof value === "string" ? { value: value.length } : { issues: [{ message: "Expected a string." }] }
|
|
283
|
-
} };
|
|
284
|
-
const wire = await codec.encode(transforming, "hello");
|
|
285
|
-
await rejects(() => codec.decode(transforming, wire), {
|
|
286
|
-
name: "TypeError",
|
|
287
|
-
message: /Task data failed schema validation/
|
|
288
|
-
});
|
|
289
|
-
});
|
|
290
|
-
});
|
|
291
|
-
//#endregion
|
|
292
|
-
export {};
|