@fedify/testing 2.0.0-dev.1641 → 2.0.0-dev.166
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/LICENSE +1 -1
- package/README.md +9 -7
- package/dist/mod.cjs +112 -43
- package/dist/mod.d.cts +83 -254
- package/dist/mod.d.ts +83 -254
- package/dist/mod.js +111 -41
- package/package.json +3 -6
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -40,7 +40,7 @@ interface for unit testing:
|
|
|
40
40
|
|
|
41
41
|
~~~~ typescript
|
|
42
42
|
import { MockFederation } from "@fedify/testing";
|
|
43
|
-
import { Create } from "@fedify/
|
|
43
|
+
import { Create } from "@fedify/vocab";
|
|
44
44
|
|
|
45
45
|
// Create a mock federation
|
|
46
46
|
const federation = new MockFederation<{ userId: string }>();
|
|
@@ -95,10 +95,12 @@ The package also exports helper functions for creating various context types:
|
|
|
95
95
|
- `createRequestContext()`: Creates a request context
|
|
96
96
|
- `createInboxContext()`: Creates an inbox context
|
|
97
97
|
|
|
98
|
-
## Features
|
|
99
98
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
-
|
|
104
|
-
-
|
|
99
|
+
Features
|
|
100
|
+
--------
|
|
101
|
+
|
|
102
|
+
- Track sent activities with metadata
|
|
103
|
+
- Simulate activity reception
|
|
104
|
+
- Configure custom URI templates
|
|
105
|
+
- Test queue-based activity processing
|
|
106
|
+
- Mock document loaders and context loaders
|
package/dist/mod.cjs
CHANGED
|
@@ -21,10 +21,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
21
21
|
}) : target, mod));
|
|
22
22
|
|
|
23
23
|
//#endregion
|
|
24
|
-
const __opentelemetry_api = __toESM(require("@opentelemetry/api"));
|
|
25
24
|
const __fedify_fedify_federation = __toESM(require("@fedify/fedify/federation"));
|
|
26
|
-
const
|
|
27
|
-
const __fedify_fedify_webfinger = __toESM(require("@fedify/fedify/webfinger"));
|
|
25
|
+
const __fedify_vocab = __toESM(require("@fedify/vocab"));
|
|
28
26
|
|
|
29
27
|
//#region src/docloader.ts
|
|
30
28
|
const mockDocumentLoader = async (url) => ({
|
|
@@ -35,6 +33,10 @@ const mockDocumentLoader = async (url) => ({
|
|
|
35
33
|
|
|
36
34
|
//#endregion
|
|
37
35
|
//#region src/context.ts
|
|
36
|
+
const noopTracerProvider$1 = { getTracer: () => ({
|
|
37
|
+
startActiveSpan: () => void 0,
|
|
38
|
+
startSpan: () => void 0
|
|
39
|
+
}) };
|
|
38
40
|
function createContext(values) {
|
|
39
41
|
const { federation, url = new URL("http://example.com/"), canonicalOrigin, data, documentLoader, contextLoader, tracerProvider, clone, getNodeInfoUri, getActorUri, getObjectUri, getCollectionUri, getOutboxUri, getInboxUri, getFollowingUri, getFollowersUri, getLikedUri, getFeaturedUri, getFeaturedTagsUri, parseUri, getActorKeyPairs, getDocumentLoader, lookupObject, traverseCollection, lookupNodeInfo, lookupWebFinger, sendActivity, routeActivity } = values;
|
|
40
42
|
function throwRouteError() {
|
|
@@ -49,7 +51,7 @@ function createContext(values) {
|
|
|
49
51
|
hostname: url.hostname,
|
|
50
52
|
documentLoader: documentLoader ?? mockDocumentLoader,
|
|
51
53
|
contextLoader: contextLoader ?? mockDocumentLoader,
|
|
52
|
-
tracerProvider: tracerProvider ??
|
|
54
|
+
tracerProvider: tracerProvider ?? noopTracerProvider$1,
|
|
53
55
|
clone: clone ?? ((data$1) => createContext({
|
|
54
56
|
...values,
|
|
55
57
|
data: data$1
|
|
@@ -73,13 +75,13 @@ function createContext(values) {
|
|
|
73
75
|
}),
|
|
74
76
|
getActorKeyPairs: getActorKeyPairs ?? ((_handle) => Promise.resolve([])),
|
|
75
77
|
lookupObject: lookupObject ?? ((uri, options = {}) => {
|
|
76
|
-
return (0,
|
|
78
|
+
return (0, __fedify_vocab.lookupObject)(uri, {
|
|
77
79
|
documentLoader: options.documentLoader ?? documentLoader ?? mockDocumentLoader,
|
|
78
80
|
contextLoader: options.contextLoader ?? contextLoader ?? mockDocumentLoader
|
|
79
81
|
});
|
|
80
82
|
}),
|
|
81
83
|
traverseCollection: traverseCollection ?? ((collection, options = {}) => {
|
|
82
|
-
return (0,
|
|
84
|
+
return (0, __fedify_vocab.traverseCollection)(collection, {
|
|
83
85
|
documentLoader: options.documentLoader ?? documentLoader ?? mockDocumentLoader,
|
|
84
86
|
contextLoader: options.contextLoader ?? contextLoader ?? mockDocumentLoader
|
|
85
87
|
});
|
|
@@ -87,8 +89,8 @@ function createContext(values) {
|
|
|
87
89
|
lookupNodeInfo: lookupNodeInfo ?? ((_params) => {
|
|
88
90
|
throw new Error("Not implemented");
|
|
89
91
|
}),
|
|
90
|
-
lookupWebFinger: lookupWebFinger ?? ((
|
|
91
|
-
return
|
|
92
|
+
lookupWebFinger: lookupWebFinger ?? ((_resource, _options = {}) => {
|
|
93
|
+
return Promise.resolve(null);
|
|
92
94
|
}),
|
|
93
95
|
sendActivity: sendActivity ?? ((_params) => {
|
|
94
96
|
throw new Error("Not implemented");
|
|
@@ -98,6 +100,13 @@ function createContext(values) {
|
|
|
98
100
|
})
|
|
99
101
|
};
|
|
100
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* Creates a RequestContext for testing purposes.
|
|
105
|
+
* Not exported - used internally only. Public API is in mock.ts
|
|
106
|
+
* @param args Partial RequestContext properties
|
|
107
|
+
* @returns A RequestContext instance
|
|
108
|
+
* @since 1.8.0
|
|
109
|
+
*/
|
|
101
110
|
function createRequestContext(args) {
|
|
102
111
|
return {
|
|
103
112
|
...createContext(args),
|
|
@@ -116,6 +125,13 @@ function createRequestContext(args) {
|
|
|
116
125
|
})
|
|
117
126
|
};
|
|
118
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* Creates an InboxContext for testing purposes.
|
|
130
|
+
* Not exported - used internally only. Public API is in mock.ts
|
|
131
|
+
* @param args Partial InboxContext properties
|
|
132
|
+
* @returns An InboxContext instance
|
|
133
|
+
* @since 1.8.0
|
|
134
|
+
*/
|
|
119
135
|
function createInboxContext(args) {
|
|
120
136
|
return {
|
|
121
137
|
...createContext(args),
|
|
@@ -132,6 +148,10 @@ function createInboxContext(args) {
|
|
|
132
148
|
|
|
133
149
|
//#endregion
|
|
134
150
|
//#region src/mock.ts
|
|
151
|
+
const noopTracerProvider = { getTracer: () => ({
|
|
152
|
+
startActiveSpan: () => void 0,
|
|
153
|
+
startSpan: () => void 0
|
|
154
|
+
}) };
|
|
135
155
|
/**
|
|
136
156
|
* Helper function to expand URI templates with values.
|
|
137
157
|
* Supports simple placeholders like {identifier}, {handle}, etc.
|
|
@@ -151,18 +171,18 @@ function expandUriTemplate(template, values) {
|
|
|
151
171
|
*
|
|
152
172
|
* @example
|
|
153
173
|
* ```typescript
|
|
154
|
-
* import { Create } from "@fedify/
|
|
155
|
-
* import {
|
|
174
|
+
* import { Create } from "@fedify/vocab";
|
|
175
|
+
* import { createFederation } from "@fedify/testing";
|
|
156
176
|
*
|
|
157
177
|
* // Create a mock federation with contextData
|
|
158
|
-
* const federation =
|
|
178
|
+
* const federation = createFederation<{ userId: string }>({
|
|
159
179
|
* contextData: { userId: "test-user" }
|
|
160
180
|
* });
|
|
161
181
|
*
|
|
162
182
|
* // Set up inbox listeners
|
|
163
183
|
* federation
|
|
164
184
|
* .setInboxListeners("/users/{identifier}/inbox")
|
|
165
|
-
* .on(Create, async (ctx, activity) => {
|
|
185
|
+
* .on(Create, async (ctx: any, activity: any) => {
|
|
166
186
|
* console.log("Received:", activity);
|
|
167
187
|
* });
|
|
168
188
|
*
|
|
@@ -318,6 +338,9 @@ var MockFederation = class {
|
|
|
318
338
|
},
|
|
319
339
|
setSharedKeyDispatcher() {
|
|
320
340
|
return this;
|
|
341
|
+
},
|
|
342
|
+
withIdempotency() {
|
|
343
|
+
return this;
|
|
321
344
|
}
|
|
322
345
|
};
|
|
323
346
|
}
|
|
@@ -336,22 +359,9 @@ var MockFederation = class {
|
|
|
336
359
|
}
|
|
337
360
|
createContext(baseUrlOrRequest, contextData) {
|
|
338
361
|
const mockFederation = this;
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
data: contextData,
|
|
343
|
-
federation: mockFederation,
|
|
344
|
-
sendActivity: async (sender, recipients, activity, options) => {
|
|
345
|
-
const tempContext = new MockContext({
|
|
346
|
-
url: new URL(baseUrlOrRequest.url),
|
|
347
|
-
data: contextData,
|
|
348
|
-
federation: mockFederation
|
|
349
|
-
});
|
|
350
|
-
await tempContext.sendActivity(sender, recipients, activity, options);
|
|
351
|
-
}
|
|
352
|
-
});
|
|
353
|
-
else return new MockContext({
|
|
354
|
-
url: baseUrlOrRequest,
|
|
362
|
+
const url = baseUrlOrRequest instanceof Request ? new URL(baseUrlOrRequest.url) : baseUrlOrRequest;
|
|
363
|
+
return new MockContext({
|
|
364
|
+
url,
|
|
355
365
|
data: contextData,
|
|
356
366
|
federation: mockFederation
|
|
357
367
|
});
|
|
@@ -409,22 +419,66 @@ var MockFederation = class {
|
|
|
409
419
|
}
|
|
410
420
|
};
|
|
411
421
|
/**
|
|
422
|
+
* Creates a mock Federation instance for testing purposes.
|
|
423
|
+
*
|
|
424
|
+
* @template TContextData The type of context data to use
|
|
425
|
+
* @param options Optional configuration for the mock federation
|
|
426
|
+
* @returns A Federation instance that can be used for testing
|
|
427
|
+
* @since 1.9.1
|
|
428
|
+
*
|
|
429
|
+
* @example
|
|
430
|
+
* ```typescript
|
|
431
|
+
* import { Create } from "@fedify/vocab";
|
|
432
|
+
* import { createFederation } from "@fedify/testing";
|
|
433
|
+
*
|
|
434
|
+
* // Create a mock federation with contextData
|
|
435
|
+
* const federation = createFederation<{ userId: string }>({
|
|
436
|
+
* contextData: { userId: "test-user" }
|
|
437
|
+
* });
|
|
438
|
+
*
|
|
439
|
+
* // Set up inbox listeners
|
|
440
|
+
* federation
|
|
441
|
+
* .setInboxListeners("/users/{identifier}/inbox")
|
|
442
|
+
* .on(Create, async (ctx, activity) => {
|
|
443
|
+
* console.log("Received:", activity);
|
|
444
|
+
* });
|
|
445
|
+
*
|
|
446
|
+
* // Simulate receiving an activity
|
|
447
|
+
* const createActivity = new Create({
|
|
448
|
+
* id: new URL("https://example.com/create/1"),
|
|
449
|
+
* actor: new URL("https://example.com/users/alice")
|
|
450
|
+
* });
|
|
451
|
+
* await federation.receiveActivity(createActivity);
|
|
452
|
+
*
|
|
453
|
+
* // Check sent activities
|
|
454
|
+
* console.log(federation.sentActivities);
|
|
455
|
+
* ```
|
|
456
|
+
*/
|
|
457
|
+
function createFederation(options = {}) {
|
|
458
|
+
return new MockFederation(options);
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
412
461
|
* A mock implementation of the {@link Context} interface for unit testing.
|
|
413
462
|
* This class provides a way to test Fedify applications without needing
|
|
414
463
|
* a real federation context.
|
|
415
464
|
*
|
|
465
|
+
* Note: This class is not exported from the public API to avoid JSR type
|
|
466
|
+
* analyzer issues. The MockContext class has complex type dependencies that
|
|
467
|
+
* can cause JSR's type analyzer to hang during processing (issue #468).
|
|
468
|
+
* Use {@link MockFederation.createContext}, {@link createContext},
|
|
469
|
+
* {@link createRequestContext}, or {@link createInboxContext} instead.
|
|
470
|
+
*
|
|
416
471
|
* @example
|
|
417
472
|
* ```typescript
|
|
418
|
-
* import { Person, Create } from "@fedify/
|
|
419
|
-
* import {
|
|
473
|
+
* import { Person, Create } from "@fedify/vocab";
|
|
474
|
+
* import { createFederation } from "@fedify/testing";
|
|
420
475
|
*
|
|
421
|
-
* // Create a mock context
|
|
422
|
-
* const
|
|
423
|
-
* const context =
|
|
424
|
-
*
|
|
425
|
-
*
|
|
426
|
-
*
|
|
427
|
-
* });
|
|
476
|
+
* // Create a mock federation and context
|
|
477
|
+
* const federation = createFederation<{ userId: string }>();
|
|
478
|
+
* const context = federation.createContext(
|
|
479
|
+
* new URL("https://example.com"),
|
|
480
|
+
* { userId: "test-user" }
|
|
481
|
+
* );
|
|
428
482
|
*
|
|
429
483
|
* // Send an activity
|
|
430
484
|
* const recipient = new Person({ id: new URL("https://example.com/users/bob") });
|
|
@@ -438,8 +492,8 @@ var MockFederation = class {
|
|
|
438
492
|
* activity
|
|
439
493
|
* );
|
|
440
494
|
*
|
|
441
|
-
* // Check sent activities
|
|
442
|
-
* const sent =
|
|
495
|
+
* // Check sent activities from the federation
|
|
496
|
+
* const sent = federation.sentActivities;
|
|
443
497
|
* console.log(sent[0].activity);
|
|
444
498
|
* ```
|
|
445
499
|
*
|
|
@@ -456,6 +510,8 @@ var MockContext = class MockContext {
|
|
|
456
510
|
documentLoader;
|
|
457
511
|
contextLoader;
|
|
458
512
|
tracerProvider;
|
|
513
|
+
request;
|
|
514
|
+
url;
|
|
459
515
|
sentActivities = [];
|
|
460
516
|
constructor(options) {
|
|
461
517
|
const url = options.url ?? new URL("https://example.com");
|
|
@@ -463,6 +519,8 @@ var MockContext = class MockContext {
|
|
|
463
519
|
this.canonicalOrigin = url.origin;
|
|
464
520
|
this.host = url.host;
|
|
465
521
|
this.hostname = url.hostname;
|
|
522
|
+
this.url = url;
|
|
523
|
+
this.request = new Request(url);
|
|
466
524
|
this.data = options.data;
|
|
467
525
|
this.federation = options.federation;
|
|
468
526
|
this.documentLoader = options.documentLoader ?? (async (url$1) => ({
|
|
@@ -471,11 +529,23 @@ var MockContext = class MockContext {
|
|
|
471
529
|
documentUrl: url$1
|
|
472
530
|
}));
|
|
473
531
|
this.contextLoader = options.contextLoader ?? this.documentLoader;
|
|
474
|
-
this.tracerProvider = options.tracerProvider ??
|
|
532
|
+
this.tracerProvider = options.tracerProvider ?? noopTracerProvider;
|
|
533
|
+
}
|
|
534
|
+
getActor(_handle) {
|
|
535
|
+
return Promise.resolve(null);
|
|
536
|
+
}
|
|
537
|
+
getObject(_cls, _values) {
|
|
538
|
+
return Promise.resolve(null);
|
|
539
|
+
}
|
|
540
|
+
getSignedKey() {
|
|
541
|
+
return Promise.resolve(null);
|
|
542
|
+
}
|
|
543
|
+
getSignedKeyOwner() {
|
|
544
|
+
return Promise.resolve(null);
|
|
475
545
|
}
|
|
476
546
|
clone(data) {
|
|
477
547
|
return new MockContext({
|
|
478
|
-
url:
|
|
548
|
+
url: this.url,
|
|
479
549
|
data,
|
|
480
550
|
federation: this.federation,
|
|
481
551
|
documentLoader: this.documentLoader,
|
|
@@ -657,8 +727,7 @@ var MockContext = class MockContext {
|
|
|
657
727
|
};
|
|
658
728
|
|
|
659
729
|
//#endregion
|
|
660
|
-
exports.MockContext = MockContext;
|
|
661
|
-
exports.MockFederation = MockFederation;
|
|
662
730
|
exports.createContext = createContext;
|
|
731
|
+
exports.createFederation = createFederation;
|
|
663
732
|
exports.createInboxContext = createInboxContext;
|
|
664
733
|
exports.createRequestContext = createRequestContext;
|
package/dist/mod.d.cts
CHANGED
|
@@ -1,12 +1,45 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { DocumentLoader } from "@fedify/fedify/runtime";
|
|
4
|
-
import { Activity, Actor, Collection, Hashtag, LookupObjectOptions, Object as Object$1, Recipient, TraverseCollectionOptions } from "@fedify/fedify/vocab";
|
|
5
|
-
import { ResourceDescriptor } from "@fedify/fedify/webfinger";
|
|
6
|
-
import { TracerProvider } from "@opentelemetry/api";
|
|
1
|
+
import { Context, Federation, InboxContext, RequestContext } from "@fedify/fedify/federation";
|
|
2
|
+
import { Activity } from "@fedify/vocab";
|
|
7
3
|
|
|
4
|
+
//#region src/context.d.ts
|
|
5
|
+
declare function createContext<TContextData>(values: Partial<Context<TContextData>> & {
|
|
6
|
+
url?: URL;
|
|
7
|
+
data: TContextData;
|
|
8
|
+
federation: Federation<TContextData>;
|
|
9
|
+
}): Context<TContextData>;
|
|
10
|
+
/**
|
|
11
|
+
* Creates a RequestContext for testing purposes.
|
|
12
|
+
* Not exported - used internally only. Public API is in mock.ts
|
|
13
|
+
* @param args Partial RequestContext properties
|
|
14
|
+
* @returns A RequestContext instance
|
|
15
|
+
* @since 1.8.0
|
|
16
|
+
*/
|
|
17
|
+
declare function createRequestContext<TContextData>(args: Partial<RequestContext<TContextData>> & {
|
|
18
|
+
url: URL;
|
|
19
|
+
data: TContextData;
|
|
20
|
+
federation: Federation<TContextData>;
|
|
21
|
+
}): RequestContext<TContextData>;
|
|
22
|
+
/**
|
|
23
|
+
* Test-specific InboxContext type alias.
|
|
24
|
+
* This indirection helps avoid JSR type analyzer issues.
|
|
25
|
+
* @since 1.9.1
|
|
26
|
+
*/
|
|
27
|
+
type TestInboxContext<TContextData> = InboxContext<TContextData>;
|
|
28
|
+
/**
|
|
29
|
+
* Creates an InboxContext for testing purposes.
|
|
30
|
+
* Not exported - used internally only. Public API is in mock.ts
|
|
31
|
+
* @param args Partial InboxContext properties
|
|
32
|
+
* @returns An InboxContext instance
|
|
33
|
+
* @since 1.8.0
|
|
34
|
+
*/
|
|
35
|
+
declare function createInboxContext<TContextData>(args: Partial<InboxContext<TContextData>> & {
|
|
36
|
+
url?: URL;
|
|
37
|
+
data: TContextData;
|
|
38
|
+
recipient?: string | null;
|
|
39
|
+
federation: Federation<TContextData>;
|
|
40
|
+
}): TestInboxContext<TContextData>;
|
|
41
|
+
//#endregion
|
|
8
42
|
//#region src/mock.d.ts
|
|
9
|
-
|
|
10
43
|
/**
|
|
11
44
|
* Represents a sent activity with metadata about how it was sent.
|
|
12
45
|
* @since 1.8.0
|
|
@@ -22,17 +55,47 @@ interface SentActivity {
|
|
|
22
55
|
sentOrder: number;
|
|
23
56
|
}
|
|
24
57
|
/**
|
|
25
|
-
* A mock
|
|
26
|
-
*
|
|
27
|
-
*
|
|
58
|
+
* A mock Context interface for testing purposes.
|
|
59
|
+
* Extends the standard Context interface with additional testing utilities.
|
|
60
|
+
* @since 1.9.1
|
|
61
|
+
*/
|
|
62
|
+
interface TestContext<TContextData> extends Omit<Context<TContextData>, "clone">, Pick<RequestContext<TContextData>, "request" | "url" | "getActor" | "getObject" | "getSignedKey" | "getSignedKeyOwner" | "sendActivity" | "routeActivity"> {
|
|
63
|
+
clone(data: TContextData): TestContext<TContextData>;
|
|
64
|
+
getSentActivities(): Array<{
|
|
65
|
+
sender: any;
|
|
66
|
+
recipients: any;
|
|
67
|
+
activity: Activity;
|
|
68
|
+
}>;
|
|
69
|
+
reset(): void;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* A mock Federation interface for testing purposes.
|
|
73
|
+
* Extends the standard Federation interface with additional testing utilities.
|
|
74
|
+
* @since 1.9.1
|
|
75
|
+
*/
|
|
76
|
+
interface TestFederation<TContextData> extends Omit<Federation<TContextData>, "createContext"> {
|
|
77
|
+
sentActivities: SentActivity[];
|
|
78
|
+
queueStarted: boolean;
|
|
79
|
+
sentCounter: number;
|
|
80
|
+
receiveActivity(activity: Activity): Promise<void>;
|
|
81
|
+
reset(): void;
|
|
82
|
+
createContext(baseUrlOrRequest: URL | Request, contextData: TContextData): TestContext<TContextData>;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Creates a mock Federation instance for testing purposes.
|
|
86
|
+
*
|
|
87
|
+
* @template TContextData The type of context data to use
|
|
88
|
+
* @param options Optional configuration for the mock federation
|
|
89
|
+
* @returns A Federation instance that can be used for testing
|
|
90
|
+
* @since 1.9.1
|
|
28
91
|
*
|
|
29
92
|
* @example
|
|
30
93
|
* ```typescript
|
|
31
|
-
* import { Create } from "@fedify/
|
|
32
|
-
* import {
|
|
94
|
+
* import { Create } from "@fedify/vocab";
|
|
95
|
+
* import { createFederation } from "@fedify/testing";
|
|
33
96
|
*
|
|
34
97
|
* // Create a mock federation with contextData
|
|
35
|
-
* const federation =
|
|
98
|
+
* const federation = createFederation<{ userId: string }>({
|
|
36
99
|
* contextData: { userId: "test-user" }
|
|
37
100
|
* });
|
|
38
101
|
*
|
|
@@ -49,249 +112,15 @@ interface SentActivity {
|
|
|
49
112
|
* actor: new URL("https://example.com/users/alice")
|
|
50
113
|
* });
|
|
51
114
|
* await federation.receiveActivity(createActivity);
|
|
52
|
-
* ```
|
|
53
|
-
*
|
|
54
|
-
* @template TContextData The context data to pass to the {@link Context}.
|
|
55
|
-
* @since 1.8.0
|
|
56
|
-
*/
|
|
57
|
-
declare class MockFederation<TContextData> implements Federation<TContextData> {
|
|
58
|
-
private options;
|
|
59
|
-
sentActivities: SentActivity[];
|
|
60
|
-
queueStarted: boolean;
|
|
61
|
-
private activeQueues;
|
|
62
|
-
sentCounter: number;
|
|
63
|
-
private nodeInfoDispatcher?;
|
|
64
|
-
private webFingerDispatcher?;
|
|
65
|
-
private actorDispatchers;
|
|
66
|
-
actorPath?: string;
|
|
67
|
-
inboxPath?: string;
|
|
68
|
-
outboxPath?: string;
|
|
69
|
-
followingPath?: string;
|
|
70
|
-
followersPath?: string;
|
|
71
|
-
likedPath?: string;
|
|
72
|
-
featuredPath?: string;
|
|
73
|
-
featuredTagsPath?: string;
|
|
74
|
-
nodeInfoPath?: string;
|
|
75
|
-
sharedInboxPath?: string;
|
|
76
|
-
objectPaths: Map<string, string>;
|
|
77
|
-
private objectDispatchers;
|
|
78
|
-
private inboxDispatcher?;
|
|
79
|
-
private outboxDispatcher?;
|
|
80
|
-
private followingDispatcher?;
|
|
81
|
-
private followersDispatcher?;
|
|
82
|
-
private likedDispatcher?;
|
|
83
|
-
private featuredDispatcher?;
|
|
84
|
-
private featuredTagsDispatcher?;
|
|
85
|
-
private inboxListeners;
|
|
86
|
-
private contextData?;
|
|
87
|
-
private receivedActivities;
|
|
88
|
-
constructor(options?: {
|
|
89
|
-
contextData?: TContextData;
|
|
90
|
-
origin?: string;
|
|
91
|
-
tracerProvider?: TracerProvider;
|
|
92
|
-
});
|
|
93
|
-
setNodeInfoDispatcher(path: string, dispatcher: NodeInfoDispatcher<TContextData>): void;
|
|
94
|
-
setWebFingerLinksDispatcher(dispatcher: WebFingerLinksDispatcher<TContextData>): void;
|
|
95
|
-
setActorDispatcher(path: `${string}{identifier}${string}` | `${string}{handle}${string}`, dispatcher: ActorDispatcher<TContextData>): ActorCallbackSetters<TContextData>;
|
|
96
|
-
setObjectDispatcher<TObject extends Object$1, TParam extends string>(cls: (new (...args: any[]) => TObject) & {
|
|
97
|
-
typeId: URL;
|
|
98
|
-
}, path: string, dispatcher: ObjectDispatcher<TContextData, TObject, TParam>): ObjectCallbackSetters<TContextData, TObject, TParam>;
|
|
99
|
-
setInboxDispatcher(_path: `${string}{identifier}${string}` | `${string}{handle}${string}`, dispatcher: CollectionDispatcher<Activity, RequestContext<TContextData>, TContextData, void>): CollectionCallbackSetters<RequestContext<TContextData>, TContextData, void>;
|
|
100
|
-
setOutboxDispatcher(path: `${string}{identifier}${string}` | `${string}{handle}${string}`, dispatcher: CollectionDispatcher<Activity, RequestContext<TContextData>, TContextData, void>): CollectionCallbackSetters<RequestContext<TContextData>, TContextData, void>;
|
|
101
|
-
setFollowingDispatcher(path: `${string}{identifier}${string}` | `${string}{handle}${string}`, dispatcher: CollectionDispatcher<Actor | URL, RequestContext<TContextData>, TContextData, void>): CollectionCallbackSetters<RequestContext<TContextData>, TContextData, void>;
|
|
102
|
-
setFollowersDispatcher(path: `${string}{identifier}${string}` | `${string}{handle}${string}`, dispatcher: CollectionDispatcher<Recipient, Context<TContextData>, TContextData, URL>): CollectionCallbackSetters<Context<TContextData>, TContextData, URL>;
|
|
103
|
-
setLikedDispatcher(path: `${string}{identifier}${string}` | `${string}{handle}${string}`, dispatcher: CollectionDispatcher<Object$1 | URL, RequestContext<TContextData>, TContextData, void>): CollectionCallbackSetters<RequestContext<TContextData>, TContextData, void>;
|
|
104
|
-
setFeaturedDispatcher(path: `${string}{identifier}${string}` | `${string}{handle}${string}`, dispatcher: CollectionDispatcher<Object$1, RequestContext<TContextData>, TContextData, void>): CollectionCallbackSetters<RequestContext<TContextData>, TContextData, void>;
|
|
105
|
-
setFeaturedTagsDispatcher(path: `${string}{identifier}${string}` | `${string}{handle}${string}`, dispatcher: CollectionDispatcher<Hashtag, RequestContext<TContextData>, TContextData, void>): CollectionCallbackSetters<RequestContext<TContextData>, TContextData, void>;
|
|
106
|
-
setInboxListeners(inboxPath: `${string}{identifier}${string}` | `${string}{handle}${string}`, sharedInboxPath?: string): InboxListenerSetters<TContextData>;
|
|
107
|
-
startQueue(contextData: TContextData, options?: FederationStartQueueOptions): Promise<void>;
|
|
108
|
-
processQueuedTask(contextData: TContextData, _message: Message): Promise<void>;
|
|
109
|
-
createContext(baseUrl: URL, contextData: TContextData): Context<TContextData>;
|
|
110
|
-
createContext(request: Request, contextData: TContextData): RequestContext<TContextData>;
|
|
111
|
-
fetch(request: Request, options: FederationFetchOptions<TContextData>): Promise<Response>;
|
|
112
|
-
/**
|
|
113
|
-
* Simulates receiving an activity. This method is specific to the mock
|
|
114
|
-
* implementation and is used for testing purposes.
|
|
115
|
-
*
|
|
116
|
-
* @param activity The activity to receive.
|
|
117
|
-
* @returns A promise that resolves when the activity has been processed.
|
|
118
|
-
* @since 1.8.0
|
|
119
|
-
*/
|
|
120
|
-
receiveActivity(activity: Activity): Promise<void>;
|
|
121
|
-
/**
|
|
122
|
-
* Clears all sent activities from the mock federation.
|
|
123
|
-
* This method is specific to the mock implementation and is used for
|
|
124
|
-
* testing purposes.
|
|
125
|
-
*
|
|
126
|
-
* @since 1.8.0
|
|
127
|
-
*/
|
|
128
|
-
reset(): void;
|
|
129
|
-
setCollectionDispatcher<TObject extends Object$1, TParams extends Record<string, string>>(_name: string | symbol, _itemType: any, _path: any, _dispatcher: any): any;
|
|
130
|
-
setOrderedCollectionDispatcher<TObject extends Object$1, TParams extends Record<string, string>>(_name: string | symbol, _itemType: any, _path: any, _dispatcher: any): any;
|
|
131
|
-
}
|
|
132
|
-
/**
|
|
133
|
-
* A mock implementation of the {@link Context} interface for unit testing.
|
|
134
|
-
* This class provides a way to test Fedify applications without needing
|
|
135
|
-
* a real federation context.
|
|
136
|
-
*
|
|
137
|
-
* @example
|
|
138
|
-
* ```typescript
|
|
139
|
-
* import { Person, Create } from "@fedify/fedify/vocab";
|
|
140
|
-
* import { MockContext, MockFederation } from "@fedify/testing";
|
|
141
|
-
*
|
|
142
|
-
* // Create a mock context
|
|
143
|
-
* const mockFederation = new MockFederation<{ userId: string }>();
|
|
144
|
-
* const context = new MockContext({
|
|
145
|
-
* url: new URL("https://example.com"),
|
|
146
|
-
* data: { userId: "test-user" },
|
|
147
|
-
* federation: mockFederation
|
|
148
|
-
* });
|
|
149
|
-
*
|
|
150
|
-
* // Send an activity
|
|
151
|
-
* const recipient = new Person({ id: new URL("https://example.com/users/bob") });
|
|
152
|
-
* const activity = new Create({
|
|
153
|
-
* id: new URL("https://example.com/create/1"),
|
|
154
|
-
* actor: new URL("https://example.com/users/alice")
|
|
155
|
-
* });
|
|
156
|
-
* await context.sendActivity(
|
|
157
|
-
* { identifier: "alice" },
|
|
158
|
-
* recipient,
|
|
159
|
-
* activity
|
|
160
|
-
* );
|
|
161
115
|
*
|
|
162
116
|
* // Check sent activities
|
|
163
|
-
*
|
|
164
|
-
* console.log(sent[0].activity);
|
|
117
|
+
* console.log(federation.sentActivities);
|
|
165
118
|
* ```
|
|
166
|
-
*
|
|
167
|
-
* @template TContextData The context data to pass to the {@link Context}.
|
|
168
|
-
* @since 1.8.0
|
|
169
119
|
*/
|
|
170
|
-
declare
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
readonly data: TContextData;
|
|
176
|
-
readonly federation: Federation<TContextData>;
|
|
177
|
-
readonly documentLoader: DocumentLoader;
|
|
178
|
-
readonly contextLoader: DocumentLoader;
|
|
179
|
-
readonly tracerProvider: TracerProvider;
|
|
180
|
-
private sentActivities;
|
|
181
|
-
constructor(options: {
|
|
182
|
-
url?: URL;
|
|
183
|
-
data: TContextData;
|
|
184
|
-
federation: Federation<TContextData>;
|
|
185
|
-
documentLoader?: DocumentLoader;
|
|
186
|
-
contextLoader?: DocumentLoader;
|
|
187
|
-
tracerProvider?: TracerProvider;
|
|
188
|
-
});
|
|
189
|
-
clone(data: TContextData): Context<TContextData>;
|
|
190
|
-
getNodeInfoUri(): URL;
|
|
191
|
-
getActorUri(identifier: string): URL;
|
|
192
|
-
getObjectUri<TObject extends Object$1>(cls: (new (...args: any[]) => TObject) & {
|
|
193
|
-
typeId: URL;
|
|
194
|
-
}, values: Record<string, string>): URL;
|
|
195
|
-
getOutboxUri(identifier: string): URL;
|
|
196
|
-
getInboxUri(identifier: string): URL;
|
|
197
|
-
getInboxUri(): URL;
|
|
198
|
-
getFollowingUri(identifier: string): URL;
|
|
199
|
-
getFollowersUri(identifier: string): URL;
|
|
200
|
-
getLikedUri(identifier: string): URL;
|
|
201
|
-
getFeaturedUri(identifier: string): URL;
|
|
202
|
-
getFeaturedTagsUri(identifier: string): URL;
|
|
203
|
-
getCollectionUri<TParam extends Record<string, string>>(_name: string | symbol, values: TParam): URL;
|
|
204
|
-
parseUri(uri: URL): ParseUriResult | null;
|
|
205
|
-
getActorKeyPairs(_identifier: string): Promise<ActorKeyPair[]>;
|
|
206
|
-
getDocumentLoader(params: {
|
|
207
|
-
handle: string;
|
|
208
|
-
} | {
|
|
209
|
-
identifier: string;
|
|
210
|
-
}): Promise<DocumentLoader>;
|
|
211
|
-
getDocumentLoader(params: {
|
|
212
|
-
keyId: URL;
|
|
213
|
-
privateKey: CryptoKey;
|
|
214
|
-
}): DocumentLoader;
|
|
215
|
-
lookupObject(_uri: URL | string, _options?: LookupObjectOptions): Promise<Object$1 | null>;
|
|
216
|
-
traverseCollection<TItem, TContext extends Context<TContextData>>(_collection: Collection | URL | null, _options?: TraverseCollectionOptions): AsyncIterable<TItem>;
|
|
217
|
-
lookupNodeInfo(url: URL | string, options?: {
|
|
218
|
-
parse?: "strict" | "best-effort";
|
|
219
|
-
} & any): Promise<NodeInfo | undefined>;
|
|
220
|
-
lookupNodeInfo(url: URL | string, options?: {
|
|
221
|
-
parse: "none";
|
|
222
|
-
} & any): Promise<JsonValue | undefined>;
|
|
223
|
-
lookupWebFinger(_resource: URL | `acct:${string}@${string}` | string, _options?: any): Promise<ResourceDescriptor | null>;
|
|
224
|
-
sendActivity(sender: SenderKeyPair | SenderKeyPair[] | {
|
|
225
|
-
identifier: string;
|
|
226
|
-
} | {
|
|
227
|
-
username: string;
|
|
228
|
-
} | {
|
|
229
|
-
handle: string;
|
|
230
|
-
}, recipients: Recipient | Recipient[], activity: Activity, options?: SendActivityOptions): Promise<void>;
|
|
231
|
-
sendActivity(sender: {
|
|
232
|
-
identifier: string;
|
|
233
|
-
} | {
|
|
234
|
-
username: string;
|
|
235
|
-
} | {
|
|
236
|
-
handle: string;
|
|
237
|
-
}, recipients: "followers", activity: Activity, options?: SendActivityOptionsForCollection): Promise<void>;
|
|
238
|
-
sendActivity(sender: SenderKeyPair | SenderKeyPair[] | {
|
|
239
|
-
identifier: string;
|
|
240
|
-
} | {
|
|
241
|
-
username: string;
|
|
242
|
-
} | {
|
|
243
|
-
handle: string;
|
|
244
|
-
}, recipients: Recipient | Recipient[], activity: Activity, options?: SendActivityOptions): Promise<void>;
|
|
245
|
-
sendActivity(sender: {
|
|
246
|
-
identifier: string;
|
|
247
|
-
} | {
|
|
248
|
-
username: string;
|
|
249
|
-
} | {
|
|
250
|
-
handle: string;
|
|
251
|
-
}, recipients: "followers", activity: Activity, options?: SendActivityOptionsForCollection): Promise<void>;
|
|
252
|
-
routeActivity(_recipient: string | null, _activity: Activity, _options?: RouteActivityOptions): Promise<boolean>;
|
|
253
|
-
/**
|
|
254
|
-
* Gets all activities that have been sent through this mock context.
|
|
255
|
-
* This method is specific to the mock implementation and is used for
|
|
256
|
-
* testing purposes.
|
|
257
|
-
*
|
|
258
|
-
* @returns An array of sent activity records.
|
|
259
|
-
*/
|
|
260
|
-
getSentActivities(): Array<{
|
|
261
|
-
sender: SenderKeyPair | SenderKeyPair[] | {
|
|
262
|
-
identifier: string;
|
|
263
|
-
} | {
|
|
264
|
-
username: string;
|
|
265
|
-
} | {
|
|
266
|
-
handle: string;
|
|
267
|
-
};
|
|
268
|
-
recipients: Recipient | Recipient[] | "followers";
|
|
269
|
-
activity: Activity;
|
|
270
|
-
}>;
|
|
271
|
-
/**
|
|
272
|
-
* Clears all sent activities from the mock context.
|
|
273
|
-
* This method is specific to the mock implementation and is used for
|
|
274
|
-
* testing purposes.
|
|
275
|
-
*/
|
|
276
|
-
reset(): void;
|
|
277
|
-
}
|
|
278
|
-
//#endregion
|
|
279
|
-
//#region src/context.d.ts
|
|
280
|
-
declare function createContext<TContextData>(values: Partial<Context<TContextData>> & {
|
|
281
|
-
url?: URL;
|
|
282
|
-
data: TContextData;
|
|
283
|
-
federation: Federation<TContextData>;
|
|
284
|
-
}): Context<TContextData>;
|
|
285
|
-
declare function createRequestContext<TContextData>(args: Partial<RequestContext<TContextData>> & {
|
|
286
|
-
url: URL;
|
|
287
|
-
data: TContextData;
|
|
288
|
-
federation: Federation<TContextData>;
|
|
289
|
-
}): RequestContext<TContextData>;
|
|
290
|
-
declare function createInboxContext<TContextData>(args: Partial<InboxContext<TContextData>> & {
|
|
291
|
-
url?: URL;
|
|
292
|
-
data: TContextData;
|
|
293
|
-
recipient?: string | null;
|
|
294
|
-
federation: Federation<TContextData>;
|
|
295
|
-
}): InboxContext<TContextData>;
|
|
120
|
+
declare function createFederation<TContextData>(options?: {
|
|
121
|
+
contextData?: TContextData;
|
|
122
|
+
origin?: string;
|
|
123
|
+
tracerProvider?: any;
|
|
124
|
+
}): TestFederation<TContextData>;
|
|
296
125
|
//#endregion
|
|
297
|
-
export {
|
|
126
|
+
export { createContext, createFederation, createInboxContext, createRequestContext };
|
package/dist/mod.d.ts
CHANGED
|
@@ -1,12 +1,45 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { Activity, Actor, Collection, Hashtag, LookupObjectOptions, Object as Object$1, Recipient, TraverseCollectionOptions } from "@fedify/fedify/vocab";
|
|
4
|
-
import { ResourceDescriptor } from "@fedify/fedify/webfinger";
|
|
5
|
-
import { JsonValue, NodeInfo } from "@fedify/fedify/nodeinfo";
|
|
6
|
-
import { DocumentLoader } from "@fedify/fedify/runtime";
|
|
1
|
+
import { Context, Federation, InboxContext, RequestContext } from "@fedify/fedify/federation";
|
|
2
|
+
import { Activity } from "@fedify/vocab";
|
|
7
3
|
|
|
4
|
+
//#region src/context.d.ts
|
|
5
|
+
declare function createContext<TContextData>(values: Partial<Context<TContextData>> & {
|
|
6
|
+
url?: URL;
|
|
7
|
+
data: TContextData;
|
|
8
|
+
federation: Federation<TContextData>;
|
|
9
|
+
}): Context<TContextData>;
|
|
10
|
+
/**
|
|
11
|
+
* Creates a RequestContext for testing purposes.
|
|
12
|
+
* Not exported - used internally only. Public API is in mock.ts
|
|
13
|
+
* @param args Partial RequestContext properties
|
|
14
|
+
* @returns A RequestContext instance
|
|
15
|
+
* @since 1.8.0
|
|
16
|
+
*/
|
|
17
|
+
declare function createRequestContext<TContextData>(args: Partial<RequestContext<TContextData>> & {
|
|
18
|
+
url: URL;
|
|
19
|
+
data: TContextData;
|
|
20
|
+
federation: Federation<TContextData>;
|
|
21
|
+
}): RequestContext<TContextData>;
|
|
22
|
+
/**
|
|
23
|
+
* Test-specific InboxContext type alias.
|
|
24
|
+
* This indirection helps avoid JSR type analyzer issues.
|
|
25
|
+
* @since 1.9.1
|
|
26
|
+
*/
|
|
27
|
+
type TestInboxContext<TContextData> = InboxContext<TContextData>;
|
|
28
|
+
/**
|
|
29
|
+
* Creates an InboxContext for testing purposes.
|
|
30
|
+
* Not exported - used internally only. Public API is in mock.ts
|
|
31
|
+
* @param args Partial InboxContext properties
|
|
32
|
+
* @returns An InboxContext instance
|
|
33
|
+
* @since 1.8.0
|
|
34
|
+
*/
|
|
35
|
+
declare function createInboxContext<TContextData>(args: Partial<InboxContext<TContextData>> & {
|
|
36
|
+
url?: URL;
|
|
37
|
+
data: TContextData;
|
|
38
|
+
recipient?: string | null;
|
|
39
|
+
federation: Federation<TContextData>;
|
|
40
|
+
}): TestInboxContext<TContextData>;
|
|
41
|
+
//#endregion
|
|
8
42
|
//#region src/mock.d.ts
|
|
9
|
-
|
|
10
43
|
/**
|
|
11
44
|
* Represents a sent activity with metadata about how it was sent.
|
|
12
45
|
* @since 1.8.0
|
|
@@ -22,17 +55,47 @@ interface SentActivity {
|
|
|
22
55
|
sentOrder: number;
|
|
23
56
|
}
|
|
24
57
|
/**
|
|
25
|
-
* A mock
|
|
26
|
-
*
|
|
27
|
-
*
|
|
58
|
+
* A mock Context interface for testing purposes.
|
|
59
|
+
* Extends the standard Context interface with additional testing utilities.
|
|
60
|
+
* @since 1.9.1
|
|
61
|
+
*/
|
|
62
|
+
interface TestContext<TContextData> extends Omit<Context<TContextData>, "clone">, Pick<RequestContext<TContextData>, "request" | "url" | "getActor" | "getObject" | "getSignedKey" | "getSignedKeyOwner" | "sendActivity" | "routeActivity"> {
|
|
63
|
+
clone(data: TContextData): TestContext<TContextData>;
|
|
64
|
+
getSentActivities(): Array<{
|
|
65
|
+
sender: any;
|
|
66
|
+
recipients: any;
|
|
67
|
+
activity: Activity;
|
|
68
|
+
}>;
|
|
69
|
+
reset(): void;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* A mock Federation interface for testing purposes.
|
|
73
|
+
* Extends the standard Federation interface with additional testing utilities.
|
|
74
|
+
* @since 1.9.1
|
|
75
|
+
*/
|
|
76
|
+
interface TestFederation<TContextData> extends Omit<Federation<TContextData>, "createContext"> {
|
|
77
|
+
sentActivities: SentActivity[];
|
|
78
|
+
queueStarted: boolean;
|
|
79
|
+
sentCounter: number;
|
|
80
|
+
receiveActivity(activity: Activity): Promise<void>;
|
|
81
|
+
reset(): void;
|
|
82
|
+
createContext(baseUrlOrRequest: URL | Request, contextData: TContextData): TestContext<TContextData>;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Creates a mock Federation instance for testing purposes.
|
|
86
|
+
*
|
|
87
|
+
* @template TContextData The type of context data to use
|
|
88
|
+
* @param options Optional configuration for the mock federation
|
|
89
|
+
* @returns A Federation instance that can be used for testing
|
|
90
|
+
* @since 1.9.1
|
|
28
91
|
*
|
|
29
92
|
* @example
|
|
30
93
|
* ```typescript
|
|
31
|
-
* import { Create } from "@fedify/
|
|
32
|
-
* import {
|
|
94
|
+
* import { Create } from "@fedify/vocab";
|
|
95
|
+
* import { createFederation } from "@fedify/testing";
|
|
33
96
|
*
|
|
34
97
|
* // Create a mock federation with contextData
|
|
35
|
-
* const federation =
|
|
98
|
+
* const federation = createFederation<{ userId: string }>({
|
|
36
99
|
* contextData: { userId: "test-user" }
|
|
37
100
|
* });
|
|
38
101
|
*
|
|
@@ -49,249 +112,15 @@ interface SentActivity {
|
|
|
49
112
|
* actor: new URL("https://example.com/users/alice")
|
|
50
113
|
* });
|
|
51
114
|
* await federation.receiveActivity(createActivity);
|
|
52
|
-
* ```
|
|
53
|
-
*
|
|
54
|
-
* @template TContextData The context data to pass to the {@link Context}.
|
|
55
|
-
* @since 1.8.0
|
|
56
|
-
*/
|
|
57
|
-
declare class MockFederation<TContextData> implements Federation<TContextData> {
|
|
58
|
-
private options;
|
|
59
|
-
sentActivities: SentActivity[];
|
|
60
|
-
queueStarted: boolean;
|
|
61
|
-
private activeQueues;
|
|
62
|
-
sentCounter: number;
|
|
63
|
-
private nodeInfoDispatcher?;
|
|
64
|
-
private webFingerDispatcher?;
|
|
65
|
-
private actorDispatchers;
|
|
66
|
-
actorPath?: string;
|
|
67
|
-
inboxPath?: string;
|
|
68
|
-
outboxPath?: string;
|
|
69
|
-
followingPath?: string;
|
|
70
|
-
followersPath?: string;
|
|
71
|
-
likedPath?: string;
|
|
72
|
-
featuredPath?: string;
|
|
73
|
-
featuredTagsPath?: string;
|
|
74
|
-
nodeInfoPath?: string;
|
|
75
|
-
sharedInboxPath?: string;
|
|
76
|
-
objectPaths: Map<string, string>;
|
|
77
|
-
private objectDispatchers;
|
|
78
|
-
private inboxDispatcher?;
|
|
79
|
-
private outboxDispatcher?;
|
|
80
|
-
private followingDispatcher?;
|
|
81
|
-
private followersDispatcher?;
|
|
82
|
-
private likedDispatcher?;
|
|
83
|
-
private featuredDispatcher?;
|
|
84
|
-
private featuredTagsDispatcher?;
|
|
85
|
-
private inboxListeners;
|
|
86
|
-
private contextData?;
|
|
87
|
-
private receivedActivities;
|
|
88
|
-
constructor(options?: {
|
|
89
|
-
contextData?: TContextData;
|
|
90
|
-
origin?: string;
|
|
91
|
-
tracerProvider?: TracerProvider;
|
|
92
|
-
});
|
|
93
|
-
setNodeInfoDispatcher(path: string, dispatcher: NodeInfoDispatcher<TContextData>): void;
|
|
94
|
-
setWebFingerLinksDispatcher(dispatcher: WebFingerLinksDispatcher<TContextData>): void;
|
|
95
|
-
setActorDispatcher(path: `${string}{identifier}${string}` | `${string}{handle}${string}`, dispatcher: ActorDispatcher<TContextData>): ActorCallbackSetters<TContextData>;
|
|
96
|
-
setObjectDispatcher<TObject extends Object$1, TParam extends string>(cls: (new (...args: any[]) => TObject) & {
|
|
97
|
-
typeId: URL;
|
|
98
|
-
}, path: string, dispatcher: ObjectDispatcher<TContextData, TObject, TParam>): ObjectCallbackSetters<TContextData, TObject, TParam>;
|
|
99
|
-
setInboxDispatcher(_path: `${string}{identifier}${string}` | `${string}{handle}${string}`, dispatcher: CollectionDispatcher<Activity, RequestContext<TContextData>, TContextData, void>): CollectionCallbackSetters<RequestContext<TContextData>, TContextData, void>;
|
|
100
|
-
setOutboxDispatcher(path: `${string}{identifier}${string}` | `${string}{handle}${string}`, dispatcher: CollectionDispatcher<Activity, RequestContext<TContextData>, TContextData, void>): CollectionCallbackSetters<RequestContext<TContextData>, TContextData, void>;
|
|
101
|
-
setFollowingDispatcher(path: `${string}{identifier}${string}` | `${string}{handle}${string}`, dispatcher: CollectionDispatcher<Actor | URL, RequestContext<TContextData>, TContextData, void>): CollectionCallbackSetters<RequestContext<TContextData>, TContextData, void>;
|
|
102
|
-
setFollowersDispatcher(path: `${string}{identifier}${string}` | `${string}{handle}${string}`, dispatcher: CollectionDispatcher<Recipient, Context<TContextData>, TContextData, URL>): CollectionCallbackSetters<Context<TContextData>, TContextData, URL>;
|
|
103
|
-
setLikedDispatcher(path: `${string}{identifier}${string}` | `${string}{handle}${string}`, dispatcher: CollectionDispatcher<Object$1 | URL, RequestContext<TContextData>, TContextData, void>): CollectionCallbackSetters<RequestContext<TContextData>, TContextData, void>;
|
|
104
|
-
setFeaturedDispatcher(path: `${string}{identifier}${string}` | `${string}{handle}${string}`, dispatcher: CollectionDispatcher<Object$1, RequestContext<TContextData>, TContextData, void>): CollectionCallbackSetters<RequestContext<TContextData>, TContextData, void>;
|
|
105
|
-
setFeaturedTagsDispatcher(path: `${string}{identifier}${string}` | `${string}{handle}${string}`, dispatcher: CollectionDispatcher<Hashtag, RequestContext<TContextData>, TContextData, void>): CollectionCallbackSetters<RequestContext<TContextData>, TContextData, void>;
|
|
106
|
-
setInboxListeners(inboxPath: `${string}{identifier}${string}` | `${string}{handle}${string}`, sharedInboxPath?: string): InboxListenerSetters<TContextData>;
|
|
107
|
-
startQueue(contextData: TContextData, options?: FederationStartQueueOptions): Promise<void>;
|
|
108
|
-
processQueuedTask(contextData: TContextData, _message: Message): Promise<void>;
|
|
109
|
-
createContext(baseUrl: URL, contextData: TContextData): Context<TContextData>;
|
|
110
|
-
createContext(request: Request, contextData: TContextData): RequestContext<TContextData>;
|
|
111
|
-
fetch(request: Request, options: FederationFetchOptions<TContextData>): Promise<Response>;
|
|
112
|
-
/**
|
|
113
|
-
* Simulates receiving an activity. This method is specific to the mock
|
|
114
|
-
* implementation and is used for testing purposes.
|
|
115
|
-
*
|
|
116
|
-
* @param activity The activity to receive.
|
|
117
|
-
* @returns A promise that resolves when the activity has been processed.
|
|
118
|
-
* @since 1.8.0
|
|
119
|
-
*/
|
|
120
|
-
receiveActivity(activity: Activity): Promise<void>;
|
|
121
|
-
/**
|
|
122
|
-
* Clears all sent activities from the mock federation.
|
|
123
|
-
* This method is specific to the mock implementation and is used for
|
|
124
|
-
* testing purposes.
|
|
125
|
-
*
|
|
126
|
-
* @since 1.8.0
|
|
127
|
-
*/
|
|
128
|
-
reset(): void;
|
|
129
|
-
setCollectionDispatcher<TObject extends Object$1, TParams extends Record<string, string>>(_name: string | symbol, _itemType: any, _path: any, _dispatcher: any): any;
|
|
130
|
-
setOrderedCollectionDispatcher<TObject extends Object$1, TParams extends Record<string, string>>(_name: string | symbol, _itemType: any, _path: any, _dispatcher: any): any;
|
|
131
|
-
}
|
|
132
|
-
/**
|
|
133
|
-
* A mock implementation of the {@link Context} interface for unit testing.
|
|
134
|
-
* This class provides a way to test Fedify applications without needing
|
|
135
|
-
* a real federation context.
|
|
136
|
-
*
|
|
137
|
-
* @example
|
|
138
|
-
* ```typescript
|
|
139
|
-
* import { Person, Create } from "@fedify/fedify/vocab";
|
|
140
|
-
* import { MockContext, MockFederation } from "@fedify/testing";
|
|
141
|
-
*
|
|
142
|
-
* // Create a mock context
|
|
143
|
-
* const mockFederation = new MockFederation<{ userId: string }>();
|
|
144
|
-
* const context = new MockContext({
|
|
145
|
-
* url: new URL("https://example.com"),
|
|
146
|
-
* data: { userId: "test-user" },
|
|
147
|
-
* federation: mockFederation
|
|
148
|
-
* });
|
|
149
|
-
*
|
|
150
|
-
* // Send an activity
|
|
151
|
-
* const recipient = new Person({ id: new URL("https://example.com/users/bob") });
|
|
152
|
-
* const activity = new Create({
|
|
153
|
-
* id: new URL("https://example.com/create/1"),
|
|
154
|
-
* actor: new URL("https://example.com/users/alice")
|
|
155
|
-
* });
|
|
156
|
-
* await context.sendActivity(
|
|
157
|
-
* { identifier: "alice" },
|
|
158
|
-
* recipient,
|
|
159
|
-
* activity
|
|
160
|
-
* );
|
|
161
115
|
*
|
|
162
116
|
* // Check sent activities
|
|
163
|
-
*
|
|
164
|
-
* console.log(sent[0].activity);
|
|
117
|
+
* console.log(federation.sentActivities);
|
|
165
118
|
* ```
|
|
166
|
-
*
|
|
167
|
-
* @template TContextData The context data to pass to the {@link Context}.
|
|
168
|
-
* @since 1.8.0
|
|
169
119
|
*/
|
|
170
|
-
declare
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
readonly data: TContextData;
|
|
176
|
-
readonly federation: Federation<TContextData>;
|
|
177
|
-
readonly documentLoader: DocumentLoader;
|
|
178
|
-
readonly contextLoader: DocumentLoader;
|
|
179
|
-
readonly tracerProvider: TracerProvider;
|
|
180
|
-
private sentActivities;
|
|
181
|
-
constructor(options: {
|
|
182
|
-
url?: URL;
|
|
183
|
-
data: TContextData;
|
|
184
|
-
federation: Federation<TContextData>;
|
|
185
|
-
documentLoader?: DocumentLoader;
|
|
186
|
-
contextLoader?: DocumentLoader;
|
|
187
|
-
tracerProvider?: TracerProvider;
|
|
188
|
-
});
|
|
189
|
-
clone(data: TContextData): Context<TContextData>;
|
|
190
|
-
getNodeInfoUri(): URL;
|
|
191
|
-
getActorUri(identifier: string): URL;
|
|
192
|
-
getObjectUri<TObject extends Object$1>(cls: (new (...args: any[]) => TObject) & {
|
|
193
|
-
typeId: URL;
|
|
194
|
-
}, values: Record<string, string>): URL;
|
|
195
|
-
getOutboxUri(identifier: string): URL;
|
|
196
|
-
getInboxUri(identifier: string): URL;
|
|
197
|
-
getInboxUri(): URL;
|
|
198
|
-
getFollowingUri(identifier: string): URL;
|
|
199
|
-
getFollowersUri(identifier: string): URL;
|
|
200
|
-
getLikedUri(identifier: string): URL;
|
|
201
|
-
getFeaturedUri(identifier: string): URL;
|
|
202
|
-
getFeaturedTagsUri(identifier: string): URL;
|
|
203
|
-
getCollectionUri<TParam extends Record<string, string>>(_name: string | symbol, values: TParam): URL;
|
|
204
|
-
parseUri(uri: URL): ParseUriResult | null;
|
|
205
|
-
getActorKeyPairs(_identifier: string): Promise<ActorKeyPair[]>;
|
|
206
|
-
getDocumentLoader(params: {
|
|
207
|
-
handle: string;
|
|
208
|
-
} | {
|
|
209
|
-
identifier: string;
|
|
210
|
-
}): Promise<DocumentLoader>;
|
|
211
|
-
getDocumentLoader(params: {
|
|
212
|
-
keyId: URL;
|
|
213
|
-
privateKey: CryptoKey;
|
|
214
|
-
}): DocumentLoader;
|
|
215
|
-
lookupObject(_uri: URL | string, _options?: LookupObjectOptions): Promise<Object$1 | null>;
|
|
216
|
-
traverseCollection<TItem, TContext extends Context<TContextData>>(_collection: Collection | URL | null, _options?: TraverseCollectionOptions): AsyncIterable<TItem>;
|
|
217
|
-
lookupNodeInfo(url: URL | string, options?: {
|
|
218
|
-
parse?: "strict" | "best-effort";
|
|
219
|
-
} & any): Promise<NodeInfo | undefined>;
|
|
220
|
-
lookupNodeInfo(url: URL | string, options?: {
|
|
221
|
-
parse: "none";
|
|
222
|
-
} & any): Promise<JsonValue | undefined>;
|
|
223
|
-
lookupWebFinger(_resource: URL | `acct:${string}@${string}` | string, _options?: any): Promise<ResourceDescriptor | null>;
|
|
224
|
-
sendActivity(sender: SenderKeyPair | SenderKeyPair[] | {
|
|
225
|
-
identifier: string;
|
|
226
|
-
} | {
|
|
227
|
-
username: string;
|
|
228
|
-
} | {
|
|
229
|
-
handle: string;
|
|
230
|
-
}, recipients: Recipient | Recipient[], activity: Activity, options?: SendActivityOptions): Promise<void>;
|
|
231
|
-
sendActivity(sender: {
|
|
232
|
-
identifier: string;
|
|
233
|
-
} | {
|
|
234
|
-
username: string;
|
|
235
|
-
} | {
|
|
236
|
-
handle: string;
|
|
237
|
-
}, recipients: "followers", activity: Activity, options?: SendActivityOptionsForCollection): Promise<void>;
|
|
238
|
-
sendActivity(sender: SenderKeyPair | SenderKeyPair[] | {
|
|
239
|
-
identifier: string;
|
|
240
|
-
} | {
|
|
241
|
-
username: string;
|
|
242
|
-
} | {
|
|
243
|
-
handle: string;
|
|
244
|
-
}, recipients: Recipient | Recipient[], activity: Activity, options?: SendActivityOptions): Promise<void>;
|
|
245
|
-
sendActivity(sender: {
|
|
246
|
-
identifier: string;
|
|
247
|
-
} | {
|
|
248
|
-
username: string;
|
|
249
|
-
} | {
|
|
250
|
-
handle: string;
|
|
251
|
-
}, recipients: "followers", activity: Activity, options?: SendActivityOptionsForCollection): Promise<void>;
|
|
252
|
-
routeActivity(_recipient: string | null, _activity: Activity, _options?: RouteActivityOptions): Promise<boolean>;
|
|
253
|
-
/**
|
|
254
|
-
* Gets all activities that have been sent through this mock context.
|
|
255
|
-
* This method is specific to the mock implementation and is used for
|
|
256
|
-
* testing purposes.
|
|
257
|
-
*
|
|
258
|
-
* @returns An array of sent activity records.
|
|
259
|
-
*/
|
|
260
|
-
getSentActivities(): Array<{
|
|
261
|
-
sender: SenderKeyPair | SenderKeyPair[] | {
|
|
262
|
-
identifier: string;
|
|
263
|
-
} | {
|
|
264
|
-
username: string;
|
|
265
|
-
} | {
|
|
266
|
-
handle: string;
|
|
267
|
-
};
|
|
268
|
-
recipients: Recipient | Recipient[] | "followers";
|
|
269
|
-
activity: Activity;
|
|
270
|
-
}>;
|
|
271
|
-
/**
|
|
272
|
-
* Clears all sent activities from the mock context.
|
|
273
|
-
* This method is specific to the mock implementation and is used for
|
|
274
|
-
* testing purposes.
|
|
275
|
-
*/
|
|
276
|
-
reset(): void;
|
|
277
|
-
}
|
|
278
|
-
//#endregion
|
|
279
|
-
//#region src/context.d.ts
|
|
280
|
-
declare function createContext<TContextData>(values: Partial<Context<TContextData>> & {
|
|
281
|
-
url?: URL;
|
|
282
|
-
data: TContextData;
|
|
283
|
-
federation: Federation<TContextData>;
|
|
284
|
-
}): Context<TContextData>;
|
|
285
|
-
declare function createRequestContext<TContextData>(args: Partial<RequestContext<TContextData>> & {
|
|
286
|
-
url: URL;
|
|
287
|
-
data: TContextData;
|
|
288
|
-
federation: Federation<TContextData>;
|
|
289
|
-
}): RequestContext<TContextData>;
|
|
290
|
-
declare function createInboxContext<TContextData>(args: Partial<InboxContext<TContextData>> & {
|
|
291
|
-
url?: URL;
|
|
292
|
-
data: TContextData;
|
|
293
|
-
recipient?: string | null;
|
|
294
|
-
federation: Federation<TContextData>;
|
|
295
|
-
}): InboxContext<TContextData>;
|
|
120
|
+
declare function createFederation<TContextData>(options?: {
|
|
121
|
+
contextData?: TContextData;
|
|
122
|
+
origin?: string;
|
|
123
|
+
tracerProvider?: any;
|
|
124
|
+
}): TestFederation<TContextData>;
|
|
296
125
|
//#endregion
|
|
297
|
-
export {
|
|
126
|
+
export { createContext, createFederation, createInboxContext, createRequestContext };
|
package/dist/mod.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { trace } from "@opentelemetry/api";
|
|
2
1
|
import { RouterError } from "@fedify/fedify/federation";
|
|
3
|
-
import { lookupObject, traverseCollection } from "@fedify/
|
|
4
|
-
import { lookupWebFinger } from "@fedify/fedify/webfinger";
|
|
2
|
+
import { lookupObject, traverseCollection } from "@fedify/vocab";
|
|
5
3
|
|
|
6
4
|
//#region src/docloader.ts
|
|
7
5
|
const mockDocumentLoader = async (url) => ({
|
|
@@ -12,8 +10,12 @@ const mockDocumentLoader = async (url) => ({
|
|
|
12
10
|
|
|
13
11
|
//#endregion
|
|
14
12
|
//#region src/context.ts
|
|
13
|
+
const noopTracerProvider$1 = { getTracer: () => ({
|
|
14
|
+
startActiveSpan: () => void 0,
|
|
15
|
+
startSpan: () => void 0
|
|
16
|
+
}) };
|
|
15
17
|
function createContext(values) {
|
|
16
|
-
const { federation, url = new URL("http://example.com/"), canonicalOrigin, data, documentLoader, contextLoader, tracerProvider, clone, getNodeInfoUri, getActorUri, getObjectUri, getCollectionUri, getOutboxUri, getInboxUri, getFollowingUri, getFollowersUri, getLikedUri, getFeaturedUri, getFeaturedTagsUri, parseUri, getActorKeyPairs, getDocumentLoader, lookupObject: lookupObject$1, traverseCollection: traverseCollection$1, lookupNodeInfo, lookupWebFinger
|
|
18
|
+
const { federation, url = new URL("http://example.com/"), canonicalOrigin, data, documentLoader, contextLoader, tracerProvider, clone, getNodeInfoUri, getActorUri, getObjectUri, getCollectionUri, getOutboxUri, getInboxUri, getFollowingUri, getFollowersUri, getLikedUri, getFeaturedUri, getFeaturedTagsUri, parseUri, getActorKeyPairs, getDocumentLoader, lookupObject: lookupObject$1, traverseCollection: traverseCollection$1, lookupNodeInfo, lookupWebFinger, sendActivity, routeActivity } = values;
|
|
17
19
|
function throwRouteError() {
|
|
18
20
|
throw new RouterError("Not implemented");
|
|
19
21
|
}
|
|
@@ -26,7 +28,7 @@ function createContext(values) {
|
|
|
26
28
|
hostname: url.hostname,
|
|
27
29
|
documentLoader: documentLoader ?? mockDocumentLoader,
|
|
28
30
|
contextLoader: contextLoader ?? mockDocumentLoader,
|
|
29
|
-
tracerProvider: tracerProvider ??
|
|
31
|
+
tracerProvider: tracerProvider ?? noopTracerProvider$1,
|
|
30
32
|
clone: clone ?? ((data$1) => createContext({
|
|
31
33
|
...values,
|
|
32
34
|
data: data$1
|
|
@@ -64,8 +66,8 @@ function createContext(values) {
|
|
|
64
66
|
lookupNodeInfo: lookupNodeInfo ?? ((_params) => {
|
|
65
67
|
throw new Error("Not implemented");
|
|
66
68
|
}),
|
|
67
|
-
lookupWebFinger: lookupWebFinger
|
|
68
|
-
return
|
|
69
|
+
lookupWebFinger: lookupWebFinger ?? ((_resource, _options = {}) => {
|
|
70
|
+
return Promise.resolve(null);
|
|
69
71
|
}),
|
|
70
72
|
sendActivity: sendActivity ?? ((_params) => {
|
|
71
73
|
throw new Error("Not implemented");
|
|
@@ -75,6 +77,13 @@ function createContext(values) {
|
|
|
75
77
|
})
|
|
76
78
|
};
|
|
77
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Creates a RequestContext for testing purposes.
|
|
82
|
+
* Not exported - used internally only. Public API is in mock.ts
|
|
83
|
+
* @param args Partial RequestContext properties
|
|
84
|
+
* @returns A RequestContext instance
|
|
85
|
+
* @since 1.8.0
|
|
86
|
+
*/
|
|
78
87
|
function createRequestContext(args) {
|
|
79
88
|
return {
|
|
80
89
|
...createContext(args),
|
|
@@ -93,6 +102,13 @@ function createRequestContext(args) {
|
|
|
93
102
|
})
|
|
94
103
|
};
|
|
95
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* Creates an InboxContext for testing purposes.
|
|
107
|
+
* Not exported - used internally only. Public API is in mock.ts
|
|
108
|
+
* @param args Partial InboxContext properties
|
|
109
|
+
* @returns An InboxContext instance
|
|
110
|
+
* @since 1.8.0
|
|
111
|
+
*/
|
|
96
112
|
function createInboxContext(args) {
|
|
97
113
|
return {
|
|
98
114
|
...createContext(args),
|
|
@@ -109,6 +125,10 @@ function createInboxContext(args) {
|
|
|
109
125
|
|
|
110
126
|
//#endregion
|
|
111
127
|
//#region src/mock.ts
|
|
128
|
+
const noopTracerProvider = { getTracer: () => ({
|
|
129
|
+
startActiveSpan: () => void 0,
|
|
130
|
+
startSpan: () => void 0
|
|
131
|
+
}) };
|
|
112
132
|
/**
|
|
113
133
|
* Helper function to expand URI templates with values.
|
|
114
134
|
* Supports simple placeholders like {identifier}, {handle}, etc.
|
|
@@ -128,18 +148,18 @@ function expandUriTemplate(template, values) {
|
|
|
128
148
|
*
|
|
129
149
|
* @example
|
|
130
150
|
* ```typescript
|
|
131
|
-
* import { Create } from "@fedify/
|
|
132
|
-
* import {
|
|
151
|
+
* import { Create } from "@fedify/vocab";
|
|
152
|
+
* import { createFederation } from "@fedify/testing";
|
|
133
153
|
*
|
|
134
154
|
* // Create a mock federation with contextData
|
|
135
|
-
* const federation =
|
|
155
|
+
* const federation = createFederation<{ userId: string }>({
|
|
136
156
|
* contextData: { userId: "test-user" }
|
|
137
157
|
* });
|
|
138
158
|
*
|
|
139
159
|
* // Set up inbox listeners
|
|
140
160
|
* federation
|
|
141
161
|
* .setInboxListeners("/users/{identifier}/inbox")
|
|
142
|
-
* .on(Create, async (ctx, activity) => {
|
|
162
|
+
* .on(Create, async (ctx: any, activity: any) => {
|
|
143
163
|
* console.log("Received:", activity);
|
|
144
164
|
* });
|
|
145
165
|
*
|
|
@@ -295,6 +315,9 @@ var MockFederation = class {
|
|
|
295
315
|
},
|
|
296
316
|
setSharedKeyDispatcher() {
|
|
297
317
|
return this;
|
|
318
|
+
},
|
|
319
|
+
withIdempotency() {
|
|
320
|
+
return this;
|
|
298
321
|
}
|
|
299
322
|
};
|
|
300
323
|
}
|
|
@@ -313,22 +336,9 @@ var MockFederation = class {
|
|
|
313
336
|
}
|
|
314
337
|
createContext(baseUrlOrRequest, contextData) {
|
|
315
338
|
const mockFederation = this;
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
data: contextData,
|
|
320
|
-
federation: mockFederation,
|
|
321
|
-
sendActivity: async (sender, recipients, activity, options) => {
|
|
322
|
-
const tempContext = new MockContext({
|
|
323
|
-
url: new URL(baseUrlOrRequest.url),
|
|
324
|
-
data: contextData,
|
|
325
|
-
federation: mockFederation
|
|
326
|
-
});
|
|
327
|
-
await tempContext.sendActivity(sender, recipients, activity, options);
|
|
328
|
-
}
|
|
329
|
-
});
|
|
330
|
-
else return new MockContext({
|
|
331
|
-
url: baseUrlOrRequest,
|
|
339
|
+
const url = baseUrlOrRequest instanceof Request ? new URL(baseUrlOrRequest.url) : baseUrlOrRequest;
|
|
340
|
+
return new MockContext({
|
|
341
|
+
url,
|
|
332
342
|
data: contextData,
|
|
333
343
|
federation: mockFederation
|
|
334
344
|
});
|
|
@@ -386,22 +396,66 @@ var MockFederation = class {
|
|
|
386
396
|
}
|
|
387
397
|
};
|
|
388
398
|
/**
|
|
399
|
+
* Creates a mock Federation instance for testing purposes.
|
|
400
|
+
*
|
|
401
|
+
* @template TContextData The type of context data to use
|
|
402
|
+
* @param options Optional configuration for the mock federation
|
|
403
|
+
* @returns A Federation instance that can be used for testing
|
|
404
|
+
* @since 1.9.1
|
|
405
|
+
*
|
|
406
|
+
* @example
|
|
407
|
+
* ```typescript
|
|
408
|
+
* import { Create } from "@fedify/vocab";
|
|
409
|
+
* import { createFederation } from "@fedify/testing";
|
|
410
|
+
*
|
|
411
|
+
* // Create a mock federation with contextData
|
|
412
|
+
* const federation = createFederation<{ userId: string }>({
|
|
413
|
+
* contextData: { userId: "test-user" }
|
|
414
|
+
* });
|
|
415
|
+
*
|
|
416
|
+
* // Set up inbox listeners
|
|
417
|
+
* federation
|
|
418
|
+
* .setInboxListeners("/users/{identifier}/inbox")
|
|
419
|
+
* .on(Create, async (ctx, activity) => {
|
|
420
|
+
* console.log("Received:", activity);
|
|
421
|
+
* });
|
|
422
|
+
*
|
|
423
|
+
* // Simulate receiving an activity
|
|
424
|
+
* const createActivity = new Create({
|
|
425
|
+
* id: new URL("https://example.com/create/1"),
|
|
426
|
+
* actor: new URL("https://example.com/users/alice")
|
|
427
|
+
* });
|
|
428
|
+
* await federation.receiveActivity(createActivity);
|
|
429
|
+
*
|
|
430
|
+
* // Check sent activities
|
|
431
|
+
* console.log(federation.sentActivities);
|
|
432
|
+
* ```
|
|
433
|
+
*/
|
|
434
|
+
function createFederation(options = {}) {
|
|
435
|
+
return new MockFederation(options);
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
389
438
|
* A mock implementation of the {@link Context} interface for unit testing.
|
|
390
439
|
* This class provides a way to test Fedify applications without needing
|
|
391
440
|
* a real federation context.
|
|
392
441
|
*
|
|
442
|
+
* Note: This class is not exported from the public API to avoid JSR type
|
|
443
|
+
* analyzer issues. The MockContext class has complex type dependencies that
|
|
444
|
+
* can cause JSR's type analyzer to hang during processing (issue #468).
|
|
445
|
+
* Use {@link MockFederation.createContext}, {@link createContext},
|
|
446
|
+
* {@link createRequestContext}, or {@link createInboxContext} instead.
|
|
447
|
+
*
|
|
393
448
|
* @example
|
|
394
449
|
* ```typescript
|
|
395
|
-
* import { Person, Create } from "@fedify/
|
|
396
|
-
* import {
|
|
450
|
+
* import { Person, Create } from "@fedify/vocab";
|
|
451
|
+
* import { createFederation } from "@fedify/testing";
|
|
397
452
|
*
|
|
398
|
-
* // Create a mock context
|
|
399
|
-
* const
|
|
400
|
-
* const context =
|
|
401
|
-
*
|
|
402
|
-
*
|
|
403
|
-
*
|
|
404
|
-
* });
|
|
453
|
+
* // Create a mock federation and context
|
|
454
|
+
* const federation = createFederation<{ userId: string }>();
|
|
455
|
+
* const context = federation.createContext(
|
|
456
|
+
* new URL("https://example.com"),
|
|
457
|
+
* { userId: "test-user" }
|
|
458
|
+
* );
|
|
405
459
|
*
|
|
406
460
|
* // Send an activity
|
|
407
461
|
* const recipient = new Person({ id: new URL("https://example.com/users/bob") });
|
|
@@ -415,8 +469,8 @@ var MockFederation = class {
|
|
|
415
469
|
* activity
|
|
416
470
|
* );
|
|
417
471
|
*
|
|
418
|
-
* // Check sent activities
|
|
419
|
-
* const sent =
|
|
472
|
+
* // Check sent activities from the federation
|
|
473
|
+
* const sent = federation.sentActivities;
|
|
420
474
|
* console.log(sent[0].activity);
|
|
421
475
|
* ```
|
|
422
476
|
*
|
|
@@ -433,6 +487,8 @@ var MockContext = class MockContext {
|
|
|
433
487
|
documentLoader;
|
|
434
488
|
contextLoader;
|
|
435
489
|
tracerProvider;
|
|
490
|
+
request;
|
|
491
|
+
url;
|
|
436
492
|
sentActivities = [];
|
|
437
493
|
constructor(options) {
|
|
438
494
|
const url = options.url ?? new URL("https://example.com");
|
|
@@ -440,6 +496,8 @@ var MockContext = class MockContext {
|
|
|
440
496
|
this.canonicalOrigin = url.origin;
|
|
441
497
|
this.host = url.host;
|
|
442
498
|
this.hostname = url.hostname;
|
|
499
|
+
this.url = url;
|
|
500
|
+
this.request = new Request(url);
|
|
443
501
|
this.data = options.data;
|
|
444
502
|
this.federation = options.federation;
|
|
445
503
|
this.documentLoader = options.documentLoader ?? (async (url$1) => ({
|
|
@@ -448,11 +506,23 @@ var MockContext = class MockContext {
|
|
|
448
506
|
documentUrl: url$1
|
|
449
507
|
}));
|
|
450
508
|
this.contextLoader = options.contextLoader ?? this.documentLoader;
|
|
451
|
-
this.tracerProvider = options.tracerProvider ??
|
|
509
|
+
this.tracerProvider = options.tracerProvider ?? noopTracerProvider;
|
|
510
|
+
}
|
|
511
|
+
getActor(_handle) {
|
|
512
|
+
return Promise.resolve(null);
|
|
513
|
+
}
|
|
514
|
+
getObject(_cls, _values) {
|
|
515
|
+
return Promise.resolve(null);
|
|
516
|
+
}
|
|
517
|
+
getSignedKey() {
|
|
518
|
+
return Promise.resolve(null);
|
|
519
|
+
}
|
|
520
|
+
getSignedKeyOwner() {
|
|
521
|
+
return Promise.resolve(null);
|
|
452
522
|
}
|
|
453
523
|
clone(data) {
|
|
454
524
|
return new MockContext({
|
|
455
|
-
url:
|
|
525
|
+
url: this.url,
|
|
456
526
|
data,
|
|
457
527
|
federation: this.federation,
|
|
458
528
|
documentLoader: this.documentLoader,
|
|
@@ -634,4 +704,4 @@ var MockContext = class MockContext {
|
|
|
634
704
|
};
|
|
635
705
|
|
|
636
706
|
//#endregion
|
|
637
|
-
export {
|
|
707
|
+
export { createContext, createFederation, createInboxContext, createRequestContext };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fedify/testing",
|
|
3
|
-
"version": "2.0.0-dev.
|
|
3
|
+
"version": "2.0.0-dev.166+15dea3c0",
|
|
4
4
|
"description": "Testing utilities for Fedify applications",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"fedify",
|
|
@@ -50,17 +50,14 @@
|
|
|
50
50
|
"package.json"
|
|
51
51
|
],
|
|
52
52
|
"peerDependencies": {
|
|
53
|
-
"@fedify/fedify": "^2.0.0-dev.
|
|
54
|
-
},
|
|
55
|
-
"dependencies": {
|
|
56
|
-
"@opentelemetry/api": "^1.9.0"
|
|
53
|
+
"@fedify/fedify": "^2.0.0-dev.166+15dea3c0"
|
|
57
54
|
},
|
|
58
55
|
"devDependencies": {
|
|
59
56
|
"@js-temporal/polyfill": "^0.5.1",
|
|
60
57
|
"@std/assert": "npm:@jsr/std__assert@^1.0.13",
|
|
61
58
|
"@std/async": "npm:@jsr/std__async@^1.0.13",
|
|
62
59
|
"tsdown": "^0.12.9",
|
|
63
|
-
"typescript": "^5.9.
|
|
60
|
+
"typescript": "^5.9.3"
|
|
64
61
|
},
|
|
65
62
|
"scripts": {
|
|
66
63
|
"build": "tsdown",
|