@fedify/testing 2.4.0-dev.2200 → 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 +46 -0
- package/dist/mod.d.cts +5 -1
- package/dist/mod.d.ts +5 -1
- package/dist/mod.js +48 -2
- package/package.json +4 -4
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.
|
|
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.
|
|
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.
|
|
56
|
-
"@fedify/vocab
|
|
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",
|