@fedify/fedify 2.4.0-dev.1504 → 2.4.0-dev.1528

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 (109) hide show
  1. package/README.md +10 -7
  2. package/dist/{assert-DvVHoIZ0.mjs → assert-OguE97r2.mjs} +1 -1
  3. package/dist/{assert_instance_of-CxoC8bVq.mjs → assert_instance_of-DBC5X09g.mjs} +1 -1
  4. package/dist/{assert_not_equals-C8vcTTA3.mjs → assert_not_equals-DkVK8oqV.mjs} +1 -1
  5. package/dist/{assert_rejects-DAdaaIWM.mjs → assert_rejects-DN60FHPX.mjs} +2 -2
  6. package/dist/{assert_strict_equals-BzqyKuYL.mjs → assert_strict_equals-XEgZAlrj.mjs} +1 -1
  7. package/dist/{assert_throws-zN79lgIC.mjs → assert_throws-BOkhLGYc.mjs} +1 -1
  8. package/dist/{builder-Ck0Fl_a5.mjs → builder-B6myMguW.mjs} +3 -23
  9. package/dist/compat/mod.d.cts +1 -1
  10. package/dist/compat/mod.d.ts +1 -1
  11. package/dist/compat/outgoing-jsonld.test.mjs +3 -3
  12. package/dist/compat/public-audience.test.mjs +3 -3
  13. package/dist/compat/transformers.test.mjs +5 -5
  14. package/dist/{context-CYF8X0ft.d.cts → context-BBVLF7lx.d.cts} +272 -543
  15. package/dist/{context-BF5B4ZDk.d.ts → context-BU6jSQdo.d.ts} +272 -542
  16. package/dist/{context-BBRTgkrs.mjs → context-DVoTs_wM.mjs} +2 -8
  17. package/dist/{deno-D3gb4X9v.mjs → deno-CVNsRJe9.mjs} +1 -1
  18. package/dist/{docloader-DUKu0GzG.mjs → docloader-CB8AGpw3.mjs} +3 -3
  19. package/dist/federation/builder.test.mjs +5 -5
  20. package/dist/federation/circuit-breaker.test.mjs +5 -5
  21. package/dist/federation/collection.test.mjs +3 -3
  22. package/dist/federation/handler.test.mjs +13 -13
  23. package/dist/federation/idempotency.test.mjs +6 -6
  24. package/dist/federation/inbox.test.mjs +3 -3
  25. package/dist/federation/keycache.test.mjs +5 -5
  26. package/dist/federation/kv.test.mjs +3 -3
  27. package/dist/federation/metrics.test.mjs +4 -4
  28. package/dist/federation/middleware.test.mjs +19 -200
  29. package/dist/federation/mod.cjs +259 -3
  30. package/dist/federation/mod.d.cts +4 -4
  31. package/dist/federation/mod.d.ts +4 -4
  32. package/dist/federation/mod.js +257 -1
  33. package/dist/federation/mq.test.mjs +261 -103
  34. package/dist/federation/negotiation.test.mjs +4 -4
  35. package/dist/federation/retry.test.mjs +3 -3
  36. package/dist/federation/router.test.mjs +5 -5
  37. package/dist/federation/send.test.mjs +10 -10
  38. package/dist/federation/temporal.test.mjs +4 -4
  39. package/dist/federation/webfinger.test.mjs +6 -6
  40. package/dist/{http-CrZzUAtV.js → http-B0-9u_1F.js} +17 -7
  41. package/dist/{http-D9p2_d2X.cjs → http-EkV7OslM.cjs} +17 -7
  42. package/dist/{http-BNFQkiEZ.mjs → http-L7wqkbZR.mjs} +4 -4
  43. package/dist/{key-BM_SRwBV.mjs → key-Ct8zNgGk.mjs} +18 -8
  44. package/dist/{kv-cache-BE1QIPdL.mjs → kv-cache-CUT9OGpX.mjs} +1 -1
  45. package/dist/{kv-cache-Cna211RR.cjs → kv-cache-CbB50co6.cjs} +1 -1
  46. package/dist/{kv-cache-Ch_Zv5Yq.js → kv-cache-Dh8ZoQfC.js} +1 -1
  47. package/dist/{ld-ubkf03eb.mjs → ld-D6I7H18J.mjs} +3 -3
  48. package/dist/{metrics-BXR36qzu.mjs → metrics-DvClPYaE.mjs} +1 -1
  49. package/dist/{middleware-DUNeIkXN.cjs → middleware-B0ujKP-0.cjs} +51 -694
  50. package/dist/{middleware-pzCP79He.mjs → middleware-CGqUj4XY.mjs} +1 -1
  51. package/dist/{middleware-lB4vtShP.js → middleware-DX9Fd37u.js} +52 -683
  52. package/dist/{middleware-iP9VRMus.mjs → middleware-RxFBNV2C.mjs} +67 -310
  53. package/dist/{mod-BHEB3xhE.d.cts → mod-C0F6kvgS.d.cts} +1 -1
  54. package/dist/{mod-4WGAuR6X.d.ts → mod-vPYVoa5n.d.ts} +1 -1
  55. package/dist/mod.cjs +6 -6
  56. package/dist/mod.d.cts +5 -5
  57. package/dist/mod.d.ts +5 -5
  58. package/dist/mod.js +5 -5
  59. package/dist/{mq-DXMt_qCY.d.cts → mq-D-nlpY04.d.ts} +0 -34
  60. package/dist/{mq-B5_hohs7.d.ts → mq-D8uSFzxe.d.cts} +0 -34
  61. package/dist/nodeinfo/client.test.mjs +3 -3
  62. package/dist/nodeinfo/handler.test.mjs +5 -5
  63. package/dist/nodeinfo/types.test.mjs +4 -4
  64. package/dist/otel/exporter.test.mjs +3 -3
  65. package/dist/{outgoing-jsonld-BNL8AC14.mjs → outgoing-jsonld-L_DbOaFe.mjs} +1 -1
  66. package/dist/{owner-Bf1KkncT.mjs → owner-BqPUA8Z6.mjs} +2 -2
  67. package/dist/{proof-Q781Ks5q.mjs → proof-BJKoRFBc.mjs} +5 -5
  68. package/dist/{proof-BMcsi8q_.js → proof-DCCmmEuJ.js} +1 -1
  69. package/dist/{proof-yeAU1MyT.cjs → proof-eZme7HYR.cjs} +1 -1
  70. package/dist/{send-DFV0S_n9.mjs → send-DVtEjoJ6.mjs} +3 -3
  71. package/dist/sig/accept.test.mjs +1 -1
  72. package/dist/sig/http.test.mjs +8 -8
  73. package/dist/sig/key.test.mjs +56 -6
  74. package/dist/sig/ld.test.mjs +7 -7
  75. package/dist/sig/mod.cjs +2 -2
  76. package/dist/sig/mod.js +2 -2
  77. package/dist/sig/owner.test.mjs +6 -6
  78. package/dist/sig/proof.test.mjs +8 -8
  79. package/dist/{std__assert-Dh6uLf_q.mjs → std__assert-BBjXFNOb.mjs} +4 -4
  80. package/dist/{temporal-CyOjsqPj.mjs → temporal-B06FcmVK.mjs} +1 -1
  81. package/dist/testing/mod.d.mts +8 -1037
  82. package/dist/testing/mod.mjs +2 -3
  83. package/dist/utils/docloader.test.mjs +6 -6
  84. package/dist/utils/kv-cache.test.mjs +1 -1
  85. package/dist/utils/mod.cjs +1 -1
  86. package/dist/utils/mod.js +1 -1
  87. package/package.json +7 -12
  88. package/dist/codec-CmlPqjNX.mjs +0 -103
  89. package/dist/federation/tasks/codec.test.d.mts +0 -2
  90. package/dist/federation/tasks/codec.test.mjs +0 -292
  91. package/dist/federation/tasks/enqueue.test.d.mts +0 -2
  92. package/dist/federation/tasks/enqueue.test.mjs +0 -992
  93. package/dist/federation/tasks/tasks.test.d.mts +0 -2
  94. package/dist/federation/tasks/tasks.test.mjs +0 -555
  95. package/dist/mq-03vS-C9P.mjs +0 -276
  96. package/dist/testing-Dy-WhqpN.mjs +0 -77
  97. /package/dist/{accept-CgDcxvjV.mjs → accept-CPkZzmGN.mjs} +0 -0
  98. /package/dist/{activity-listener-BeTGV3wc.mjs → activity-listener-tztVvlNb.mjs} +0 -0
  99. /package/dist/{assert_equals-PBVKNMJd.mjs → assert_equals-C-ZRDbaf.mjs} +0 -0
  100. /package/dist/{circuit-breaker-hJBB6jwA.mjs → circuit-breaker-CSWsyoef.mjs} +0 -0
  101. /package/dist/{client-B_A6mfn3.mjs → client-ByXmQhYD.mjs} +0 -0
  102. /package/dist/{collection-Dp5ky45w.mjs → collection-Cc3DVAhE.mjs} +0 -0
  103. /package/dist/{keycache-CaOR6NYg.mjs → keycache-BeU0LCII.mjs} +0 -0
  104. /package/dist/{keys-CSYsOMFG.mjs → keys-DGu1NFwu.mjs} +0 -0
  105. /package/dist/{kv-CIvR3Non.mjs → kv-rV3vodCc.mjs} +0 -0
  106. /package/dist/{negotiation-m_L2nyS3.mjs → negotiation-DDstyBvc.mjs} +0 -0
  107. /package/dist/{public-audience-c9zmYKgA.mjs → public-audience-Cvbr2Gzt.mjs} +0 -0
  108. /package/dist/{retry-DI4O-zYl.mjs → retry-CXg_MBI-.mjs} +0 -0
  109. /package/dist/{types-BFowWFTT.mjs → types-J53Kw7so.mjs} +0 -0
