@fedify/vocab 2.1.0-dev.406 → 2.1.0-dev.408
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/deno.json +1 -1
- package/dist/actor.test.js +2 -2
- package/dist/{deno-C_9tl6Bv.js → deno-C1T-ELP0.js} +1 -1
- package/dist/endpoints.yaml +1 -0
- package/dist/lookup.test.js +2 -2
- package/dist/mod.cjs +1 -5
- package/dist/mod.js +1 -5
- package/dist/source.yaml +1 -0
- package/dist/type.test.js +1 -1
- package/dist/{vocab-D_VpV6k4.js → vocab-DNa6QysH.js} +1 -5
- package/dist/vocab.test.js +260 -2
- package/package.json +4 -4
- package/src/endpoints.yaml +1 -0
- package/src/source.yaml +1 -0
- package/src/vocab.test.ts +404 -10
package/deno.json
CHANGED
package/dist/actor.test.js
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
|
|
5
5
|
import { __export } from "./chunk-BeeFIeNn.js";
|
|
6
|
-
import { Application, Group, Organization, Person, Service, test } from "./vocab-
|
|
7
|
-
import { deno_default, esm_default } from "./deno-
|
|
6
|
+
import { Application, Group, Organization, Person, Service, test } from "./vocab-DNa6QysH.js";
|
|
7
|
+
import { deno_default, esm_default } from "./deno-C1T-ELP0.js";
|
|
8
8
|
import { getTypeId } from "./type-Dnf0m2yO.js";
|
|
9
9
|
import { SpanStatusCode, trace } from "@opentelemetry/api";
|
|
10
10
|
import { deepStrictEqual, ok, rejects, strictEqual, throws } from "node:assert/strict";
|
|
@@ -1240,7 +1240,7 @@ var esm_default = FetchMock_default;
|
|
|
1240
1240
|
//#endregion
|
|
1241
1241
|
//#region deno.json
|
|
1242
1242
|
var name = "@fedify/vocab";
|
|
1243
|
-
var version = "2.1.0-dev.
|
|
1243
|
+
var version = "2.1.0-dev.408+5c3c9d78";
|
|
1244
1244
|
var license = "MIT";
|
|
1245
1245
|
var exports = { ".": "./src/mod.ts" };
|
|
1246
1246
|
var description = "Vocabularies library for @fedify/fedify";
|
package/dist/endpoints.yaml
CHANGED
package/dist/lookup.test.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { Temporal } from "@js-temporal/polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
|
|
5
|
-
import { Collection, Note, Object as Object$1, Person, createTestTracerProvider, mockDocumentLoader, test } from "./vocab-
|
|
6
|
-
import { deno_default, esm_default } from "./deno-
|
|
5
|
+
import { Collection, Note, Object as Object$1, Person, createTestTracerProvider, mockDocumentLoader, test } from "./vocab-DNa6QysH.js";
|
|
6
|
+
import { deno_default, esm_default } from "./deno-C1T-ELP0.js";
|
|
7
7
|
import { getTypeId } from "./type-Dnf0m2yO.js";
|
|
8
8
|
import { assertInstanceOf } from "./utils-Dm0Onkcz.js";
|
|
9
9
|
import { getLogger } from "@logtape/logtape";
|
package/dist/mod.cjs
CHANGED
|
@@ -34,7 +34,7 @@ const es_toolkit = __toESM(require("es-toolkit"));
|
|
|
34
34
|
|
|
35
35
|
//#region deno.json
|
|
36
36
|
var name = "@fedify/vocab";
|
|
37
|
-
var version = "2.1.0-dev.
|
|
37
|
+
var version = "2.1.0-dev.408+5c3c9d78";
|
|
38
38
|
var license = "MIT";
|
|
39
39
|
var exports$1 = { ".": "./src/mod.ts" };
|
|
40
40
|
var description = "Vocabularies library for @fedify/fedify";
|
|
@@ -19197,7 +19197,6 @@ var Endpoints = class {
|
|
|
19197
19197
|
compactItems.push(item);
|
|
19198
19198
|
}
|
|
19199
19199
|
if (compactItems.length > 0) result["sharedInbox"] = compactItems.length > 1 ? compactItems : compactItems[0];
|
|
19200
|
-
result["type"] = "as:Endpoints";
|
|
19201
19200
|
if (this.id != null) result["id"] = this.id.href;
|
|
19202
19201
|
result["@context"] = "https://www.w3.org/ns/activitystreams";
|
|
19203
19202
|
return result;
|
|
@@ -19258,7 +19257,6 @@ var Endpoints = class {
|
|
|
19258
19257
|
const propValue = array;
|
|
19259
19258
|
values["https://www.w3.org/ns/activitystreams#sharedInbox"] = propValue;
|
|
19260
19259
|
}
|
|
19261
|
-
values["@type"] = ["https://www.w3.org/ns/activitystreams#Endpoints"];
|
|
19262
19260
|
if (this.id != null) values["@id"] = this.id.href;
|
|
19263
19261
|
if (options.format === "expand") return await jsonld.default.expand(values, { documentLoader: options.contextLoader });
|
|
19264
19262
|
const docContext = options.context ?? "https://www.w3.org/ns/activitystreams";
|
|
@@ -40028,7 +40026,6 @@ var Source = class {
|
|
|
40028
40026
|
compactItems.push(item);
|
|
40029
40027
|
}
|
|
40030
40028
|
if (compactItems.length > 0) result["mediaType"] = compactItems.length > 1 ? compactItems : compactItems[0];
|
|
40031
|
-
result["type"] = "as:Source";
|
|
40032
40029
|
if (this.id != null) result["id"] = this.id.href;
|
|
40033
40030
|
result["@context"] = "https://www.w3.org/ns/activitystreams";
|
|
40034
40031
|
return result;
|
|
@@ -40056,7 +40053,6 @@ var Source = class {
|
|
|
40056
40053
|
const propValue = array;
|
|
40057
40054
|
values["https://www.w3.org/ns/activitystreams#mediaType"] = propValue;
|
|
40058
40055
|
}
|
|
40059
|
-
values["@type"] = ["https://www.w3.org/ns/activitystreams#Source"];
|
|
40060
40056
|
if (this.id != null) values["@id"] = this.id.href;
|
|
40061
40057
|
if (options.format === "expand") return await jsonld.default.expand(values, { documentLoader: options.contextLoader });
|
|
40062
40058
|
const docContext = options.context ?? "https://www.w3.org/ns/activitystreams";
|
package/dist/mod.js
CHANGED
|
@@ -11,7 +11,7 @@ import { delay } from "es-toolkit";
|
|
|
11
11
|
|
|
12
12
|
//#region deno.json
|
|
13
13
|
var name = "@fedify/vocab";
|
|
14
|
-
var version = "2.1.0-dev.
|
|
14
|
+
var version = "2.1.0-dev.408+5c3c9d78";
|
|
15
15
|
var license = "MIT";
|
|
16
16
|
var exports = { ".": "./src/mod.ts" };
|
|
17
17
|
var description = "Vocabularies library for @fedify/fedify";
|
|
@@ -19174,7 +19174,6 @@ var Endpoints = class {
|
|
|
19174
19174
|
compactItems.push(item);
|
|
19175
19175
|
}
|
|
19176
19176
|
if (compactItems.length > 0) result["sharedInbox"] = compactItems.length > 1 ? compactItems : compactItems[0];
|
|
19177
|
-
result["type"] = "as:Endpoints";
|
|
19178
19177
|
if (this.id != null) result["id"] = this.id.href;
|
|
19179
19178
|
result["@context"] = "https://www.w3.org/ns/activitystreams";
|
|
19180
19179
|
return result;
|
|
@@ -19235,7 +19234,6 @@ var Endpoints = class {
|
|
|
19235
19234
|
const propValue = array;
|
|
19236
19235
|
values["https://www.w3.org/ns/activitystreams#sharedInbox"] = propValue;
|
|
19237
19236
|
}
|
|
19238
|
-
values["@type"] = ["https://www.w3.org/ns/activitystreams#Endpoints"];
|
|
19239
19237
|
if (this.id != null) values["@id"] = this.id.href;
|
|
19240
19238
|
if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader });
|
|
19241
19239
|
const docContext = options.context ?? "https://www.w3.org/ns/activitystreams";
|
|
@@ -40005,7 +40003,6 @@ var Source = class {
|
|
|
40005
40003
|
compactItems.push(item);
|
|
40006
40004
|
}
|
|
40007
40005
|
if (compactItems.length > 0) result["mediaType"] = compactItems.length > 1 ? compactItems : compactItems[0];
|
|
40008
|
-
result["type"] = "as:Source";
|
|
40009
40006
|
if (this.id != null) result["id"] = this.id.href;
|
|
40010
40007
|
result["@context"] = "https://www.w3.org/ns/activitystreams";
|
|
40011
40008
|
return result;
|
|
@@ -40033,7 +40030,6 @@ var Source = class {
|
|
|
40033
40030
|
const propValue = array;
|
|
40034
40031
|
values["https://www.w3.org/ns/activitystreams#mediaType"] = propValue;
|
|
40035
40032
|
}
|
|
40036
|
-
values["@type"] = ["https://www.w3.org/ns/activitystreams#Source"];
|
|
40037
40033
|
if (this.id != null) values["@id"] = this.id.href;
|
|
40038
40034
|
if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader });
|
|
40039
40035
|
const docContext = options.context ?? "https://www.w3.org/ns/activitystreams";
|
package/dist/source.yaml
CHANGED
package/dist/type.test.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { Temporal } from "@js-temporal/polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
|
|
5
|
-
import { Person, test } from "./vocab-
|
|
5
|
+
import { Person, test } from "./vocab-DNa6QysH.js";
|
|
6
6
|
import { getTypeId } from "./type-Dnf0m2yO.js";
|
|
7
7
|
import { deepStrictEqual } from "node:assert/strict";
|
|
8
8
|
|
|
@@ -25453,7 +25453,6 @@ var Endpoints = class {
|
|
|
25453
25453
|
compactItems.push(item);
|
|
25454
25454
|
}
|
|
25455
25455
|
if (compactItems.length > 0) result["sharedInbox"] = compactItems.length > 1 ? compactItems : compactItems[0];
|
|
25456
|
-
result["type"] = "as:Endpoints";
|
|
25457
25456
|
if (this.id != null) result["id"] = this.id.href;
|
|
25458
25457
|
result["@context"] = "https://www.w3.org/ns/activitystreams";
|
|
25459
25458
|
return result;
|
|
@@ -25514,7 +25513,6 @@ var Endpoints = class {
|
|
|
25514
25513
|
const propValue = array;
|
|
25515
25514
|
values["https://www.w3.org/ns/activitystreams#sharedInbox"] = propValue;
|
|
25516
25515
|
}
|
|
25517
|
-
values["@type"] = ["https://www.w3.org/ns/activitystreams#Endpoints"];
|
|
25518
25516
|
if (this.id != null) values["@id"] = this.id.href;
|
|
25519
25517
|
if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader });
|
|
25520
25518
|
const docContext = options.context ?? "https://www.w3.org/ns/activitystreams";
|
|
@@ -46284,7 +46282,6 @@ var Source = class {
|
|
|
46284
46282
|
compactItems.push(item);
|
|
46285
46283
|
}
|
|
46286
46284
|
if (compactItems.length > 0) result["mediaType"] = compactItems.length > 1 ? compactItems : compactItems[0];
|
|
46287
|
-
result["type"] = "as:Source";
|
|
46288
46285
|
if (this.id != null) result["id"] = this.id.href;
|
|
46289
46286
|
result["@context"] = "https://www.w3.org/ns/activitystreams";
|
|
46290
46287
|
return result;
|
|
@@ -46312,7 +46309,6 @@ var Source = class {
|
|
|
46312
46309
|
const propValue = array;
|
|
46313
46310
|
values["https://www.w3.org/ns/activitystreams#mediaType"] = propValue;
|
|
46314
46311
|
}
|
|
46315
|
-
values["@type"] = ["https://www.w3.org/ns/activitystreams#Source"];
|
|
46316
46312
|
if (this.id != null) values["@id"] = this.id.href;
|
|
46317
46313
|
if (options.format === "expand") return await jsonld.expand(values, { documentLoader: options.contextLoader });
|
|
46318
46314
|
const docContext = options.context ?? "https://www.w3.org/ns/activitystreams";
|
|
@@ -47833,4 +47829,4 @@ View.prototype[Symbol.for("nodejs.util.inspect.custom")] = function(_depth, opti
|
|
|
47833
47829
|
};
|
|
47834
47830
|
|
|
47835
47831
|
//#endregion
|
|
47836
|
-
export { Activity, Announce, Application, Collection, Create, CryptographicKey, Follow, Group, Hashtag, Link, Note, Object$1 as Object, OrderedCollectionPage, Organization, Person, Place, Question, Service, Source, createTestTracerProvider, mockDocumentLoader, test, vocab_exports };
|
|
47832
|
+
export { Activity, Announce, Application, Collection, Create, CryptographicKey, Endpoints, Follow, Group, Hashtag, Link, Note, Object$1 as Object, OrderedCollectionPage, Organization, Person, Place, Question, Service, Source, createTestTracerProvider, mockDocumentLoader, test, vocab_exports };
|
package/dist/vocab.test.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { Temporal } from "@js-temporal/polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
|
|
5
|
-
import { Activity, Announce, Collection, Create, CryptographicKey, Follow, Hashtag, Link, Note, Object as Object$1, OrderedCollectionPage, Person, Place, Question, Source, mockDocumentLoader, test, vocab_exports } from "./vocab-
|
|
5
|
+
import { Activity, Announce, Collection, Create, CryptographicKey, Endpoints, Follow, Hashtag, Link, Note, Object as Object$1, OrderedCollectionPage, Person, Place, Question, Source, mockDocumentLoader, test, vocab_exports } from "./vocab-DNa6QysH.js";
|
|
6
6
|
import { assertInstanceOf } from "./utils-Dm0Onkcz.js";
|
|
7
7
|
import { deepStrictEqual, notDeepStrictEqual, ok, rejects, throws } from "node:assert/strict";
|
|
8
8
|
import { LanguageString, decodeMultibase } from "@fedify/vocab-runtime";
|
|
@@ -432,6 +432,258 @@ test("Person.toJsonLd()", async () => {
|
|
|
432
432
|
type: "Person"
|
|
433
433
|
});
|
|
434
434
|
});
|
|
435
|
+
test("Endpoints.toJsonLd() omits type", async () => {
|
|
436
|
+
const ep = new Endpoints({ sharedInbox: new URL("https://example.com/inbox") });
|
|
437
|
+
const compact = await ep.toJsonLd();
|
|
438
|
+
ok(!("type" in compact), "compact heuristic output should not have 'type'");
|
|
439
|
+
deepStrictEqual(compact["sharedInbox"], "https://example.com/inbox");
|
|
440
|
+
deepStrictEqual(compact["@context"], "https://www.w3.org/ns/activitystreams");
|
|
441
|
+
const expanded = await ep.toJsonLd({
|
|
442
|
+
format: "expand",
|
|
443
|
+
contextLoader: mockDocumentLoader
|
|
444
|
+
});
|
|
445
|
+
ok(!("@type" in expanded[0]), "expanded output should not have '@type'");
|
|
446
|
+
const compactLib = await ep.toJsonLd({
|
|
447
|
+
format: "compact",
|
|
448
|
+
contextLoader: mockDocumentLoader
|
|
449
|
+
});
|
|
450
|
+
ok(!("type" in compactLib), "compact (library) output should not have 'type'");
|
|
451
|
+
const restored = await Endpoints.fromJsonLd(compact, {
|
|
452
|
+
documentLoader: mockDocumentLoader,
|
|
453
|
+
contextLoader: mockDocumentLoader
|
|
454
|
+
});
|
|
455
|
+
deepStrictEqual(restored, ep);
|
|
456
|
+
});
|
|
457
|
+
test("Source.toJsonLd() omits type", async () => {
|
|
458
|
+
const src = new Source({
|
|
459
|
+
content: "Hello, world!",
|
|
460
|
+
mediaType: "text/plain"
|
|
461
|
+
});
|
|
462
|
+
const compact = await src.toJsonLd();
|
|
463
|
+
ok(!("type" in compact), "compact heuristic output should not have 'type'");
|
|
464
|
+
deepStrictEqual(compact["mediaType"], "text/plain");
|
|
465
|
+
const expanded = await src.toJsonLd({
|
|
466
|
+
format: "expand",
|
|
467
|
+
contextLoader: mockDocumentLoader
|
|
468
|
+
});
|
|
469
|
+
ok(!("@type" in expanded[0]), "expanded output should not have '@type'");
|
|
470
|
+
const restored = await Source.fromJsonLd(compact, {
|
|
471
|
+
documentLoader: mockDocumentLoader,
|
|
472
|
+
contextLoader: mockDocumentLoader
|
|
473
|
+
});
|
|
474
|
+
deepStrictEqual(restored, src);
|
|
475
|
+
});
|
|
476
|
+
test("Endpoints.fromJsonLd() accepts input with @type (backward compat)", async () => {
|
|
477
|
+
const ep = await Endpoints.fromJsonLd({
|
|
478
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
479
|
+
"type": "as:Endpoints",
|
|
480
|
+
"sharedInbox": "https://example.com/inbox"
|
|
481
|
+
}, {
|
|
482
|
+
documentLoader: mockDocumentLoader,
|
|
483
|
+
contextLoader: mockDocumentLoader
|
|
484
|
+
});
|
|
485
|
+
assertInstanceOf(ep, Endpoints);
|
|
486
|
+
deepStrictEqual(ep.sharedInbox?.href, "https://example.com/inbox");
|
|
487
|
+
});
|
|
488
|
+
test("Source.fromJsonLd() accepts input with @type (backward compat)", async () => {
|
|
489
|
+
const src = await Source.fromJsonLd({
|
|
490
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
491
|
+
"type": "as:Source",
|
|
492
|
+
"content": "Hello",
|
|
493
|
+
"mediaType": "text/plain"
|
|
494
|
+
}, {
|
|
495
|
+
documentLoader: mockDocumentLoader,
|
|
496
|
+
contextLoader: mockDocumentLoader
|
|
497
|
+
});
|
|
498
|
+
assertInstanceOf(src, Source);
|
|
499
|
+
deepStrictEqual(src.content, "Hello");
|
|
500
|
+
deepStrictEqual(src.mediaType, "text/plain");
|
|
501
|
+
});
|
|
502
|
+
test("Endpoints with all properties set omits type", async () => {
|
|
503
|
+
const ep = new Endpoints({
|
|
504
|
+
proxyUrl: new URL("https://example.com/proxy"),
|
|
505
|
+
oauthAuthorizationEndpoint: new URL("https://example.com/oauth/authorize"),
|
|
506
|
+
oauthTokenEndpoint: new URL("https://example.com/oauth/token"),
|
|
507
|
+
provideClientKey: new URL("https://example.com/provide-key"),
|
|
508
|
+
signClientKey: new URL("https://example.com/sign-key"),
|
|
509
|
+
sharedInbox: new URL("https://example.com/inbox")
|
|
510
|
+
});
|
|
511
|
+
const compact = await ep.toJsonLd();
|
|
512
|
+
ok(!("type" in compact), "compact output should not have 'type'");
|
|
513
|
+
deepStrictEqual(compact["proxyUrl"], "https://example.com/proxy");
|
|
514
|
+
deepStrictEqual(compact["oauthAuthorizationEndpoint"], "https://example.com/oauth/authorize");
|
|
515
|
+
deepStrictEqual(compact["oauthTokenEndpoint"], "https://example.com/oauth/token");
|
|
516
|
+
deepStrictEqual(compact["provideClientKey"], "https://example.com/provide-key");
|
|
517
|
+
deepStrictEqual(compact["signClientKey"], "https://example.com/sign-key");
|
|
518
|
+
deepStrictEqual(compact["sharedInbox"], "https://example.com/inbox");
|
|
519
|
+
for (const format of [
|
|
520
|
+
void 0,
|
|
521
|
+
"compact",
|
|
522
|
+
"expand"
|
|
523
|
+
]) {
|
|
524
|
+
const jsonLd = await ep.toJsonLd({
|
|
525
|
+
format,
|
|
526
|
+
contextLoader: mockDocumentLoader
|
|
527
|
+
});
|
|
528
|
+
const restored = await Endpoints.fromJsonLd(jsonLd, {
|
|
529
|
+
documentLoader: mockDocumentLoader,
|
|
530
|
+
contextLoader: mockDocumentLoader
|
|
531
|
+
});
|
|
532
|
+
deepStrictEqual(restored, ep, `round-trip failed for format=${format ?? "heuristic"}`);
|
|
533
|
+
}
|
|
534
|
+
});
|
|
535
|
+
test("Empty Endpoints omits type", async () => {
|
|
536
|
+
const ep = new Endpoints({});
|
|
537
|
+
const compact = await ep.toJsonLd();
|
|
538
|
+
ok(!("type" in compact), "empty compact output should not have 'type'");
|
|
539
|
+
const expanded = await ep.toJsonLd({
|
|
540
|
+
format: "expand",
|
|
541
|
+
contextLoader: mockDocumentLoader
|
|
542
|
+
});
|
|
543
|
+
ok(!("@type" in (expanded[0] ?? {})), "empty expanded output should not have '@type'");
|
|
544
|
+
});
|
|
545
|
+
test("Empty Source omits type", async () => {
|
|
546
|
+
const src = new Source({});
|
|
547
|
+
const compact = await src.toJsonLd();
|
|
548
|
+
ok(!("type" in compact), "empty compact output should not have 'type'");
|
|
549
|
+
const expanded = await src.toJsonLd({
|
|
550
|
+
format: "expand",
|
|
551
|
+
contextLoader: mockDocumentLoader
|
|
552
|
+
});
|
|
553
|
+
ok(!("@type" in (expanded[0] ?? {})), "empty expanded output should not have '@type'");
|
|
554
|
+
});
|
|
555
|
+
test("Person.toJsonLd() embeds Endpoints without type", async () => {
|
|
556
|
+
const person = new Person({
|
|
557
|
+
id: new URL("https://example.com/person/1"),
|
|
558
|
+
endpoints: new Endpoints({ sharedInbox: new URL("https://example.com/inbox") })
|
|
559
|
+
});
|
|
560
|
+
const compact = await person.toJsonLd();
|
|
561
|
+
const endpoints = compact["endpoints"];
|
|
562
|
+
ok(endpoints != null, "endpoints should be present");
|
|
563
|
+
ok(!("type" in endpoints), "embedded endpoints should not have 'type'");
|
|
564
|
+
deepStrictEqual(endpoints["sharedInbox"], "https://example.com/inbox");
|
|
565
|
+
const restored = await Person.fromJsonLd(compact, {
|
|
566
|
+
documentLoader: mockDocumentLoader,
|
|
567
|
+
contextLoader: mockDocumentLoader
|
|
568
|
+
});
|
|
569
|
+
deepStrictEqual(restored.id, person.id);
|
|
570
|
+
deepStrictEqual(restored.endpoints?.sharedInbox, person.endpoints?.sharedInbox);
|
|
571
|
+
const expanded = await person.toJsonLd({
|
|
572
|
+
format: "expand",
|
|
573
|
+
contextLoader: mockDocumentLoader
|
|
574
|
+
});
|
|
575
|
+
const expandedEndpoints = expanded[0]["https://www.w3.org/ns/activitystreams#endpoints"]?.[0];
|
|
576
|
+
ok(expandedEndpoints != null, "expanded endpoints should be present");
|
|
577
|
+
ok(!("@type" in expandedEndpoints), "expanded embedded endpoints should not have '@type'");
|
|
578
|
+
const restored2 = await Person.fromJsonLd(expanded, {
|
|
579
|
+
documentLoader: mockDocumentLoader,
|
|
580
|
+
contextLoader: mockDocumentLoader
|
|
581
|
+
});
|
|
582
|
+
deepStrictEqual(restored2.endpoints?.sharedInbox, person.endpoints?.sharedInbox);
|
|
583
|
+
const compactLib = await person.toJsonLd({
|
|
584
|
+
format: "compact",
|
|
585
|
+
contextLoader: mockDocumentLoader,
|
|
586
|
+
context: "https://www.w3.org/ns/activitystreams"
|
|
587
|
+
});
|
|
588
|
+
const endpointsLib = compactLib["endpoints"];
|
|
589
|
+
ok(endpointsLib != null, "compact-lib endpoints should be present");
|
|
590
|
+
ok(!("type" in endpointsLib), "compact-lib endpoints should not have 'type'");
|
|
591
|
+
const restored3 = await Person.fromJsonLd(compactLib, {
|
|
592
|
+
documentLoader: mockDocumentLoader,
|
|
593
|
+
contextLoader: mockDocumentLoader
|
|
594
|
+
});
|
|
595
|
+
deepStrictEqual(restored3.endpoints?.sharedInbox, person.endpoints?.sharedInbox);
|
|
596
|
+
});
|
|
597
|
+
test("Object.toJsonLd() embeds Source without type", async () => {
|
|
598
|
+
const obj = new Object$1({
|
|
599
|
+
id: new URL("https://example.com/object/1"),
|
|
600
|
+
source: new Source({
|
|
601
|
+
content: "Hello, world!",
|
|
602
|
+
mediaType: "text/plain"
|
|
603
|
+
})
|
|
604
|
+
});
|
|
605
|
+
const compact = await obj.toJsonLd();
|
|
606
|
+
const source = compact["source"];
|
|
607
|
+
ok(source != null, "source should be present");
|
|
608
|
+
ok(!("type" in source), "embedded source should not have 'type'");
|
|
609
|
+
deepStrictEqual(source["mediaType"], "text/plain");
|
|
610
|
+
const restored = await Object$1.fromJsonLd(compact, {
|
|
611
|
+
documentLoader: mockDocumentLoader,
|
|
612
|
+
contextLoader: mockDocumentLoader
|
|
613
|
+
});
|
|
614
|
+
deepStrictEqual(restored.source?.content, "Hello, world!");
|
|
615
|
+
deepStrictEqual(restored.source?.mediaType, "text/plain");
|
|
616
|
+
});
|
|
617
|
+
test("Person.fromJsonLd() with Mastodon-style endpoints (no type)", async () => {
|
|
618
|
+
const person = await Person.fromJsonLd({
|
|
619
|
+
"@context": ["https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1"],
|
|
620
|
+
"id": "https://mastodon.social/users/testuser",
|
|
621
|
+
"type": "Person",
|
|
622
|
+
"preferredUsername": "testuser",
|
|
623
|
+
"inbox": "https://mastodon.social/users/testuser/inbox",
|
|
624
|
+
"outbox": "https://mastodon.social/users/testuser/outbox",
|
|
625
|
+
"endpoints": { "sharedInbox": "https://mastodon.social/inbox" }
|
|
626
|
+
}, {
|
|
627
|
+
documentLoader: mockDocumentLoader,
|
|
628
|
+
contextLoader: mockDocumentLoader
|
|
629
|
+
});
|
|
630
|
+
assertInstanceOf(person, Person);
|
|
631
|
+
deepStrictEqual(person.endpoints?.sharedInbox?.href, "https://mastodon.social/inbox");
|
|
632
|
+
});
|
|
633
|
+
test("Person.fromJsonLd() with old Fedify-style endpoints (with type)", async () => {
|
|
634
|
+
const person = await Person.fromJsonLd({
|
|
635
|
+
"@context": ["https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1"],
|
|
636
|
+
"id": "https://example.com/users/testuser",
|
|
637
|
+
"type": "Person",
|
|
638
|
+
"endpoints": {
|
|
639
|
+
"type": "as:Endpoints",
|
|
640
|
+
"sharedInbox": "https://example.com/inbox"
|
|
641
|
+
}
|
|
642
|
+
}, {
|
|
643
|
+
documentLoader: mockDocumentLoader,
|
|
644
|
+
contextLoader: mockDocumentLoader
|
|
645
|
+
});
|
|
646
|
+
assertInstanceOf(person, Person);
|
|
647
|
+
deepStrictEqual(person.endpoints?.sharedInbox?.href, "https://example.com/inbox");
|
|
648
|
+
});
|
|
649
|
+
test("Source with LanguageString content omits type", async () => {
|
|
650
|
+
const src = new Source({
|
|
651
|
+
contents: [new LanguageString("Hello", "en"), new LanguageString("Bonjour", "fr")],
|
|
652
|
+
mediaType: "text/plain"
|
|
653
|
+
});
|
|
654
|
+
const compact = await src.toJsonLd();
|
|
655
|
+
ok(!("type" in compact), "source with LanguageString should not have 'type'");
|
|
656
|
+
const restored = await Source.fromJsonLd(compact, {
|
|
657
|
+
documentLoader: mockDocumentLoader,
|
|
658
|
+
contextLoader: mockDocumentLoader
|
|
659
|
+
});
|
|
660
|
+
deepStrictEqual(restored, src);
|
|
661
|
+
});
|
|
662
|
+
test("Cross-format round-trip for Endpoints", async () => {
|
|
663
|
+
const ep = new Endpoints({
|
|
664
|
+
sharedInbox: new URL("https://example.com/inbox"),
|
|
665
|
+
proxyUrl: new URL("https://example.com/proxy")
|
|
666
|
+
});
|
|
667
|
+
const compact1 = await ep.toJsonLd();
|
|
668
|
+
const restored1 = await Endpoints.fromJsonLd(compact1, {
|
|
669
|
+
documentLoader: mockDocumentLoader,
|
|
670
|
+
contextLoader: mockDocumentLoader
|
|
671
|
+
});
|
|
672
|
+
const expanded = await restored1.toJsonLd({
|
|
673
|
+
format: "expand",
|
|
674
|
+
contextLoader: mockDocumentLoader
|
|
675
|
+
});
|
|
676
|
+
const restored2 = await Endpoints.fromJsonLd(expanded, {
|
|
677
|
+
documentLoader: mockDocumentLoader,
|
|
678
|
+
contextLoader: mockDocumentLoader
|
|
679
|
+
});
|
|
680
|
+
const compact2 = await restored2.toJsonLd({ contextLoader: mockDocumentLoader });
|
|
681
|
+
const restored3 = await Endpoints.fromJsonLd(compact2, {
|
|
682
|
+
documentLoader: mockDocumentLoader,
|
|
683
|
+
contextLoader: mockDocumentLoader
|
|
684
|
+
});
|
|
685
|
+
deepStrictEqual(restored3, ep);
|
|
686
|
+
});
|
|
435
687
|
test("Collection.fromJsonLd()", async () => {
|
|
436
688
|
const collection = await Collection.fromJsonLd({
|
|
437
689
|
"@context": ["https://www.w3.org/ns/activitystreams", "https://w3id.org/fep/5711"],
|
|
@@ -1212,7 +1464,13 @@ for (const typeUri in types) {
|
|
|
1212
1464
|
"@id": "https://example.com/",
|
|
1213
1465
|
"@type": typeUri
|
|
1214
1466
|
});
|
|
1215
|
-
|
|
1467
|
+
if (type.typeless) {
|
|
1468
|
+
const compactJsonLd = await instance.toJsonLd({
|
|
1469
|
+
format: "compact",
|
|
1470
|
+
contextLoader: mockDocumentLoader
|
|
1471
|
+
});
|
|
1472
|
+
ok(!("type" in compactJsonLd), `${type.name} is typeless; compact output should not have 'type'`);
|
|
1473
|
+
} else deepStrictEqual(await instance.toJsonLd({
|
|
1216
1474
|
format: "compact",
|
|
1217
1475
|
contextLoader: mockDocumentLoader
|
|
1218
1476
|
}), {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fedify/vocab",
|
|
3
|
-
"version": "2.1.0-dev.
|
|
3
|
+
"version": "2.1.0-dev.408+5c3c9d78",
|
|
4
4
|
"homepage": "https://fedify.dev/",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -47,9 +47,9 @@
|
|
|
47
47
|
"jsonld": "^9.0.0",
|
|
48
48
|
"multicodec": "^3.2.1",
|
|
49
49
|
"pkijs": "^3.3.3",
|
|
50
|
-
"@fedify/
|
|
51
|
-
"@fedify/vocab-runtime": "2.1.0-dev.
|
|
52
|
-
"@fedify/
|
|
50
|
+
"@fedify/vocab-tools": "2.1.0-dev.408+5c3c9d78",
|
|
51
|
+
"@fedify/vocab-runtime": "2.1.0-dev.408+5c3c9d78",
|
|
52
|
+
"@fedify/webfinger": "2.1.0-dev.408+5c3c9d78"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@types/node": "^22.17.0",
|
package/src/endpoints.yaml
CHANGED
package/src/source.yaml
CHANGED
package/src/vocab.test.ts
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
Create,
|
|
24
24
|
CryptographicKey,
|
|
25
25
|
type DataIntegrityProof,
|
|
26
|
+
Endpoints,
|
|
26
27
|
Follow,
|
|
27
28
|
Hashtag,
|
|
28
29
|
Link,
|
|
@@ -656,6 +657,388 @@ test("Person.toJsonLd()", async () => {
|
|
|
656
657
|
});
|
|
657
658
|
});
|
|
658
659
|
|
|
660
|
+
test("Endpoints.toJsonLd() omits type", async () => {
|
|
661
|
+
const ep = new Endpoints({
|
|
662
|
+
sharedInbox: new URL("https://example.com/inbox"),
|
|
663
|
+
});
|
|
664
|
+
|
|
665
|
+
// Compact heuristic path (format == null)
|
|
666
|
+
const compact = await ep.toJsonLd() as Record<string, unknown>;
|
|
667
|
+
ok(!("type" in compact), "compact heuristic output should not have 'type'");
|
|
668
|
+
deepStrictEqual(compact["sharedInbox"], "https://example.com/inbox");
|
|
669
|
+
deepStrictEqual(compact["@context"], "https://www.w3.org/ns/activitystreams");
|
|
670
|
+
|
|
671
|
+
// Expanded format
|
|
672
|
+
const expanded = await ep.toJsonLd({
|
|
673
|
+
format: "expand",
|
|
674
|
+
contextLoader: mockDocumentLoader,
|
|
675
|
+
}) as Record<string, unknown>[];
|
|
676
|
+
ok(
|
|
677
|
+
!("@type" in expanded[0]),
|
|
678
|
+
"expanded output should not have '@type'",
|
|
679
|
+
);
|
|
680
|
+
|
|
681
|
+
// Compact via JSON-LD library
|
|
682
|
+
const compactLib = await ep.toJsonLd({
|
|
683
|
+
format: "compact",
|
|
684
|
+
contextLoader: mockDocumentLoader,
|
|
685
|
+
}) as Record<string, unknown>;
|
|
686
|
+
ok(
|
|
687
|
+
!("type" in compactLib),
|
|
688
|
+
"compact (library) output should not have 'type'",
|
|
689
|
+
);
|
|
690
|
+
|
|
691
|
+
// Round-trip: compact heuristic → fromJsonLd → compare
|
|
692
|
+
const restored = await Endpoints.fromJsonLd(compact, {
|
|
693
|
+
documentLoader: mockDocumentLoader,
|
|
694
|
+
contextLoader: mockDocumentLoader,
|
|
695
|
+
});
|
|
696
|
+
deepStrictEqual(restored, ep);
|
|
697
|
+
});
|
|
698
|
+
|
|
699
|
+
test("Source.toJsonLd() omits type", async () => {
|
|
700
|
+
const src = new Source({
|
|
701
|
+
content: "Hello, world!",
|
|
702
|
+
mediaType: "text/plain",
|
|
703
|
+
});
|
|
704
|
+
|
|
705
|
+
// Compact heuristic path (format == null)
|
|
706
|
+
const compact = await src.toJsonLd() as Record<string, unknown>;
|
|
707
|
+
ok(!("type" in compact), "compact heuristic output should not have 'type'");
|
|
708
|
+
deepStrictEqual(compact["mediaType"], "text/plain");
|
|
709
|
+
|
|
710
|
+
// Expanded format
|
|
711
|
+
const expanded = await src.toJsonLd({
|
|
712
|
+
format: "expand",
|
|
713
|
+
contextLoader: mockDocumentLoader,
|
|
714
|
+
}) as Record<string, unknown>[];
|
|
715
|
+
ok(
|
|
716
|
+
!("@type" in expanded[0]),
|
|
717
|
+
"expanded output should not have '@type'",
|
|
718
|
+
);
|
|
719
|
+
|
|
720
|
+
// Round-trip: compact heuristic → fromJsonLd → compare
|
|
721
|
+
const restored = await Source.fromJsonLd(compact, {
|
|
722
|
+
documentLoader: mockDocumentLoader,
|
|
723
|
+
contextLoader: mockDocumentLoader,
|
|
724
|
+
});
|
|
725
|
+
deepStrictEqual(restored, src);
|
|
726
|
+
});
|
|
727
|
+
|
|
728
|
+
test("Endpoints.fromJsonLd() accepts input with @type (backward compat)", async () => {
|
|
729
|
+
// Older Fedify instances may still send @type for Endpoints
|
|
730
|
+
const ep = await Endpoints.fromJsonLd({
|
|
731
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
732
|
+
"type": "as:Endpoints",
|
|
733
|
+
"sharedInbox": "https://example.com/inbox",
|
|
734
|
+
}, {
|
|
735
|
+
documentLoader: mockDocumentLoader,
|
|
736
|
+
contextLoader: mockDocumentLoader,
|
|
737
|
+
});
|
|
738
|
+
assertInstanceOf(ep, Endpoints);
|
|
739
|
+
deepStrictEqual(ep.sharedInbox?.href, "https://example.com/inbox");
|
|
740
|
+
});
|
|
741
|
+
|
|
742
|
+
test("Source.fromJsonLd() accepts input with @type (backward compat)", async () => {
|
|
743
|
+
const src = await Source.fromJsonLd({
|
|
744
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
745
|
+
"type": "as:Source",
|
|
746
|
+
"content": "Hello",
|
|
747
|
+
"mediaType": "text/plain",
|
|
748
|
+
}, {
|
|
749
|
+
documentLoader: mockDocumentLoader,
|
|
750
|
+
contextLoader: mockDocumentLoader,
|
|
751
|
+
});
|
|
752
|
+
assertInstanceOf(src, Source);
|
|
753
|
+
deepStrictEqual(src.content, "Hello");
|
|
754
|
+
deepStrictEqual(src.mediaType, "text/plain");
|
|
755
|
+
});
|
|
756
|
+
|
|
757
|
+
test("Endpoints with all properties set omits type", async () => {
|
|
758
|
+
const ep = new Endpoints({
|
|
759
|
+
proxyUrl: new URL("https://example.com/proxy"),
|
|
760
|
+
oauthAuthorizationEndpoint: new URL("https://example.com/oauth/authorize"),
|
|
761
|
+
oauthTokenEndpoint: new URL("https://example.com/oauth/token"),
|
|
762
|
+
provideClientKey: new URL("https://example.com/provide-key"),
|
|
763
|
+
signClientKey: new URL("https://example.com/sign-key"),
|
|
764
|
+
sharedInbox: new URL("https://example.com/inbox"),
|
|
765
|
+
});
|
|
766
|
+
|
|
767
|
+
// Compact heuristic path
|
|
768
|
+
const compact = await ep.toJsonLd() as Record<string, unknown>;
|
|
769
|
+
ok(!("type" in compact), "compact output should not have 'type'");
|
|
770
|
+
deepStrictEqual(compact["proxyUrl"], "https://example.com/proxy");
|
|
771
|
+
deepStrictEqual(
|
|
772
|
+
compact["oauthAuthorizationEndpoint"],
|
|
773
|
+
"https://example.com/oauth/authorize",
|
|
774
|
+
);
|
|
775
|
+
deepStrictEqual(
|
|
776
|
+
compact["oauthTokenEndpoint"],
|
|
777
|
+
"https://example.com/oauth/token",
|
|
778
|
+
);
|
|
779
|
+
deepStrictEqual(
|
|
780
|
+
compact["provideClientKey"],
|
|
781
|
+
"https://example.com/provide-key",
|
|
782
|
+
);
|
|
783
|
+
deepStrictEqual(compact["signClientKey"], "https://example.com/sign-key");
|
|
784
|
+
deepStrictEqual(compact["sharedInbox"], "https://example.com/inbox");
|
|
785
|
+
|
|
786
|
+
// Round-trip all three formats
|
|
787
|
+
for (
|
|
788
|
+
const format of [undefined, "compact" as const, "expand" as const]
|
|
789
|
+
) {
|
|
790
|
+
const jsonLd = await ep.toJsonLd({
|
|
791
|
+
format,
|
|
792
|
+
contextLoader: mockDocumentLoader,
|
|
793
|
+
});
|
|
794
|
+
const restored = await Endpoints.fromJsonLd(jsonLd, {
|
|
795
|
+
documentLoader: mockDocumentLoader,
|
|
796
|
+
contextLoader: mockDocumentLoader,
|
|
797
|
+
});
|
|
798
|
+
deepStrictEqual(
|
|
799
|
+
restored,
|
|
800
|
+
ep,
|
|
801
|
+
`round-trip failed for format=${format ?? "heuristic"}`,
|
|
802
|
+
);
|
|
803
|
+
}
|
|
804
|
+
});
|
|
805
|
+
|
|
806
|
+
test("Empty Endpoints omits type", async () => {
|
|
807
|
+
const ep = new Endpoints({});
|
|
808
|
+
|
|
809
|
+
const compact = await ep.toJsonLd() as Record<string, unknown>;
|
|
810
|
+
ok(!("type" in compact), "empty compact output should not have 'type'");
|
|
811
|
+
|
|
812
|
+
const expanded = await ep.toJsonLd({
|
|
813
|
+
format: "expand",
|
|
814
|
+
contextLoader: mockDocumentLoader,
|
|
815
|
+
}) as Record<string, unknown>[];
|
|
816
|
+
ok(
|
|
817
|
+
!("@type" in (expanded[0] ?? {})),
|
|
818
|
+
"empty expanded output should not have '@type'",
|
|
819
|
+
);
|
|
820
|
+
});
|
|
821
|
+
|
|
822
|
+
test("Empty Source omits type", async () => {
|
|
823
|
+
const src = new Source({});
|
|
824
|
+
|
|
825
|
+
const compact = await src.toJsonLd() as Record<string, unknown>;
|
|
826
|
+
ok(!("type" in compact), "empty compact output should not have 'type'");
|
|
827
|
+
|
|
828
|
+
const expanded = await src.toJsonLd({
|
|
829
|
+
format: "expand",
|
|
830
|
+
contextLoader: mockDocumentLoader,
|
|
831
|
+
}) as Record<string, unknown>[];
|
|
832
|
+
ok(
|
|
833
|
+
!("@type" in (expanded[0] ?? {})),
|
|
834
|
+
"empty expanded output should not have '@type'",
|
|
835
|
+
);
|
|
836
|
+
});
|
|
837
|
+
|
|
838
|
+
test("Person.toJsonLd() embeds Endpoints without type", async () => {
|
|
839
|
+
const person = new Person({
|
|
840
|
+
id: new URL("https://example.com/person/1"),
|
|
841
|
+
endpoints: new Endpoints({
|
|
842
|
+
sharedInbox: new URL("https://example.com/inbox"),
|
|
843
|
+
}),
|
|
844
|
+
});
|
|
845
|
+
|
|
846
|
+
// Compact heuristic path (the real-world code path)
|
|
847
|
+
const compact = await person.toJsonLd() as Record<string, unknown>;
|
|
848
|
+
const endpoints = compact["endpoints"] as Record<string, unknown>;
|
|
849
|
+
ok(endpoints != null, "endpoints should be present");
|
|
850
|
+
ok(
|
|
851
|
+
!("type" in endpoints),
|
|
852
|
+
"embedded endpoints should not have 'type'",
|
|
853
|
+
);
|
|
854
|
+
deepStrictEqual(endpoints["sharedInbox"], "https://example.com/inbox");
|
|
855
|
+
|
|
856
|
+
// Round-trip
|
|
857
|
+
const restored = await Person.fromJsonLd(compact, {
|
|
858
|
+
documentLoader: mockDocumentLoader,
|
|
859
|
+
contextLoader: mockDocumentLoader,
|
|
860
|
+
});
|
|
861
|
+
deepStrictEqual(restored.id, person.id);
|
|
862
|
+
deepStrictEqual(
|
|
863
|
+
restored.endpoints?.sharedInbox,
|
|
864
|
+
person.endpoints?.sharedInbox,
|
|
865
|
+
);
|
|
866
|
+
|
|
867
|
+
// Expanded format
|
|
868
|
+
const expanded = await person.toJsonLd({
|
|
869
|
+
format: "expand",
|
|
870
|
+
contextLoader: mockDocumentLoader,
|
|
871
|
+
}) as Record<string, unknown>[];
|
|
872
|
+
const expandedEndpoints =
|
|
873
|
+
(expanded[0]["https://www.w3.org/ns/activitystreams#endpoints"] as Record<
|
|
874
|
+
string,
|
|
875
|
+
unknown
|
|
876
|
+
>[])?.[0];
|
|
877
|
+
ok(expandedEndpoints != null, "expanded endpoints should be present");
|
|
878
|
+
ok(
|
|
879
|
+
!("@type" in expandedEndpoints),
|
|
880
|
+
"expanded embedded endpoints should not have '@type'",
|
|
881
|
+
);
|
|
882
|
+
|
|
883
|
+
// Expanded round-trip
|
|
884
|
+
const restored2 = await Person.fromJsonLd(expanded, {
|
|
885
|
+
documentLoader: mockDocumentLoader,
|
|
886
|
+
contextLoader: mockDocumentLoader,
|
|
887
|
+
});
|
|
888
|
+
deepStrictEqual(
|
|
889
|
+
restored2.endpoints?.sharedInbox,
|
|
890
|
+
person.endpoints?.sharedInbox,
|
|
891
|
+
);
|
|
892
|
+
|
|
893
|
+
// Compact via JSON-LD library
|
|
894
|
+
const compactLib = await person.toJsonLd({
|
|
895
|
+
format: "compact",
|
|
896
|
+
contextLoader: mockDocumentLoader,
|
|
897
|
+
context: "https://www.w3.org/ns/activitystreams",
|
|
898
|
+
}) as Record<string, unknown>;
|
|
899
|
+
const endpointsLib = compactLib["endpoints"] as Record<string, unknown>;
|
|
900
|
+
ok(endpointsLib != null, "compact-lib endpoints should be present");
|
|
901
|
+
ok(
|
|
902
|
+
!("type" in endpointsLib),
|
|
903
|
+
"compact-lib endpoints should not have 'type'",
|
|
904
|
+
);
|
|
905
|
+
|
|
906
|
+
// Compact library round-trip
|
|
907
|
+
const restored3 = await Person.fromJsonLd(compactLib, {
|
|
908
|
+
documentLoader: mockDocumentLoader,
|
|
909
|
+
contextLoader: mockDocumentLoader,
|
|
910
|
+
});
|
|
911
|
+
deepStrictEqual(
|
|
912
|
+
restored3.endpoints?.sharedInbox,
|
|
913
|
+
person.endpoints?.sharedInbox,
|
|
914
|
+
);
|
|
915
|
+
});
|
|
916
|
+
|
|
917
|
+
test("Object.toJsonLd() embeds Source without type", async () => {
|
|
918
|
+
const obj = new Object({
|
|
919
|
+
id: new URL("https://example.com/object/1"),
|
|
920
|
+
source: new Source({
|
|
921
|
+
content: "Hello, world!",
|
|
922
|
+
mediaType: "text/plain",
|
|
923
|
+
}),
|
|
924
|
+
});
|
|
925
|
+
|
|
926
|
+
// Compact heuristic path
|
|
927
|
+
const compact = await obj.toJsonLd() as Record<string, unknown>;
|
|
928
|
+
const source = compact["source"] as Record<string, unknown>;
|
|
929
|
+
ok(source != null, "source should be present");
|
|
930
|
+
ok(!("type" in source), "embedded source should not have 'type'");
|
|
931
|
+
deepStrictEqual(source["mediaType"], "text/plain");
|
|
932
|
+
|
|
933
|
+
// Round-trip
|
|
934
|
+
const restored = await Object.fromJsonLd(compact, {
|
|
935
|
+
documentLoader: mockDocumentLoader,
|
|
936
|
+
contextLoader: mockDocumentLoader,
|
|
937
|
+
});
|
|
938
|
+
deepStrictEqual(restored.source?.content, "Hello, world!");
|
|
939
|
+
deepStrictEqual(restored.source?.mediaType, "text/plain");
|
|
940
|
+
});
|
|
941
|
+
|
|
942
|
+
test("Person.fromJsonLd() with Mastodon-style endpoints (no type)", async () => {
|
|
943
|
+
// Mastodon serializes endpoints without a type field
|
|
944
|
+
const person = await Person.fromJsonLd({
|
|
945
|
+
"@context": [
|
|
946
|
+
"https://www.w3.org/ns/activitystreams",
|
|
947
|
+
"https://w3id.org/security/v1",
|
|
948
|
+
],
|
|
949
|
+
"id": "https://mastodon.social/users/testuser",
|
|
950
|
+
"type": "Person",
|
|
951
|
+
"preferredUsername": "testuser",
|
|
952
|
+
"inbox": "https://mastodon.social/users/testuser/inbox",
|
|
953
|
+
"outbox": "https://mastodon.social/users/testuser/outbox",
|
|
954
|
+
"endpoints": {
|
|
955
|
+
"sharedInbox": "https://mastodon.social/inbox",
|
|
956
|
+
},
|
|
957
|
+
}, {
|
|
958
|
+
documentLoader: mockDocumentLoader,
|
|
959
|
+
contextLoader: mockDocumentLoader,
|
|
960
|
+
});
|
|
961
|
+
assertInstanceOf(person, Person);
|
|
962
|
+
deepStrictEqual(
|
|
963
|
+
person.endpoints?.sharedInbox?.href,
|
|
964
|
+
"https://mastodon.social/inbox",
|
|
965
|
+
);
|
|
966
|
+
});
|
|
967
|
+
|
|
968
|
+
test("Person.fromJsonLd() with old Fedify-style endpoints (with type)", async () => {
|
|
969
|
+
// Older Fedify versions serialized endpoints with type: "as:Endpoints"
|
|
970
|
+
const person = await Person.fromJsonLd({
|
|
971
|
+
"@context": [
|
|
972
|
+
"https://www.w3.org/ns/activitystreams",
|
|
973
|
+
"https://w3id.org/security/v1",
|
|
974
|
+
],
|
|
975
|
+
"id": "https://example.com/users/testuser",
|
|
976
|
+
"type": "Person",
|
|
977
|
+
"endpoints": {
|
|
978
|
+
"type": "as:Endpoints",
|
|
979
|
+
"sharedInbox": "https://example.com/inbox",
|
|
980
|
+
},
|
|
981
|
+
}, {
|
|
982
|
+
documentLoader: mockDocumentLoader,
|
|
983
|
+
contextLoader: mockDocumentLoader,
|
|
984
|
+
});
|
|
985
|
+
assertInstanceOf(person, Person);
|
|
986
|
+
deepStrictEqual(
|
|
987
|
+
person.endpoints?.sharedInbox?.href,
|
|
988
|
+
"https://example.com/inbox",
|
|
989
|
+
);
|
|
990
|
+
});
|
|
991
|
+
|
|
992
|
+
test("Source with LanguageString content omits type", async () => {
|
|
993
|
+
const src = new Source({
|
|
994
|
+
contents: [
|
|
995
|
+
new LanguageString("Hello", "en"),
|
|
996
|
+
new LanguageString("Bonjour", "fr"),
|
|
997
|
+
],
|
|
998
|
+
mediaType: "text/plain",
|
|
999
|
+
});
|
|
1000
|
+
|
|
1001
|
+
const compact = await src.toJsonLd() as Record<string, unknown>;
|
|
1002
|
+
ok(!("type" in compact), "source with LanguageString should not have 'type'");
|
|
1003
|
+
|
|
1004
|
+
// Round-trip
|
|
1005
|
+
const restored = await Source.fromJsonLd(compact, {
|
|
1006
|
+
documentLoader: mockDocumentLoader,
|
|
1007
|
+
contextLoader: mockDocumentLoader,
|
|
1008
|
+
});
|
|
1009
|
+
deepStrictEqual(restored, src);
|
|
1010
|
+
});
|
|
1011
|
+
|
|
1012
|
+
test("Cross-format round-trip for Endpoints", async () => {
|
|
1013
|
+
const ep = new Endpoints({
|
|
1014
|
+
sharedInbox: new URL("https://example.com/inbox"),
|
|
1015
|
+
proxyUrl: new URL("https://example.com/proxy"),
|
|
1016
|
+
});
|
|
1017
|
+
|
|
1018
|
+
// compact heuristic → expanded → compact heuristic
|
|
1019
|
+
const compact1 = await ep.toJsonLd();
|
|
1020
|
+
const restored1 = await Endpoints.fromJsonLd(compact1, {
|
|
1021
|
+
documentLoader: mockDocumentLoader,
|
|
1022
|
+
contextLoader: mockDocumentLoader,
|
|
1023
|
+
});
|
|
1024
|
+
const expanded = await restored1.toJsonLd({
|
|
1025
|
+
format: "expand",
|
|
1026
|
+
contextLoader: mockDocumentLoader,
|
|
1027
|
+
});
|
|
1028
|
+
const restored2 = await Endpoints.fromJsonLd(expanded, {
|
|
1029
|
+
documentLoader: mockDocumentLoader,
|
|
1030
|
+
contextLoader: mockDocumentLoader,
|
|
1031
|
+
});
|
|
1032
|
+
const compact2 = await restored2.toJsonLd({
|
|
1033
|
+
contextLoader: mockDocumentLoader,
|
|
1034
|
+
});
|
|
1035
|
+
const restored3 = await Endpoints.fromJsonLd(compact2, {
|
|
1036
|
+
documentLoader: mockDocumentLoader,
|
|
1037
|
+
contextLoader: mockDocumentLoader,
|
|
1038
|
+
});
|
|
1039
|
+
deepStrictEqual(restored3, ep);
|
|
1040
|
+
});
|
|
1041
|
+
|
|
659
1042
|
test("Collection.fromJsonLd()", async () => {
|
|
660
1043
|
const collection = await Collection.fromJsonLd({
|
|
661
1044
|
"@context": [
|
|
@@ -1860,18 +2243,29 @@ for (const typeUri in types) {
|
|
|
1860
2243
|
"@type": typeUri,
|
|
1861
2244
|
},
|
|
1862
2245
|
);
|
|
1863
|
-
|
|
1864
|
-
await instance.toJsonLd({
|
|
2246
|
+
if (type.typeless) {
|
|
2247
|
+
const compactJsonLd = await instance.toJsonLd({
|
|
1865
2248
|
format: "compact",
|
|
1866
2249
|
contextLoader: mockDocumentLoader,
|
|
1867
|
-
}),
|
|
1868
|
-
|
|
1869
|
-
"
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
2250
|
+
}) as Record<string, unknown>;
|
|
2251
|
+
ok(
|
|
2252
|
+
!("type" in compactJsonLd),
|
|
2253
|
+
`${type.name} is typeless; compact output should not have 'type'`,
|
|
2254
|
+
);
|
|
2255
|
+
} else {
|
|
2256
|
+
deepStrictEqual(
|
|
2257
|
+
await instance.toJsonLd({
|
|
2258
|
+
format: "compact",
|
|
2259
|
+
contextLoader: mockDocumentLoader,
|
|
2260
|
+
}),
|
|
2261
|
+
{
|
|
2262
|
+
"@context": type.defaultContext,
|
|
2263
|
+
"id": "https://example.com/",
|
|
2264
|
+
"type": type.compactName ??
|
|
2265
|
+
(type.name === "DataIntegrityProof" ? type.name : type.uri),
|
|
2266
|
+
},
|
|
2267
|
+
);
|
|
2268
|
+
}
|
|
1875
2269
|
|
|
1876
2270
|
if (type.extends != null) {
|
|
1877
2271
|
await rejects(() =>
|