@fedify/vocab 2.1.0-dev.405 → 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.
@@ -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-BoHbeM38.js";
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
- deepStrictEqual(await instance.toJsonLd({
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.405+f4e278ae",
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/vocab-tools": "2.1.0-dev.405+f4e278ae",
51
- "@fedify/webfinger": "2.1.0-dev.405+f4e278ae",
52
- "@fedify/vocab-runtime": "2.1.0-dev.405+f4e278ae"
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",
@@ -3,6 +3,7 @@ name: Endpoints
3
3
  compactName: as:Endpoints
4
4
  uri: "https://www.w3.org/ns/activitystreams#Endpoints"
5
5
  entity: false
6
+ typeless: true
6
7
  description: Contents of {@link Actor}'s `endpoints`.
7
8
  defaultContext: "https://www.w3.org/ns/activitystreams"
8
9
 
package/src/source.yaml CHANGED
@@ -3,6 +3,7 @@ name: Source
3
3
  compactName: as:Source
4
4
  uri: "https://www.w3.org/ns/activitystreams#Source"
5
5
  entity: false
6
+ typeless: true
6
7
  description: Contents of {@link Object}'s `source`.
7
8
  defaultContext: "https://www.w3.org/ns/activitystreams"
8
9