@@ -1,6 +1,5 @@
1
1
  import "@js-temporal/polyfill";
2
2
  import "urlpattern-polyfill";
3
3
  globalThis.addEventListener = () => {};
4
- import { a as testDefinitions, n as createOutboxContext, r as createRequestContext, t as createInboxContext } from "../context-BBRTgkrs.mjs";
5
- import { a as numberSchema, i as makeSchema, n as baseOptions, o as stringSchema, r as envelopeSchema, t as MockQueue } from "../testing-Dy-WhqpN.mjs";
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-PBVKNMJd.mjs";
6
- import "../std__assert-Dh6uLf_q.mjs";
7
- import { t as assertRejects } from "../assert_rejects-DAdaaIWM.mjs";
8
- import { l as verifyRequest } from "../http-BNFQkiEZ.mjs";
9
- import { i as rsaPrivateKey2 } from "../keys-CSYsOMFG.mjs";
10
- import { t as getAuthenticatedDocumentLoader } from "../docloader-DUKu0GzG.mjs";
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-L7wqkbZR.mjs";
9
+ import { i as rsaPrivateKey2 } from "../keys-DGu1NFwu.mjs";
10
+ import { t as getAuthenticatedDocumentLoader } from "../docloader-CB8AGpw3.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-BE1QIPdL.mjs";
4
+ import { n as kvCache, t as MockKvStore } from "../kv-cache-CUT9OGpX.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";
@@ -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-Cna211RR.cjs");
4
+ const require_kv_cache = require("../kv-cache-CbB50co6.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-Ch_Zv5Yq.js";
3
+ import { n as getAuthenticatedDocumentLoader, t as kvCache } from "../kv-cache-Dh8ZoQfC.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.1504+756217cc",
3
+ "version": "2.4.0-dev.1528+fea670ad",
4
4
  "description": "An ActivityPub server framework",
5
5
  "keywords": [
6
6
  "ActivityPub",
@@ -21,10 +21,7 @@
21
21
  "bugs": {
22
22
  "url": "https://github.com/fedify-dev/fedify/issues"
23
23
  },
24
- "funding": [
25
- "https://opencollective.com/fedify",
26
- "https://github.com/sponsors/dahlia"
27
- ],
24
+ "funding": "https://opencollective.com/fedify",
28
25
  "engines": {
29
26
  "deno": ">=2.0.0",
30
27
  "node": ">=22.0.0",
@@ -146,18 +143,16 @@
146
143
  "@opentelemetry/sdk-metrics": "2.7.1",
147
144
  "@opentelemetry/sdk-trace-base": "^2.7.1",
148
145
  "@opentelemetry/semantic-conventions": "^1.40.0",
149
- "@standard-schema/spec": "^1.1.0",
150
146
  "byte-encodings": "^1.0.11",
151
- "devalue": "^5.8.1",
152
147
  "es-toolkit": "1.46.1",
153
148
  "json-canon": "^1.0.1",
154
149
  "jsonld": "^9.0.0",
155
150
  "structured-field-values": "^2.0.4",
156
151
  "urlpattern-polyfill": "^10.1.0",
157
- "@fedify/uri-template": "2.4.0-dev.1504+756217cc",
158
- "@fedify/vocab": "2.4.0-dev.1504+756217cc",
159
- "@fedify/webfinger": "2.4.0-dev.1504+756217cc",
160
- "@fedify/vocab-runtime": "2.4.0-dev.1504+756217cc"
152
+ "@fedify/vocab": "2.4.0-dev.1528+fea670ad",
153
+ "@fedify/vocab-runtime": "2.4.0-dev.1528+fea670ad",
154
+ "@fedify/uri-template": "2.4.0-dev.1528+fea670ad",
155
+ "@fedify/webfinger": "2.4.0-dev.1528+fea670ad"
161
156
  },
162
157
  "devDependencies": {
163
158
  "@std/assert": "npm:@jsr/std__assert@^0.226.0",
@@ -170,7 +165,7 @@
170
165
  "typescript": "^6.0.0",
171
166
  "wrangler": "^4.17.0",
172
167
  "@fedify/fixture": "2.0.0",
173
- "@fedify/vocab-tools": "^2.4.0-dev.1504+756217cc"
168
+ "@fedify/vocab-tools": "^2.4.0-dev.1528+fea670ad"
174
169
  },
175
170
  "scripts": {
176
171
  "build:self": "tsdown",
@@ -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,2 +0,0 @@
1
- import { Temporal } from "@js-temporal/polyfill";
2
- import { URLPattern } from "urlpattern-polyfill";
@@ -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 {};
@@ -1,2 +0,0 @@
1
- import { Temporal } from "@js-temporal/polyfill";
2
- import { URLPattern } from "urlpattern-polyfill";