@fedify/testing 2.4.0-dev.2193 → 2.4.0-dev.2212

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/dist/mod.cjs CHANGED
@@ -143,11 +143,54 @@ function createRequestContext(args) {
143
143
  getObject: args.getObject ?? (() => Promise.resolve(null)),
144
144
  getSignedKey: args.getSignedKey ?? (() => Promise.resolve(null)),
145
145
  getSignedKeyOwner: args.getSignedKeyOwner ?? (() => Promise.resolve(null)),
146
+ isSignedByAudience: args.isSignedByAudience ?? ((object, options) => isSignedByAudience(() => args.getSignedKeyOwner == null ? Promise.resolve(null) : args.getSignedKeyOwner(options ?? {}), object, options?.isMember)),
146
147
  sendActivity: args.sendActivity ?? ((_params) => {
147
148
  throw new Error("Not implemented");
148
149
  })
149
150
  };
150
151
  }
152
+ const PUBLIC_IDS = /* @__PURE__ */ new Set([
153
+ _fedify_vocab.PUBLIC_COLLECTION.href,
154
+ "as:Public",
155
+ "Public"
156
+ ]);
157
+ function getPortableIri(id) {
158
+ try {
159
+ if (id.protocol === "ap:" || id.protocol === "ap+ef61:") return (0, _fedify_vocab_runtime.formatIri)(id);
160
+ const portable = (0, _fedify_vocab_runtime.fromCompatibleEf61Id)(id);
161
+ return portable == null ? null : (0, _fedify_vocab_runtime.formatIri)(portable);
162
+ } catch (error) {
163
+ if (error instanceof TypeError) return null;
164
+ throw error;
165
+ }
166
+ }
167
+ function isSameActorId(a, b) {
168
+ const portableA = getPortableIri(a);
169
+ const portableB = getPortableIri(b);
170
+ if (portableA != null || portableB != null) return portableA != null && portableB != null && (0, _fedify_vocab_runtime.arePortableUrisEqual)(portableA, portableB);
171
+ return a.href === b.href;
172
+ }
173
+ /**
174
+ * The default implementation of `RequestContext.isSignedByAudience()` for
175
+ * testing, which checks the audience against `getSignedKeyOwner()`.
176
+ */
177
+ async function isSignedByAudience(getSignedKeyOwner, object, isMember) {
178
+ const addressees = [
179
+ ...object.toIds,
180
+ ...object.ccIds,
181
+ ...object.btoIds,
182
+ ...object.bccIds,
183
+ ...object.audienceIds
184
+ ];
185
+ if (addressees.some((id) => PUBLIC_IDS.has(id.href))) return true;
186
+ const actor = await getSignedKeyOwner();
187
+ const actorId = actor?.id;
188
+ if (actor == null || actorId == null) return false;
189
+ if (addressees.some((id) => isSameActorId(id, actorId))) return true;
190
+ if (isMember == null) return false;
191
+ for (const addressee of addressees) if (await isMember(addressee, actor)) return true;
192
+ return false;
193
+ }
151
194
  /**
152
195
  * Creates an InboxContext for testing purposes.
153
196
  * Not exported - used internally only. Public API is in mock.ts
@@ -868,6 +911,9 @@ var MockContext = class MockContext {
868
911
  getSignedKeyOwner() {
869
912
  return Promise.resolve(null);
870
913
  }
914
+ isSignedByAudience(object, options) {
915
+ return isSignedByAudience(() => this.getSignedKeyOwner(), object, options?.isMember);
916
+ }
871
917
  #resolveTaskDefinition(task) {
872
918
  if (!(this.federation instanceof MockFederation)) throw new TypeError("No task definitions are available.");
873
919
  const def = this.federation.taskDefinitions.get(task.name);
package/dist/mod.d.cts CHANGED
@@ -22,6 +22,10 @@ declare function createRequestContext<TContextData>(args: Partial<RequestContext
22
22
  federation: Federation<TContextData>;
23
23
  }): RequestContext<TContextData>;
24
24
  /**
25
+ * The default implementation of `RequestContext.isSignedByAudience()` for
26
+ * testing, which checks the audience against `getSignedKeyOwner()`.
27
+ */
28
+ /**
25
29
  * Test-specific InboxContext type alias.
26
30
  * This indirection helps avoid JSR type analyzer issues.
27
31
  * @since 1.9.1
@@ -82,7 +86,7 @@ interface SentActivity {
82
86
  * Extends the standard Context interface with additional testing utilities.
83
87
  * @since 1.9.1
84
88
  */
