From 4dae9df16f8bd0633c7ed95671ff439299b16525 Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Mon, 19 Oct 2026 21:14:00 +0900 Subject: [PATCH 1/2] Honor private addresses in testing federations Mock inbox delivery did not attach federation loaders, so lazy actor lookups rejected localhost even when tests opted in. Configure HTTP loaders for received activities and federation-created contexts when allowPrivateAddress is true, using a working tracer for context-based lookups. Preserve offline mock behavior when false or omitted. Clone received activities without losing their original JSON-LD or unknown extensions, and keep embedded object identity and trust intact. Add regression coverage and document the opt-in behavior. Fixes https://github.com/fedify-dev/fedify/issues/1302 Assisted-by: Codex:gpt-6.1-sol Assisted-by: Codex:gpt-6-astra Assisted-by: Claude Code:claude-opus-5-5 Assisted-by: Claude Code:claude-fable-5-1 --- CHANGES.md | 6 + changes.d/testing/allow-private-address.md | 9 + docs/manual/test.md | 34 +++ packages/testing/package.json | 3 +- packages/testing/src/mock.test.ts | 260 ++++++++++++++++++++- packages/testing/src/mock.ts | 43 +++- pnpm-lock.yaml | 9 +- 7 files changed, 356 insertions(+), 8 deletions(-) create mode 100644 changes.d/testing/allow-private-address.md diff --git a/CHANGES.md b/CHANGES.md index d180feb33..51abfe65f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,12 +10,18 @@ To be released. ### @fedify/testing + - Fixed `createFederation()` ignoring `allowPrivateAddress: true`. Received + activities and federation-created contexts now use document loaders that + allow local servers, so calls such as `follow.getActor()` can resolve + localhost actors in inbox listeners. [[#1302], [#1306]] - Fixed missing runtime dependencies in the npm package. `@fedify/vocab` and `@js-temporal/polyfill` are now installed automatically so importing `@fedify/testing` works even when dependency hoisting is disabled on Node.js and Bun. [[#1305], [#1307]] +[#1302]: https://github.com/fedify-dev/fedify/issues/1302 [#1305]: https://github.com/fedify-dev/fedify/issues/1305 +[#1306]: https://github.com/fedify-dev/fedify/pull/1306 [#1307]: https://github.com/fedify-dev/fedify/pull/1307 diff --git a/changes.d/testing/allow-private-address.md b/changes.d/testing/allow-private-address.md new file mode 100644 index 000000000..00d4a942f --- /dev/null +++ b/changes.d/testing/allow-private-address.md @@ -0,0 +1,9 @@ +--- +links: + '#1302': https://github.com/fedify-dev/fedify/issues/1302 + '#1306': https://github.com/fedify-dev/fedify/pull/1306 +--- + - Fixed `createFederation()` ignoring `allowPrivateAddress: true`. Received + activities and federation-created contexts now use document loaders that + allow local servers, so calls such as `follow.getActor()` can resolve + localhost actors in inbox listeners. [[#1302], [#1306]] diff --git a/docs/manual/test.md b/docs/manual/test.md index 22d0ef06e..2e1d7a1da 100644 --- a/docs/manual/test.md +++ b/docs/manual/test.md @@ -240,6 +240,40 @@ await federation.receiveActivity(activity); console.log("Sent activities:", federation.sentActivities); ~~~~ +To load actors or other referenced objects from a local HTTP server, pass +`allowPrivateAddress: true`. This enables HTTP document loading for received +activities and contexts created by the mock federation, including addresses +such as `localhost`: + +~~~~ typescript twoslash +import { createFederation } from "@fedify/testing"; +import { Follow, Undo } from "@fedify/vocab"; + +const federation = createFederation({ + contextData: {}, + allowPrivateAddress: true +}); + +federation + .setInboxListeners("/users/{identifier}/inbox") + .on(Follow, async (ctx, follow) => { + const actor = await follow.getActor(); + }) + .on(Undo, async (ctx, undo) => { + const object = await undo.getObject(); + if (object instanceof Follow) { + const actor = await object.getActor(ctx); + } + }); +~~~~ + +*The `allowPrivateAddress` option is available since Fedify 2.0.35.* + +Received activities are cloned with the configured loaders. Embedded objects +remain shared, so pass the listener context to their getters, as in +`object.getActor(ctx)` above. If the option is `false` or omitted, contexts +keep their no-op mock loaders and received activities keep their own loaders. + ### Creating mock contexts You can create mock contexts using the `createContext()` method, diff --git a/packages/testing/package.json b/packages/testing/package.json index 7410a778c..4bd9ae195 100644 --- a/packages/testing/package.json +++ b/packages/testing/package.json @@ -54,12 +54,13 @@ }, "dependencies": { "@fedify/vocab": "workspace:^", + "@fedify/vocab-runtime": "workspace:^", "@js-temporal/polyfill": "catalog:", + "@opentelemetry/api": "catalog:", "es-toolkit": "catalog:" }, "devDependencies": { "@fedify/fixture": "workspace:^", - "@fedify/vocab-runtime": "workspace:^", "@std/assert": "catalog:", "@std/async": "catalog:", "tsdown": "catalog:", diff --git a/packages/testing/src/mock.test.ts b/packages/testing/src/mock.test.ts index 5914f5584..20a3aa3eb 100644 --- a/packages/testing/src/mock.test.ts +++ b/packages/testing/src/mock.test.ts @@ -1,7 +1,14 @@ import type { InboxContext } from "@fedify/fedify/federation"; import { test } from "@fedify/fixture"; -import { Create, Note, Person } from "@fedify/vocab"; -import { assertEquals, assertRejects, assertStrictEquals } from "@std/assert"; +import { Create, Follow, Note, Person, Undo } from "@fedify/vocab"; +import { getDocumentLoader, UrlError } from "@fedify/vocab-runtime"; +import { + assertEquals, + assertInstanceOf, + assertNotStrictEquals, + assertRejects, + assertStrictEquals, +} from "@std/assert"; import { createFederation } from "./mock.ts"; test("MockFederation actor setters support chaining in any order", () => { @@ -599,3 +606,252 @@ test("MockContext.getActorKeyPairs() returns empty array when no dispatcher regi const keyPairs = await context.getActorKeyPairs("alice"); assertEquals(keyPairs, []); }); + +const localActorUrl = "http://localhost:9999/users/alicia"; + +function createNetworkFederation() { + const options = { contextData: {}, allowPrivateAddress: true }; + return createFederation(options); +} + +function createLocalFollow(): Follow { + return new Follow({ + id: new URL("http://localhost:9999/activities/follow"), + actor: new URL(localActorUrl), + object: new URL("https://example.com/users/alice"), + }); +} + +async function withActorFetch(fn: () => Promise): Promise { + const originalFetch = globalThis.fetch; + const requests: string[] = []; + globalThis.fetch = (input) => { + const url = input instanceof Request ? input.url : String(input); + requests.push(url); + return Promise.resolve( + new Response( + JSON.stringify({ + "@context": "https://www.w3.org/ns/activitystreams", + id: url, + type: "Person", + preferredUsername: "alicia", + }), + { headers: { "Content-Type": "application/activity+json" } }, + ), + ); + }; + try { + await fn(); + } finally { + globalThis.fetch = originalFetch; + } + return requests; +} + +for (const passContext of [false, true]) { + test(`receiveActivity allows private actor lookup (pass context: ${passContext})`, async () => { + const federation = createNetworkFederation(); + const activity = createLocalFollow(); + const received: Follow[] = []; + let actor: unknown; + federation.setInboxListeners("/users/{identifier}/inbox").on( + Follow, + async (ctx: InboxContext>, follow: Follow) => { + received.push(follow); + actor = await follow.getActor(passContext ? ctx : {}); + }, + ).on( + Follow, + (_ctx: InboxContext>, follow: Follow) => { + received.push(follow); + return Promise.resolve(); + }, + ); + const requests = await withActorFetch(() => + federation.receiveActivity(activity) + ); + assertEquals(requests, [localActorUrl]); + assertInstanceOf(actor, Person); + assertEquals(actor.id?.href, localActorUrl); + assertInstanceOf(received[0], Follow); + assertNotStrictEquals(received[0], activity); + assertStrictEquals(received[0], received[1]); + assertEquals(activity.actorId?.href, localActorUrl); + // The listener's lazy lookup must not populate the caller's actor cache. + await assertRejects(() => activity.getActor(), UrlError, "Localhost"); + }); +} + +for (const allowPrivateAddress of [undefined, false]) { + test(`receiveActivity retains offline defaults (allowPrivateAddress: ${allowPrivateAddress})`, async () => { + const options = { contextData: {}, allowPrivateAddress }; + const federation = createFederation(options); + const activity = createLocalFollow(); + let received: Follow | undefined; + let document: unknown; + let contextDocument: unknown; + federation.setInboxListeners("/users/{identifier}/inbox").on( + Follow, + async (ctx: InboxContext>, follow: Follow) => { + received = follow; + document = (await ctx.documentLoader(localActorUrl)).document; + contextDocument = (await ctx.contextLoader(localActorUrl)).document; + await assertRejects(() => follow.getActor(), UrlError, "Localhost"); + }, + ); + const requests = await withActorFetch(async () => { + await federation.receiveActivity(activity); + const ctx = federation.createContext(new URL("https://example.com"), {}); + await ctx.documentLoader(localActorUrl); + await ctx.contextLoader(localActorUrl); + }); + assertEquals(requests, []); + assertStrictEquals(received, activity); + assertEquals(document, {}); + assertEquals(contextDocument, {}); + }); +} + +test("createContext allows private actor lookup", async () => { + const federation = createNetworkFederation(); + const ctx = federation.createContext(new URL("https://example.com"), {}); + const activity = createLocalFollow(); + let actor: unknown; + const requests = await withActorFetch(async () => { + actor = await activity.getActor(ctx); + }); + assertEquals(requests, [localActorUrl]); + assertInstanceOf(actor, Person); + assertEquals(actor.id?.href, localActorUrl); +}); + +test("receiveActivity preserves embedded objects and supports lookup with context", async () => { + const federation = createNetworkFederation(); + const follow = createLocalFollow(); + // A different origin must not cause a trusted embedded object to be fetched. + const activity = new Undo({ + id: new URL("https://example.com/activities/undo"), + object: follow, + }); + let embedded: unknown; + let actor: unknown; + federation.setInboxListeners("/users/{identifier}/inbox").on( + Undo, + async (ctx: InboxContext>, undo: Undo) => { + const object = await undo.getObject(); + embedded = object; + if (object instanceof Follow) actor = await object.getActor(ctx); + }, + ); + const requests = await withActorFetch(() => + federation.receiveActivity(activity) + ); + assertEquals(requests, [localActorUrl]); + assertStrictEquals(embedded, follow); + assertInstanceOf(actor, Person); + assertEquals(actor.id?.href, localActorUrl); +}); + +test("receiveActivity respects an explicit getter document loader", async () => { + const federation = createNetworkFederation(); + let actor: unknown; + const loaderRequests: string[] = []; + federation.setInboxListeners("/users/{identifier}/inbox").on( + Follow, + async (_ctx: InboxContext>, follow: Follow) => { + actor = await follow.getActor({ + documentLoader: (url) => { + loaderRequests.push(url); + return Promise.resolve({ + contextUrl: null, + documentUrl: url, + document: { + "@context": "https://www.w3.org/ns/activitystreams", + id: url, + type: "Person", + }, + }); + }, + }); + }, + ); + const requests = await withActorFetch(() => + federation.receiveActivity(createLocalFollow()) + ); + assertEquals(requests, []); + assertEquals(loaderRequests, [localActorUrl]); + assertInstanceOf(actor, Person); + assertEquals(actor.id?.href, localActorUrl); +}); + +test("receiveActivity preserves an unconfigured activity's own loaders", async () => { + const federation = createFederation({ contextData: {} }); + const loader = getDocumentLoader({ allowPrivateAddress: true }); + const activity = createLocalFollow().clone({}, { + documentLoader: loader, + contextLoader: loader, + }); + let actor: unknown; + federation.setInboxListeners("/users/{identifier}/inbox").on( + Follow, + async (_ctx: InboxContext>, follow: Follow) => { + actor = await follow.getActor(); + }, + ); + const requests = await withActorFetch(() => + federation.receiveActivity(activity) + ); + assertEquals(requests, [localActorUrl]); + assertInstanceOf(actor, Person); +}); + +test("receiveActivity does not clone without listeners or context data", async () => { + const options = { contextData: undefined, allowPrivateAddress: true }; + const federation = createFederation(options); + const activity = createLocalFollow(); + let clones = 0; + activity.clone = () => { + clones++; + return activity; + }; + const requests = await withActorFetch(async () => { + await federation.receiveActivity(activity); + federation.setInboxListeners("/users/{identifier}/inbox").on( + Follow, + () => Promise.resolve(), + ); + await assertRejects( + () => federation.receiveActivity(activity), + Error, + "contextData", + ); + }); + assertEquals(requests, []); + assertEquals(clones, 0); +}); + +test("receiveActivity preserves parsed JSON-LD extension properties", async () => { + const federation = createNetworkFederation(); + const json = { + "@context": "https://www.w3.org/ns/activitystreams", + id: "http://localhost:9999/activities/follow", + type: "Follow", + actor: localActorUrl, + object: "https://example.com/users/alice", + "https://example.com/ns#custom": "preserved", + }; + const activity = await Follow.fromJsonLd(json); + let receivedJson: unknown; + federation.setInboxListeners("/users/{identifier}/inbox").on( + Follow, + async (_ctx: InboxContext>, follow: Follow) => { + receivedJson = await follow.toJsonLd(); + }, + ); + const requests = await withActorFetch(() => + federation.receiveActivity(activity) + ); + assertEquals(requests, []); + assertEquals(receivedJson, json); + assertEquals(await activity.toJsonLd(), json); +}); diff --git a/packages/testing/src/mock.ts b/packages/testing/src/mock.ts index f18d8d968..5d4b73bed 100644 --- a/packages/testing/src/mock.ts +++ b/packages/testing/src/mock.ts @@ -18,7 +18,8 @@ import type { Object, TraverseCollectionOptions, } from "@fedify/vocab"; -import type { DocumentLoader } from "@fedify/vocab-runtime"; +import { type DocumentLoader, getDocumentLoader } from "@fedify/vocab-runtime"; +import { trace } from "@opentelemetry/api"; import { createContext, createInboxContext, @@ -203,15 +204,20 @@ class MockFederation implements Federation { private inboxListeners: Map = new Map(); private contextData?: TContextData; private receivedActivities: Activity[] = []; + private readonly documentLoader?: DocumentLoader; constructor( private options: { contextData?: TContextData; origin?: string; + allowPrivateAddress?: boolean; tracerProvider?: any; } = {}, ) { this.contextData = options.contextData; + if (options.allowPrivateAddress === true) { + this.documentLoader = getDocumentLoader({ allowPrivateAddress: true }); + } } setNodeInfoDispatcher(path: string, dispatcher: any): void { @@ -408,6 +414,11 @@ class MockFederation implements Federation { url, data: contextData, federation: mockFederation as any, + documentLoader: this.documentLoader, + contextLoader: this.documentLoader, + tracerProvider: this.documentLoader == null + ? undefined + : this.options.tracerProvider ?? trace.getTracerProvider(), }); } @@ -446,12 +457,32 @@ class MockFederation implements Federation { ); } + const receivedActivity = listeners.length > 0 && this.documentLoader != null + ? activity.clone({}, { + documentLoader: this.documentLoader, + contextLoader: this.documentLoader, + }) + : activity; + if (receivedActivity !== activity) { + // clone() drops the parsed JSON-LD cache. Preserve it so listeners can + // serialize the received document without losing unknown extensions. + Reflect.set( + receivedActivity, + "_cachedJsonLd", + Reflect.get(activity, "_cachedJsonLd"), + ); + } for (const listener of listeners) { const context = createInboxContext({ data: this.contextData as TContextData, federation: this as any, + documentLoader: this.documentLoader, + contextLoader: this.documentLoader, + tracerProvider: this.documentLoader == null + ? undefined + : this.options.tracerProvider ?? trace.getTracerProvider(), }); - await listener(context, activity); + await listener(context, receivedActivity); } } @@ -545,6 +576,14 @@ export function createFederation( options: { contextData?: TContextData; origin?: string; + /** + * Use HTTP document loading for received activities and contexts created by + * this federation, allowing private addresses such as localhost. + * If false or omitted, contexts retain their no-op mock loaders and + * received activities retain their own loaders. + * @since 2.0.35 + */ + allowPrivateAddress?: boolean; tracerProvider?: any; } = {}, ): TestFederation { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c23b428d7..573724fb1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1468,9 +1468,15 @@ importers: '@fedify/vocab': specifier: workspace:^ version: link:../vocab + '@fedify/vocab-runtime': + specifier: workspace:^ + version: link:../vocab-runtime '@js-temporal/polyfill': specifier: 'catalog:' version: 0.5.1 + '@opentelemetry/api': + specifier: 'catalog:' + version: 1.9.0 es-toolkit: specifier: 'catalog:' version: 1.43.0 @@ -1478,9 +1484,6 @@ importers: '@fedify/fixture': specifier: workspace:^ version: link:../fixture - '@fedify/vocab-runtime': - specifier: workspace:^ - version: link:../vocab-runtime '@std/assert': specifier: 'catalog:' version: '@jsr/std__assert@1.0.13' From f1a3bae1a4700f80553d5b69bc48316e35a8883c Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Tue, 20 Oct 2026 00:21:39 +0900 Subject: [PATCH 2/2] Document the vocabulary cache bridge Keep the generated _cachedJsonLd accessor stable for the testing package's loader-attaching clones. Document this internal contract in the generator and at its call site instead of adding a public cache-transfer API to a maintenance bug fix. Refresh the Deno, Node.js and Bun code-generation snapshots. https://github.com/fedify-dev/fedify/pull/1306#discussion_r4314031333 Assisted-by: Codex:gpt-6.1-sol --- packages/testing/src/mock.ts | 5 ++- .../src/__snapshots__/class.test.ts.deno.snap | 45 +++++++++++++++++++ .../src/__snapshots__/class.test.ts.node.snap | 45 +++++++++++++++++++ .../src/__snapshots__/class.test.ts.snap | 45 +++++++++++++++++++ packages/vocab-tools/src/class.ts | 5 +++ 5 files changed, 143 insertions(+), 2 deletions(-) diff --git a/packages/testing/src/mock.ts b/packages/testing/src/mock.ts index 5d4b73bed..383b6f14a 100644 --- a/packages/testing/src/mock.ts +++ b/packages/testing/src/mock.ts @@ -464,8 +464,9 @@ class MockFederation implements Federation { }) : activity; if (receivedActivity !== activity) { - // clone() drops the parsed JSON-LD cache. Preserve it so listeners can - // serialize the received document without losing unknown extensions. + // _cachedJsonLd is an internal cross-package contract documented in + // @fedify/vocab-tools. clone() drops this cache, so preserve it to keep + // unknown extensions when listeners serialize the received document. Reflect.set( receivedActivity, "_cachedJsonLd", diff --git a/packages/vocab-tools/src/__snapshots__/class.test.ts.deno.snap b/packages/vocab-tools/src/__snapshots__/class.test.ts.deno.snap index daed8cde1..10dbde171 100644 --- a/packages/vocab-tools/src/__snapshots__/class.test.ts.deno.snap +++ b/packages/vocab-tools/src/__snapshots__/class.test.ts.deno.snap @@ -86,6 +86,11 @@ export class Object { return this.#warning; } + /** + * Internal cross-package contract with @fedify/testing, which copies this + * cache when attaching document loaders to an activity clone. Keep this + * accessor name and its getter/setter semantics stable. + */ protected get _cachedJsonLd(): unknown | undefined { return this.#cachedJsonLd; } @@ -16504,6 +16509,11 @@ export class PropertyValue { return this.#warning; } + /** + * Internal cross-package contract with @fedify/testing, which copies this + * cache when attaching document loaders to an activity clone. Keep this + * accessor name and its getter/setter semantics stable. + */ protected get _cachedJsonLd(): unknown | undefined { return this.#cachedJsonLd; } @@ -17149,6 +17159,11 @@ export class DidService { return this.#warning; } + /** + * Internal cross-package contract with @fedify/testing, which copies this + * cache when attaching document loaders to an activity clone. Keep this + * accessor name and its getter/setter semantics stable. + */ protected get _cachedJsonLd(): unknown | undefined { return this.#cachedJsonLd; } @@ -17980,6 +17995,11 @@ export class DataIntegrityProof { return this.#warning; } + /** + * Internal cross-package contract with @fedify/testing, which copies this + * cache when attaching document loaders to an activity clone. Keep this + * accessor name and its getter/setter semantics stable. + */ protected get _cachedJsonLd(): unknown | undefined { return this.#cachedJsonLd; } @@ -19067,6 +19087,11 @@ export class CryptographicKey { return this.#warning; } + /** + * Internal cross-package contract with @fedify/testing, which copies this + * cache when attaching document loaders to an activity clone. Keep this + * accessor name and its getter/setter semantics stable. + */ protected get _cachedJsonLd(): unknown | undefined { return this.#cachedJsonLd; } @@ -19983,6 +20008,11 @@ export class Multikey { return this.#warning; } + /** + * Internal cross-package contract with @fedify/testing, which copies this + * cache when attaching document loaders to an activity clone. Keep this + * accessor name and its getter/setter semantics stable. + */ protected get _cachedJsonLd(): unknown | undefined { return this.#cachedJsonLd; } @@ -38808,6 +38838,11 @@ export class Endpoints { return this.#warning; } + /** + * Internal cross-package contract with @fedify/testing, which copies this + * cache when attaching document loaders to an activity clone. Keep this + * accessor name and its getter/setter semantics stable. + */ protected get _cachedJsonLd(): unknown | undefined { return this.#cachedJsonLd; } @@ -47969,6 +48004,11 @@ export class Link { return this.#warning; } + /** + * Internal cross-package contract with @fedify/testing, which copies this + * cache when attaching document loaders to an activity clone. Keep this + * accessor name and its getter/setter semantics stable. + */ protected get _cachedJsonLd(): unknown | undefined { return this.#cachedJsonLd; } @@ -82276,6 +82316,11 @@ export class Source { return this.#warning; } + /** + * Internal cross-package contract with @fedify/testing, which copies this + * cache when attaching document loaders to an activity clone. Keep this + * accessor name and its getter/setter semantics stable. + */ protected get _cachedJsonLd(): unknown | undefined { return this.#cachedJsonLd; } diff --git a/packages/vocab-tools/src/__snapshots__/class.test.ts.node.snap b/packages/vocab-tools/src/__snapshots__/class.test.ts.node.snap index 9bf7bbff7..c08c0e0e9 100644 --- a/packages/vocab-tools/src/__snapshots__/class.test.ts.node.snap +++ b/packages/vocab-tools/src/__snapshots__/class.test.ts.node.snap @@ -84,6 +84,11 @@ export class Object { return this.#warning; } + /** + * Internal cross-package contract with @fedify/testing, which copies this + * cache when attaching document loaders to an activity clone. Keep this + * accessor name and its getter/setter semantics stable. + */ protected get _cachedJsonLd(): unknown | undefined { return this.#cachedJsonLd; } @@ -16502,6 +16507,11 @@ export class PropertyValue { return this.#warning; } + /** + * Internal cross-package contract with @fedify/testing, which copies this + * cache when attaching document loaders to an activity clone. Keep this + * accessor name and its getter/setter semantics stable. + */ protected get _cachedJsonLd(): unknown | undefined { return this.#cachedJsonLd; } @@ -17147,6 +17157,11 @@ export class DidService { return this.#warning; } + /** + * Internal cross-package contract with @fedify/testing, which copies this + * cache when attaching document loaders to an activity clone. Keep this + * accessor name and its getter/setter semantics stable. + */ protected get _cachedJsonLd(): unknown | undefined { return this.#cachedJsonLd; } @@ -17978,6 +17993,11 @@ export class DataIntegrityProof { return this.#warning; } + /** + * Internal cross-package contract with @fedify/testing, which copies this + * cache when attaching document loaders to an activity clone. Keep this + * accessor name and its getter/setter semantics stable. + */ protected get _cachedJsonLd(): unknown | undefined { return this.#cachedJsonLd; } @@ -19065,6 +19085,11 @@ export class CryptographicKey { return this.#warning; } + /** + * Internal cross-package contract with @fedify/testing, which copies this + * cache when attaching document loaders to an activity clone. Keep this + * accessor name and its getter/setter semantics stable. + */ protected get _cachedJsonLd(): unknown | undefined { return this.#cachedJsonLd; } @@ -19981,6 +20006,11 @@ export class Multikey { return this.#warning; } + /** + * Internal cross-package contract with @fedify/testing, which copies this + * cache when attaching document loaders to an activity clone. Keep this + * accessor name and its getter/setter semantics stable. + */ protected get _cachedJsonLd(): unknown | undefined { return this.#cachedJsonLd; } @@ -38806,6 +38836,11 @@ export class Endpoints { return this.#warning; } + /** + * Internal cross-package contract with @fedify/testing, which copies this + * cache when attaching document loaders to an activity clone. Keep this + * accessor name and its getter/setter semantics stable. + */ protected get _cachedJsonLd(): unknown | undefined { return this.#cachedJsonLd; } @@ -47967,6 +48002,11 @@ export class Link { return this.#warning; } + /** + * Internal cross-package contract with @fedify/testing, which copies this + * cache when attaching document loaders to an activity clone. Keep this + * accessor name and its getter/setter semantics stable. + */ protected get _cachedJsonLd(): unknown | undefined { return this.#cachedJsonLd; } @@ -82274,6 +82314,11 @@ export class Source { return this.#warning; } + /** + * Internal cross-package contract with @fedify/testing, which copies this + * cache when attaching document loaders to an activity clone. Keep this + * accessor name and its getter/setter semantics stable. + */ protected get _cachedJsonLd(): unknown | undefined { return this.#cachedJsonLd; } diff --git a/packages/vocab-tools/src/__snapshots__/class.test.ts.snap b/packages/vocab-tools/src/__snapshots__/class.test.ts.snap index ba7de4a93..8cd0661a6 100644 --- a/packages/vocab-tools/src/__snapshots__/class.test.ts.snap +++ b/packages/vocab-tools/src/__snapshots__/class.test.ts.snap @@ -86,6 +86,11 @@ export class Object { return this.#warning; } + /** + * Internal cross-package contract with @fedify/testing, which copies this + * cache when attaching document loaders to an activity clone. Keep this + * accessor name and its getter/setter semantics stable. + */ protected get _cachedJsonLd(): unknown | undefined { return this.#cachedJsonLd; } @@ -16504,6 +16509,11 @@ export class PropertyValue { return this.#warning; } + /** + * Internal cross-package contract with @fedify/testing, which copies this + * cache when attaching document loaders to an activity clone. Keep this + * accessor name and its getter/setter semantics stable. + */ protected get _cachedJsonLd(): unknown | undefined { return this.#cachedJsonLd; } @@ -17149,6 +17159,11 @@ export class DidService { return this.#warning; } + /** + * Internal cross-package contract with @fedify/testing, which copies this + * cache when attaching document loaders to an activity clone. Keep this + * accessor name and its getter/setter semantics stable. + */ protected get _cachedJsonLd(): unknown | undefined { return this.#cachedJsonLd; } @@ -17980,6 +17995,11 @@ export class DataIntegrityProof { return this.#warning; } + /** + * Internal cross-package contract with @fedify/testing, which copies this + * cache when attaching document loaders to an activity clone. Keep this + * accessor name and its getter/setter semantics stable. + */ protected get _cachedJsonLd(): unknown | undefined { return this.#cachedJsonLd; } @@ -19067,6 +19087,11 @@ export class CryptographicKey { return this.#warning; } + /** + * Internal cross-package contract with @fedify/testing, which copies this + * cache when attaching document loaders to an activity clone. Keep this + * accessor name and its getter/setter semantics stable. + */ protected get _cachedJsonLd(): unknown | undefined { return this.#cachedJsonLd; } @@ -19983,6 +20008,11 @@ export class Multikey { return this.#warning; } + /** + * Internal cross-package contract with @fedify/testing, which copies this + * cache when attaching document loaders to an activity clone. Keep this + * accessor name and its getter/setter semantics stable. + */ protected get _cachedJsonLd(): unknown | undefined { return this.#cachedJsonLd; } @@ -38808,6 +38838,11 @@ export class Endpoints { return this.#warning; } + /** + * Internal cross-package contract with @fedify/testing, which copies this + * cache when attaching document loaders to an activity clone. Keep this + * accessor name and its getter/setter semantics stable. + */ protected get _cachedJsonLd(): unknown | undefined { return this.#cachedJsonLd; } @@ -47969,6 +48004,11 @@ export class Link { return this.#warning; } + /** + * Internal cross-package contract with @fedify/testing, which copies this + * cache when attaching document loaders to an activity clone. Keep this + * accessor name and its getter/setter semantics stable. + */ protected get _cachedJsonLd(): unknown | undefined { return this.#cachedJsonLd; } @@ -82276,6 +82316,11 @@ export class Source { return this.#warning; } + /** + * Internal cross-package contract with @fedify/testing, which copies this + * cache when attaching document loaders to an activity clone. Keep this + * accessor name and its getter/setter semantics stable. + */ protected get _cachedJsonLd(): unknown | undefined { return this.#cachedJsonLd; } diff --git a/packages/vocab-tools/src/class.ts b/packages/vocab-tools/src/class.ts index 4acdcf001..7715087a4 100644 --- a/packages/vocab-tools/src/class.ts +++ b/packages/vocab-tools/src/class.ts @@ -80,6 +80,11 @@ async function* generateClass( return this.#warning; } + /** + * Internal cross-package contract with @fedify/testing, which copies this + * cache when attaching document loaders to an activity clone. Keep this + * accessor name and its getter/setter semantics stable. + */ protected get _cachedJsonLd(): unknown | undefined { return this.#cachedJsonLd; }