85
- interface TestContext<TContextData> extends Omit<Context<TContextData>, "clone">, Pick<RequestContext<TContextData>, "request" | "url" | "getActor" | "getObject" | "getSignedKey" | "getSignedKeyOwner" | "sendActivity" | "routeActivity"> {
89
+ interface TestContext<TContextData> extends Omit<Context<TContextData>, "clone">, Pick<RequestContext<TContextData>, "request" | "url" | "getActor" | "getObject" | "getSignedKey" | "getSignedKeyOwner" | "isSignedByAudience" | "sendActivity" | "routeActivity"> {
86
90
  clone(data: TContextData): TestContext<TContextData>;
87
91
  getSentActivities(): Array<{
88
92
  sender: any;
package/dist/mod.d.ts CHANGED
@@ -22,6 +22,10 @@ declare function createRequestContext<TContextData>(args: Partial<RequestContext
22
22
  federation: Federation<TContextData>;
23
23
  }): RequestContext<TContextData>;
24
24
  /**
25
+ * The default implementation of `RequestContext.isSignedByAudience()` for
26
+ * testing, which checks the audience against `getSignedKeyOwner()`.
27
+ */
28
+ /**
25
29
  * Test-specific InboxContext type alias.
26
30
  * This indirection helps avoid JSR type analyzer issues.
27
31
  * @since 1.9.1
@@ -82,7 +86,7 @@ interface SentActivity {
82
86
  * Extends the standard Context interface with additional testing utilities.
83
87
  * @since 1.9.1
84
88
  */
85
- interface TestContext<TContextData> extends Omit<Context<TContextData>, "clone">, Pick<RequestContext<TContextData>, "request" | "url" | "getActor" | "getObject" | "getSignedKey" | "getSignedKeyOwner" | "sendActivity" | "routeActivity"> {
89
+ interface TestContext<TContextData> extends Omit<Context<TContextData>, "clone">, Pick<RequestContext<TContextData>, "request" | "url" | "getActor" | "getObject" | "getSignedKey" | "getSignedKeyOwner" | "isSignedByAudience" | "sendActivity" | "routeActivity"> {
86
90
  clone(data: TContextData): TestContext<TContextData>;
87
91
  getSentActivities(): Array<{
88
92
  sender: any;
package/dist/mod.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Temporal } from "temporal-polyfill";
2
2
  import { hasProofLike, hasSignatureLike } from "@fedify/fedify/sig";
3
- import { Activity, CryptographicKey, Multikey, Tombstone, lookupObject, traverseCollection } from "@fedify/vocab";
4
- import { canonicalizePortableUri, formatIri, fromCompatibleEf61Id, getFe34Origin, parseIri } from "@fedify/vocab-runtime";
3
+ import { Activity, CryptographicKey, Multikey, PUBLIC_COLLECTION, Tombstone, lookupObject, traverseCollection } from "@fedify/vocab";
4
+ import { arePortableUrisEqual, canonicalizePortableUri, formatIri, fromCompatibleEf61Id, getFe34Origin, parseIri } from "@fedify/vocab-runtime";
5
5
  import { RouterError } from "@fedify/fedify/federation";
6
6
  import { delay } from "es-toolkit";
7
7
  import { deepStrictEqual, ok, strictEqual } from "node:assert/strict";
@@ -142,11 +142,54 @@ function createRequestContext(args) {
142
142
  getObject: args.getObject ?? (() => Promise.resolve(null)),
143
143
  getSignedKey: args.getSignedKey ?? (() => Promise.resolve(null)),
144
144
  getSignedKeyOwner: args.getSignedKeyOwner ?? (() => Promise.resolve(null)),
145
+ isSignedByAudience: args.isSignedByAudience ?? ((object, options) => isSignedByAudience(() => args.getSignedKeyOwner == null ? Promise.resolve(null) : args.getSignedKeyOwner(options ?? {}), object, options?.isMember)),
145
146
  sendActivity: args.sendActivity ?? ((_params) => {
146
147
  throw new Error("Not implemented");
147
148
  })
148
149
  };
149
150
  }
151
+ const PUBLIC_IDS = /* @__PURE__ */ new Set([
152
+ PUBLIC_COLLECTION.href,
153
+ "as:Public",
154
+ "Public"
155
+ ]);
156
+ function getPortableIri(id) {
157
+ try {
158
+ if (id.protocol === "ap:" || id.protocol === "ap+ef61:") return formatIri(id);
159
+ const portable = fromCompatibleEf61Id(id);
160
+ return portable == null ? null : formatIri(portable);
161
+ } catch (error) {
162
+ if (error instanceof TypeError) return null;
163
+ throw error;
164
+ }
165
+ }
166
+ function isSameActorId(a, b) {
167
+ const portableA = getPortableIri(a);
168
+ const portableB = getPortableIri(b);
169
+ if (portableA != null || portableB != null) return portableA != null && portableB != null && arePortableUrisEqual(portableA, portableB);
170
+ return a.href === b.href;
171
+ }
172
+ /**
173
+ * The default implementation of `RequestContext.isSignedByAudience()` for
174
+ * testing, which checks the audience against `getSignedKeyOwner()`.
175
+ */
176
+ async function isSignedByAudience(getSignedKeyOwner, object, isMember) {
177
+ const addressees = [
178
+ ...object.toIds,
179
+ ...object.ccIds,
180
+ ...object.btoIds,
181
+ ...object.bccIds,
182
+ ...object.audienceIds
183
+ ];
184
+ if (addressees.some((id) => PUBLIC_IDS.has(id.href))) return true;
185
+ const actor = await getSignedKeyOwner();
186
+ const actorId = actor?.id;
187
+ if (actor == null || actorId == null) return false;
188
+ if (addressees.some((id) => isSameActorId(id, actorId))) return true;
189
+ if (isMember == null) return false;
190
+ for (const addressee of addressees) if (await isMember(addressee, actor)) return true;
191
+ return false;
192
+ }
150
193
  /**
151
194
  * Creates an InboxContext for testing purposes.
152
195
  * Not exported - used internally only. Public API is in mock.ts
@@ -867,6 +910,9 @@ var MockContext = class MockContext {
867
910
  getSignedKeyOwner() {
868
911
  return Promise.resolve(null);
869
912
  }
913
+ isSignedByAudience(object, options) {
914
+ return isSignedByAudience(() => this.getSignedKeyOwner(), object, options?.isMember);
915
+ }
870
916
  #resolveTaskDefinition(task) {
871
917
  if (!(this.federation instanceof MockFederation)) throw new TypeError("No task definitions are available.");
872
918
  const def = this.federation.taskDefinitions.get(task.name);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/testing",
3
- "version": "2.4.0-dev.2193+402149b5",
3
+ "version": "2.4.0-dev.2212+26ce9858",
4
4
  "description": "Testing utilities for Fedify applications",
5
5
  "keywords": [
6
6
  "fedify",
@@ -47,13 +47,13 @@
47
47
  "package.json"
48
48
  ],
49
49
  "peerDependencies": {
50
- "@fedify/fedify": "^2.4.0-dev.2193+402149b5"
50
+ "@fedify/fedify": "^2.4.0-dev.2212+26ce9858"
51
51
  },
52
52
  "dependencies": {
53
53
  "es-toolkit": "1.46.1",
54
54
  "temporal-polyfill": "^1.0.1",
55
- "@fedify/vocab": "2.4.0-dev.2193+402149b5",
56
- "@fedify/vocab-runtime": "^2.4.0-dev.2193+402149b5"
55
+ "@fedify/vocab-runtime": "^2.4.0-dev.2212+26ce9858",
56
+ "@fedify/vocab": "2.4.0-dev.2212+26ce9858"
57
57
  },
58
58
  "devDependencies": {
59
59
  "@standard-schema/spec": "^1.1.0",