@ddd-ts-kit/testing 0.8.0 → 0.10.0
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/README.md +19 -0
- package/dist/contracts/event-store/companion-stores-suite.d.ts +12 -0
- package/dist/contracts/event-store/companion-stores-suite.d.ts.map +1 -0
- package/dist/contracts/event-store/companion-stores-suite.js +60 -0
- package/dist/contracts/event-store/companion-stores-suite.js.map +1 -0
- package/dist/contracts/event-store/consignment-registered.d.ts +8 -0
- package/dist/contracts/event-store/consignment-registered.d.ts.map +1 -0
- package/dist/contracts/event-store/consignment-registered.js +10 -0
- package/dist/contracts/event-store/consignment-registered.js.map +1 -0
- package/dist/contracts/event-store/consignment-weighed.d.ts +9 -0
- package/dist/contracts/event-store/consignment-weighed.d.ts.map +1 -0
- package/dist/contracts/event-store/consignment-weighed.js +12 -0
- package/dist/contracts/event-store/consignment-weighed.js.map +1 -0
- package/dist/contracts/event-store/consignment.d.ts +16 -0
- package/dist/contracts/event-store/consignment.d.ts.map +1 -0
- package/dist/contracts/event-store/consignment.js +36 -0
- package/dist/contracts/event-store/consignment.js.map +1 -0
- package/dist/contracts/event-store/consignments.d.ts +10 -0
- package/dist/contracts/event-store/consignments.d.ts.map +1 -0
- package/dist/contracts/event-store/consignments.js +34 -0
- package/dist/contracts/event-store/consignments.js.map +1 -0
- package/dist/contracts/event-store/event-of.d.ts +4 -0
- package/dist/contracts/event-store/event-of.d.ts.map +1 -0
- package/dist/contracts/event-store/event-of.js +13 -0
- package/dist/contracts/event-store/event-of.js.map +1 -0
- package/dist/contracts/event-store/event-store-under-contract.d.ts +11 -0
- package/dist/contracts/event-store/event-store-under-contract.d.ts.map +1 -0
- package/dist/contracts/event-store/event-store-under-contract.js +2 -0
- package/dist/contracts/event-store/event-store-under-contract.js.map +1 -0
- package/dist/contracts/event-store/one-transaction-suite.d.ts +18 -0
- package/dist/contracts/event-store/one-transaction-suite.d.ts.map +1 -0
- package/dist/contracts/event-store/one-transaction-suite.js +92 -0
- package/dist/contracts/event-store/one-transaction-suite.js.map +1 -0
- package/dist/contracts/event-store/store-suite.d.ts +10 -0
- package/dist/contracts/event-store/store-suite.d.ts.map +1 -0
- package/dist/contracts/event-store/store-suite.js +44 -0
- package/dist/contracts/event-store/store-suite.js.map +1 -0
- package/dist/contracts/event-store/stream-suite.d.ts +11 -0
- package/dist/contracts/event-store/stream-suite.d.ts.map +1 -0
- package/dist/contracts/event-store/stream-suite.js +91 -0
- package/dist/contracts/event-store/stream-suite.js.map +1 -0
- package/dist/contracts/event-store-contract.d.ts +20 -0
- package/dist/contracts/event-store-contract.d.ts.map +1 -0
- package/dist/contracts/event-store-contract.js +21 -0
- package/dist/contracts/event-store-contract.js.map +1 -0
- package/dist/contracts/event-store-unit-of-work-contract.d.ts +15 -0
- package/dist/contracts/event-store-unit-of-work-contract.d.ts.map +1 -0
- package/dist/contracts/event-store-unit-of-work-contract.js +10 -0
- package/dist/contracts/event-store-unit-of-work-contract.js.map +1 -0
- package/dist/contracts/file-storage/arrangement-suite.d.ts +9 -0
- package/dist/contracts/file-storage/arrangement-suite.d.ts.map +1 -0
- package/dist/contracts/file-storage/arrangement-suite.js +51 -0
- package/dist/contracts/file-storage/arrangement-suite.js.map +1 -0
- package/dist/contracts/file-storage/checksum-of.d.ts +3 -0
- package/dist/contracts/file-storage/checksum-of.d.ts.map +1 -0
- package/dist/contracts/file-storage/checksum-of.js +10 -0
- package/dist/contracts/file-storage/checksum-of.js.map +1 -0
- package/dist/contracts/file-storage/chunks-of.d.ts +3 -0
- package/dist/contracts/file-storage/chunks-of.d.ts.map +1 -0
- package/dist/contracts/file-storage/chunks-of.js +5 -0
- package/dist/contracts/file-storage/chunks-of.js.map +1 -0
- package/dist/contracts/file-storage/content-suite.d.ts +12 -0
- package/dist/contracts/file-storage/content-suite.d.ts.map +1 -0
- package/dist/contracts/file-storage/content-suite.js +110 -0
- package/dist/contracts/file-storage/content-suite.js.map +1 -0
- package/dist/contracts/file-storage/contents.d.ts +7 -0
- package/dist/contracts/file-storage/contents.d.ts.map +1 -0
- package/dist/contracts/file-storage/contents.js +7 -0
- package/dist/contracts/file-storage/contents.js.map +1 -0
- package/dist/contracts/file-storage/file-storage-contract-options.d.ts +17 -0
- package/dist/contracts/file-storage/file-storage-contract-options.d.ts.map +1 -0
- package/dist/contracts/file-storage/file-storage-contract-options.js +2 -0
- package/dist/contracts/file-storage/file-storage-contract-options.js.map +1 -0
- package/dist/contracts/file-storage/file-storage-suite.d.ts +14 -0
- package/dist/contracts/file-storage/file-storage-suite.d.ts.map +1 -0
- package/dist/contracts/file-storage/file-storage-suite.js +30 -0
- package/dist/contracts/file-storage/file-storage-suite.js.map +1 -0
- package/dist/contracts/file-storage/follow-served.d.ts +9 -0
- package/dist/contracts/file-storage/follow-served.d.ts.map +1 -0
- package/dist/contracts/file-storage/follow-served.js +28 -0
- package/dist/contracts/file-storage/follow-served.js.map +1 -0
- package/dist/contracts/file-storage/follow-with-fetch.d.ts +5 -0
- package/dist/contracts/file-storage/follow-with-fetch.d.ts.map +1 -0
- package/dist/contracts/file-storage/follow-with-fetch.js +14 -0
- package/dist/contracts/file-storage/follow-with-fetch.js.map +1 -0
- package/dist/contracts/file-storage/followed-response.d.ts +7 -0
- package/dist/contracts/file-storage/followed-response.d.ts.map +1 -0
- package/dist/contracts/file-storage/followed-response.js +2 -0
- package/dist/contracts/file-storage/followed-response.js.map +1 -0
- package/dist/contracts/file-storage/large-content.d.ts +3 -0
- package/dist/contracts/file-storage/large-content.d.ts.map +1 -0
- package/dist/contracts/file-storage/large-content.js +8 -0
- package/dist/contracts/file-storage/large-content.js.map +1 -0
- package/dist/contracts/file-storage/read-all.d.ts +3 -0
- package/dist/contracts/file-storage/read-all.d.ts.map +1 -0
- package/dist/contracts/file-storage/read-all.js +9 -0
- package/dist/contracts/file-storage/read-all.js.map +1 -0
- package/dist/contracts/file-storage/signed-links-suite.d.ts +11 -0
- package/dist/contracts/file-storage/signed-links-suite.d.ts.map +1 -0
- package/dist/contracts/file-storage/signed-links-suite.js +93 -0
- package/dist/contracts/file-storage/signed-links-suite.js.map +1 -0
- package/dist/contracts/file-storage/signed-request.d.ts +8 -0
- package/dist/contracts/file-storage/signed-request.d.ts.map +1 -0
- package/dist/contracts/file-storage/signed-request.js +2 -0
- package/dist/contracts/file-storage/signed-request.js.map +1 -0
- package/dist/contracts/file-storage/tampered.d.ts +3 -0
- package/dist/contracts/file-storage/tampered.d.ts.map +1 -0
- package/dist/contracts/file-storage/tampered.js +5 -0
- package/dist/contracts/file-storage/tampered.js.map +1 -0
- package/dist/contracts/file-storage-contract.d.ts +11 -0
- package/dist/contracts/file-storage-contract.d.ts.map +1 -0
- package/dist/contracts/file-storage-contract.js +16 -0
- package/dist/contracts/file-storage-contract.js.map +1 -0
- package/dist/contracts.d.ts +9 -0
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +5 -0
- package/dist/contracts.js.map +1 -1
- package/dist/event-sourcing/expect-snapshot-equivalence.d.ts +14 -0
- package/dist/event-sourcing/expect-snapshot-equivalence.d.ts.map +1 -0
- package/dist/event-sourcing/expect-snapshot-equivalence.js +48 -0
- package/dist/event-sourcing/expect-snapshot-equivalence.js.map +1 -0
- package/dist/event-sourcing/given-events.d.ts +12 -0
- package/dist/event-sourcing/given-events.d.ts.map +1 -0
- package/dist/event-sourcing/given-events.js +16 -0
- package/dist/event-sourcing/given-events.js.map +1 -0
- package/dist/event-sourcing/snapshot-equivalence.d.ts +12 -0
- package/dist/event-sourcing/snapshot-equivalence.d.ts.map +1 -0
- package/dist/event-sourcing/snapshot-equivalence.js +2 -0
- package/dist/event-sourcing/snapshot-equivalence.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Readable } from 'node:stream';
|
|
2
|
+
import { contentDisposition } from '@ddd-ts-kit/kernel';
|
|
3
|
+
import { readAll } from './read-all.js';
|
|
4
|
+
/**
|
|
5
|
+
* Follows a link of a storage the application serves, without a server: the token is the `token`
|
|
6
|
+
* parameter of the query, answered the way `signedFileRoutes` of `@ddd-ts-kit/http` answers it.
|
|
7
|
+
*/
|
|
8
|
+
export function followServed(storage) {
|
|
9
|
+
return async (request) => {
|
|
10
|
+
const token = new URL(request.url).searchParams.get('token') ?? '';
|
|
11
|
+
if (request.method === 'GET') {
|
|
12
|
+
const download = await storage.openSigned(token);
|
|
13
|
+
return download === undefined
|
|
14
|
+
? refused()
|
|
15
|
+
: { status: 200, headers: dispositionOf(download.fileName), body: await readAll(download.stream) };
|
|
16
|
+
}
|
|
17
|
+
const body = Readable.from([Buffer.from(request.body ?? new Uint8Array())]);
|
|
18
|
+
const stored = await storage.acceptSigned(token, body, request.headers?.['content-type'] ?? '');
|
|
19
|
+
return stored === undefined ? refused() : { status: 200, headers: {}, body: new Uint8Array() };
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function refused() {
|
|
23
|
+
return { status: 403, headers: {}, body: new Uint8Array() };
|
|
24
|
+
}
|
|
25
|
+
function dispositionOf(fileName) {
|
|
26
|
+
return { 'content-disposition': contentDisposition(fileName) };
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=follow-served.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"follow-served.js","sourceRoot":"","sources":["../../../src/contracts/file-storage/follow-served.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,kBAAkB,EAA0B,MAAM,oBAAoB,CAAC;AAEhF,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAGxC;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,OAA0B;IACrD,OAAO,KAAK,EAAE,OAAO,EAAE,EAAE;QACvB,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QAEnE,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;YAC7B,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;YAEjD,OAAO,QAAQ,KAAK,SAAS;gBAC3B,CAAC,CAAC,OAAO,EAAE;gBACX,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,aAAa,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACvG,CAAC;QAED,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,IAAI,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC;QAC5E,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC;QAEhG,OAAO,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,UAAU,EAAE,EAAE,CAAC;IACjG,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,OAAO;IACd,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,UAAU,EAAE,EAAE,CAAC;AAC9D,CAAC;AAED,SAAS,aAAa,CAAC,QAA4B;IACjD,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CAAC;AACjE,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { FollowedResponse } from './followed-response.js';
|
|
2
|
+
import type { SignedRequest } from './signed-request.js';
|
|
3
|
+
/** Follows a link over the network: for a storage that answers its own links, an object store. */
|
|
4
|
+
export declare function followWithFetch(request: SignedRequest): Promise<FollowedResponse>;
|
|
5
|
+
//# sourceMappingURL=follow-with-fetch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"follow-with-fetch.d.ts","sourceRoot":"","sources":["../../../src/contracts/file-storage/follow-with-fetch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,kGAAkG;AAClG,wBAAsB,eAAe,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAYvF"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Follows a link over the network: for a storage that answers its own links, an object store. */
|
|
2
|
+
export async function followWithFetch(request) {
|
|
3
|
+
const response = await fetch(request.url, {
|
|
4
|
+
method: request.method,
|
|
5
|
+
headers: { ...request.headers },
|
|
6
|
+
...(request.body === undefined ? {} : { body: request.body }),
|
|
7
|
+
});
|
|
8
|
+
return {
|
|
9
|
+
status: response.status,
|
|
10
|
+
headers: Object.fromEntries(response.headers.entries()),
|
|
11
|
+
body: new Uint8Array(await response.arrayBuffer()),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=follow-with-fetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"follow-with-fetch.js","sourceRoot":"","sources":["../../../src/contracts/file-storage/follow-with-fetch.ts"],"names":[],"mappings":"AAGA,kGAAkG;AAClG,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAAsB;IAC1D,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;QACxC,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,OAAO,EAAE,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE;QAC/B,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC;KAC9D,CAAC,CAAC;IAEH,OAAO;QACL,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QACvD,IAAI,EAAE,IAAI,UAAU,CAAC,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC;KACnD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"followed-response.d.ts","sourceRoot":"","sources":["../../../src/contracts/file-storage/followed-response.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACnD,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;CAC3B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"followed-response.js","sourceRoot":"","sources":["../../../src/contracts/file-storage/followed-response.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"large-content.d.ts","sourceRoot":"","sources":["../../../src/contracts/file-storage/large-content.ts"],"names":[],"mappings":"AAEA,sFAAsF;AACtF,wBAAuB,YAAY,IAAI,aAAa,CAAC,UAAU,CAAC,CAI/D"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { LARGE_CHUNK, LARGE_SIZE } from './contents.js';
|
|
2
|
+
/** Six mebibytes in chunks of 64 KiB, each filled with its rank: never held whole. */
|
|
3
|
+
export async function* largeContent() {
|
|
4
|
+
for (let offset = 0; offset < LARGE_SIZE; offset += LARGE_CHUNK) {
|
|
5
|
+
yield new Uint8Array(LARGE_CHUNK).fill(offset / LARGE_CHUNK);
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=large-content.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"large-content.js","sourceRoot":"","sources":["../../../src/contracts/file-storage/large-content.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAExD,sFAAsF;AACtF,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,YAAY;IACjC,KAAK,IAAI,MAAM,GAAG,CAAC,EAAE,MAAM,GAAG,UAAU,EAAE,MAAM,IAAI,WAAW,EAAE,CAAC;QAChE,MAAM,IAAI,UAAU,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC,CAAC;IAC/D,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-all.d.ts","sourceRoot":"","sources":["../../../src/contracts/file-storage/read-all.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,wBAAsB,OAAO,CAAC,MAAM,EAAE,aAAa,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAQjF"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** The whole content of a stream: for the small files of a test, never in an adapter. */
|
|
2
|
+
export async function readAll(stream) {
|
|
3
|
+
const chunks = [];
|
|
4
|
+
for await (const chunk of stream) {
|
|
5
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk instanceof Uint8Array ? chunk : String(chunk)));
|
|
6
|
+
}
|
|
7
|
+
return new Uint8Array(Buffer.concat(chunks));
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=read-all.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-all.js","sourceRoot":"","sources":["../../../src/contracts/file-storage/read-all.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,MAA8B;IAC1D,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QACjC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,YAAY,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACjH,CAAC;IAED,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { FileStorageSuite } from './file-storage-suite.js';
|
|
2
|
+
/** A signed link grants one action on one file, for a short time, to whoever holds it unchanged. */
|
|
3
|
+
export declare class SignedLinksSuite extends FileStorageSuite {
|
|
4
|
+
protected tests(): void;
|
|
5
|
+
private downloads;
|
|
6
|
+
private uploads;
|
|
7
|
+
private refuses;
|
|
8
|
+
private textUpload;
|
|
9
|
+
private follow;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=signed-links-suite.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signed-links-suite.d.ts","sourceRoot":"","sources":["../../../src/contracts/file-storage/signed-links-suite.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAG3D,oGAAoG;AACpG,qBAAa,gBAAiB,SAAQ,gBAAgB;IACpD,SAAS,CAAC,KAAK,IAAI,IAAI,CAItB;IAED,OAAO,CAAC,SAAS;IAmCjB,OAAO,CAAC,OAAO;IAiCf,OAAO,CAAC,OAAO;IA2Bf,OAAO,CAAC,UAAU;IAQlB,OAAO,CAAC,MAAM;CAGf"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { MAX_SIGNED_URL_SECONDS } from '@ddd-ts-kit/kernel';
|
|
2
|
+
import { PDF, TEXT } from './contents.js';
|
|
3
|
+
import { tampered } from './tampered.js';
|
|
4
|
+
import { followWithFetch } from './follow-with-fetch.js';
|
|
5
|
+
import { FileStorageSuite } from './file-storage-suite.js';
|
|
6
|
+
/** A signed link grants one action on one file, for a short time, to whoever holds it unchanged. */
|
|
7
|
+
export class SignedLinksSuite extends FileStorageSuite {
|
|
8
|
+
tests() {
|
|
9
|
+
this.downloads();
|
|
10
|
+
this.uploads();
|
|
11
|
+
this.refuses();
|
|
12
|
+
}
|
|
13
|
+
downloads() {
|
|
14
|
+
this.it('downloads the file through its link, under the name it was signed with', async () => {
|
|
15
|
+
await this.write('documents/report.pdf', PDF);
|
|
16
|
+
const link = await this.subject.signedDownloadUrl('documents/report.pdf', {
|
|
17
|
+
expiresInSeconds: 300,
|
|
18
|
+
fileName: 'report.pdf',
|
|
19
|
+
});
|
|
20
|
+
const longer = await this.subject.signedDownloadUrl('documents/report.pdf', { expiresInSeconds: 600 });
|
|
21
|
+
const response = await this.follow({ url: link.url, method: 'GET' });
|
|
22
|
+
this.expect([response.status, response.body]).toEqual([200, PDF]);
|
|
23
|
+
this.expect(response.headers['content-disposition']?.includes('report.pdf')).toBe(true);
|
|
24
|
+
this.expect(Math.abs(longer.expiresAt.getTime() - link.expiresAt.getTime() - 300_000) < 5_000).toBe(true);
|
|
25
|
+
});
|
|
26
|
+
this.it('serves a link signed without a name as an attachment all the same, never inline', async () => {
|
|
27
|
+
await this.write('documents/report.pdf', PDF);
|
|
28
|
+
const link = await this.subject.signedDownloadUrl('documents/report.pdf', { expiresInSeconds: 300 });
|
|
29
|
+
const response = await this.follow({ url: link.url, method: 'GET' });
|
|
30
|
+
this.expect(response.headers['content-disposition']?.startsWith('attachment')).toBe(true);
|
|
31
|
+
});
|
|
32
|
+
this.it('refuses a download link once it has expired', async () => {
|
|
33
|
+
await this.write('documents/report.pdf', PDF);
|
|
34
|
+
const link = await this.subject.signedDownloadUrl('documents/report.pdf', { expiresInSeconds: 1 });
|
|
35
|
+
await this.options.elapse(2_100);
|
|
36
|
+
this.expect((await this.follow({ url: link.url, method: 'GET' })).status >= 400).toBe(true);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
uploads() {
|
|
40
|
+
this.it('stores what is sent through an upload link, with the media type it was signed for', async () => {
|
|
41
|
+
const upload = await this.textUpload();
|
|
42
|
+
const response = await this.follow({
|
|
43
|
+
url: upload.url,
|
|
44
|
+
method: upload.method,
|
|
45
|
+
headers: upload.headers,
|
|
46
|
+
body: TEXT,
|
|
47
|
+
});
|
|
48
|
+
const metadata = await this.subject.stat('staging/documents/notes.txt');
|
|
49
|
+
this.expect(response.status < 300).toBe(true);
|
|
50
|
+
this.expect([metadata?.size, metadata?.mediaType]).toEqual([TEXT.length, 'text/plain']);
|
|
51
|
+
this.expect(await this.read('staging/documents/notes.txt')).toEqual(TEXT);
|
|
52
|
+
});
|
|
53
|
+
this.it('refuses an upload sent with another media type than the one signed', async () => {
|
|
54
|
+
const upload = await this.textUpload();
|
|
55
|
+
const response = await this.follow({
|
|
56
|
+
url: upload.url,
|
|
57
|
+
method: 'PUT',
|
|
58
|
+
headers: { 'content-type': 'text/html' },
|
|
59
|
+
body: TEXT,
|
|
60
|
+
});
|
|
61
|
+
this.expect(response.status >= 400).toBe(true);
|
|
62
|
+
this.expect(await this.subject.stat('staging/documents/notes.txt')).toBe(undefined);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
refuses() {
|
|
66
|
+
this.it('refuses a link whose signature was changed', async () => {
|
|
67
|
+
await this.write('documents/report.pdf', PDF);
|
|
68
|
+
const link = await this.subject.signedDownloadUrl('documents/report.pdf', { expiresInSeconds: 300 });
|
|
69
|
+
this.expect((await this.follow({ url: tampered(link.url), method: 'GET' })).status >= 400).toBe(true);
|
|
70
|
+
});
|
|
71
|
+
this.it('refuses to sign a link for longer than the maximum, or for no time', async () => {
|
|
72
|
+
for (const expiresInSeconds of [MAX_SIGNED_URL_SECONDS + 1, 0, 1.5]) {
|
|
73
|
+
const code = await this.codeOf(() => this.subject.signedDownloadUrl('documents/report.pdf', { expiresInSeconds }));
|
|
74
|
+
this.expect(code).toBe('INVALID_FILE_URL_EXPIRY');
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
this.it('refuses to sign a link for a key that could leave its place', async () => {
|
|
78
|
+
const code = await this.codeOf(() => this.subject.signedUploadUrl('../outside', { expiresInSeconds: 60, mediaType: 'text/plain', maxBytes: 1_000 }));
|
|
79
|
+
this.expect(code).toBe('INVALID_FILE_KEY');
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
textUpload() {
|
|
83
|
+
return this.subject.signedUploadUrl('staging/documents/notes.txt', {
|
|
84
|
+
expiresInSeconds: 300,
|
|
85
|
+
mediaType: 'text/plain',
|
|
86
|
+
maxBytes: 1_000,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
follow(request) {
|
|
90
|
+
return (this.options.follow ?? followWithFetch)(request);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=signed-links-suite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signed-links-suite.js","sourceRoot":"","sources":["../../../src/contracts/file-storage/signed-links-suite.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** A request to a signed link, as a client would send it. */
|
|
2
|
+
export interface SignedRequest {
|
|
3
|
+
readonly url: string;
|
|
4
|
+
readonly method: 'GET' | 'PUT';
|
|
5
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
6
|
+
readonly body?: Uint8Array;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=signed-request.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signed-request.d.ts","sourceRoot":"","sources":["../../../src/contracts/file-storage/signed-request.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,KAAK,GAAG,KAAK,CAAC;IAC/B,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACpD,QAAQ,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC;CAC5B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signed-request.js","sourceRoot":"","sources":["../../../src/contracts/file-storage/signed-request.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tampered.d.ts","sourceRoot":"","sources":["../../../src/contracts/file-storage/tampered.ts"],"names":[],"mappings":"AAAA,0GAA0G;AAC1G,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE5C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tampered.js","sourceRoot":"","sources":["../../../src/contracts/file-storage/tampered.ts"],"names":[],"mappings":"AAAA,0GAA0G;AAC1G,MAAM,UAAU,QAAQ,CAAC,GAAW;IAClC,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;AAC/D,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ContractRunner } from './contract-runner.js';
|
|
2
|
+
import type { FileStorageContractOptions } from './file-storage/file-storage-contract-options.js';
|
|
3
|
+
/**
|
|
4
|
+
* What every connector of the kernel `FileStorage` port guarantees, the in-memory one included:
|
|
5
|
+
* content streams in and out intact and measured, a refused write leaves nothing, keys never
|
|
6
|
+
* leave their place, copies, moves and listings by key, and short signed links that grant one
|
|
7
|
+
* action. A connector of your own (Google Cloud Storage, Azure Blob Storage) is done when it
|
|
8
|
+
* passes this suite against the real service or its emulator.
|
|
9
|
+
*/
|
|
10
|
+
export declare function fileStorageContract(runner: ContractRunner, options: FileStorageContractOptions): void;
|
|
11
|
+
//# sourceMappingURL=file-storage-contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-storage-contract.d.ts","sourceRoot":"","sources":["../../src/contracts/file-storage-contract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3D,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,iDAAiD,CAAC;AAGlG;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,0BAA0B,GAAG,IAAI,CAIrG"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ArrangementSuite } from './file-storage/arrangement-suite.js';
|
|
2
|
+
import { ContentSuite } from './file-storage/content-suite.js';
|
|
3
|
+
import { SignedLinksSuite } from './file-storage/signed-links-suite.js';
|
|
4
|
+
/**
|
|
5
|
+
* What every connector of the kernel `FileStorage` port guarantees, the in-memory one included:
|
|
6
|
+
* content streams in and out intact and measured, a refused write leaves nothing, keys never
|
|
7
|
+
* leave their place, copies, moves and listings by key, and short signed links that grant one
|
|
8
|
+
* action. A connector of your own (Google Cloud Storage, Azure Blob Storage) is done when it
|
|
9
|
+
* passes this suite against the real service or its emulator.
|
|
10
|
+
*/
|
|
11
|
+
export function fileStorageContract(runner, options) {
|
|
12
|
+
new ContentSuite(runner, options).describe(`${options.name} (file storage contract: content)`);
|
|
13
|
+
new ArrangementSuite(runner, options).describe(`${options.name} (file storage contract: copy, move, list)`);
|
|
14
|
+
new SignedLinksSuite(runner, options).describe(`${options.name} (file storage contract: signed links)`);
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=file-storage-contract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-storage-contract.js","sourceRoot":"","sources":["../../src/contracts/file-storage-contract.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AACvE,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAE/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAExE;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAsB,EAAE,OAAmC;IAC7F,IAAI,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,IAAI,mCAAmC,CAAC,CAAC;IAC/F,IAAI,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,IAAI,4CAA4C,CAAC,CAAC;IAC5G,IAAI,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,IAAI,wCAAwC,CAAC,CAAC;AAC1G,CAAC"}
|
package/dist/contracts.d.ts
CHANGED
|
@@ -8,7 +8,16 @@ export { criteriaContractDefinition } from './contracts/criteria/criteria-contra
|
|
|
8
8
|
export type { CriteriaContractRow } from './contracts/criteria/criteria-contract-row.js';
|
|
9
9
|
export { criteriaContractRows } from './contracts/criteria/criteria-contract-rows.js';
|
|
10
10
|
export { eventBusContract, type EventBusContractOptions, type EventBusUnderContract, } from './contracts/event-bus-contract.js';
|
|
11
|
+
export { fileStorageContract } from './contracts/file-storage-contract.js';
|
|
12
|
+
export type { FileStorageContractOptions } from './contracts/file-storage/file-storage-contract-options.js';
|
|
13
|
+
export { followServed } from './contracts/file-storage/follow-served.js';
|
|
14
|
+
export { followWithFetch } from './contracts/file-storage/follow-with-fetch.js';
|
|
15
|
+
export type { FollowedResponse } from './contracts/file-storage/followed-response.js';
|
|
16
|
+
export type { SignedRequest } from './contracts/file-storage/signed-request.js';
|
|
11
17
|
export { jobSchedulerContract, type JobSchedulerContractOptions, type JobSchedulerUnderContract, } from './contracts/job-scheduler-contract.js';
|
|
18
|
+
export { eventStoreContract, type EventStoreContractOptions } from './contracts/event-store-contract.js';
|
|
19
|
+
export type { EventStoreUnderContract } from './contracts/event-store/event-store-under-contract.js';
|
|
20
|
+
export { eventStoreUnitOfWorkContract, type EventStoreUnitOfWorkContractOptions, } from './contracts/event-store-unit-of-work-contract.js';
|
|
12
21
|
export { lockContract, type LockContractOptions } from './contracts/lock-contract.js';
|
|
13
22
|
export { loggerContract, type LoggerContractOptions } from './contracts/logger-contract.js';
|
|
14
23
|
export type { CreateLogger } from './contracts/logger/create-logger.js';
|
package/dist/contracts.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACzF,YAAY,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EACL,gBAAgB,EAChB,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,GAC5B,MAAM,kCAAkC,CAAC;AAC1C,YAAY,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,EAAE,0BAA0B,EAAE,MAAM,sDAAsD,CAAC;AAClG,YAAY,EAAE,mBAAmB,EAAE,MAAM,+CAA+C,CAAC;AACzF,OAAO,EAAE,oBAAoB,EAAE,MAAM,gDAAgD,CAAC;AACtF,OAAO,EACL,gBAAgB,EAChB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,GAC3B,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACL,oBAAoB,EACpB,KAAK,2BAA2B,EAChC,KAAK,yBAAyB,GAC/B,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACtF,OAAO,EAAE,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAC5F,YAAY,EAAE,YAAY,EAAE,MAAM,qCAAqC,CAAC;AACxE,YAAY,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAC;AACpE,YAAY,EAAE,mBAAmB,EAAE,MAAM,6CAA6C,CAAC;AACvF,YAAY,EAAE,mBAAmB,EAAE,MAAM,6CAA6C,CAAC;AACvF,OAAO,EACL,mBAAmB,EACnB,KAAK,0BAA0B,EAC/B,KAAK,wBAAwB,GAC9B,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EACL,2BAA2B,EAC3B,KAAK,kCAAkC,GACxC,MAAM,+CAA+C,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,KAAK,0BAA0B,EAAE,MAAM,sCAAsC,CAAC;AAC5G,OAAO,EAAE,sBAAsB,EAAE,KAAK,6BAA6B,EAAE,MAAM,0CAA0C,CAAC;AACtH,YAAY,EAAE,2BAA2B,EAAE,MAAM,2DAA2D,CAAC;AAC7G,OAAO,EAAE,aAAa,EAAE,MAAM,2CAA2C,CAAC;AAC1E,OAAO,EAAE,kBAAkB,EAAE,KAAK,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AACxG,OAAO,EACL,uBAAuB,EACvB,KAAK,8BAA8B,GACpC,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,KAAK,yBAAyB,EAAE,MAAM,sCAAsC,CAAC;AAC1G,YAAY,EAAE,uBAAuB,EAAE,MAAM,yDAAyD,CAAC"}
|
|
1
|
+
{"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACzF,YAAY,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EACL,gBAAgB,EAChB,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,GAC5B,MAAM,kCAAkC,CAAC;AAC1C,YAAY,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,EAAE,0BAA0B,EAAE,MAAM,sDAAsD,CAAC;AAClG,YAAY,EAAE,mBAAmB,EAAE,MAAM,+CAA+C,CAAC;AACzF,OAAO,EAAE,oBAAoB,EAAE,MAAM,gDAAgD,CAAC;AACtF,OAAO,EACL,gBAAgB,EAChB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,GAC3B,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAC3E,YAAY,EAAE,0BAA0B,EAAE,MAAM,2DAA2D,CAAC;AAC5G,OAAO,EAAE,YAAY,EAAE,MAAM,2CAA2C,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,+CAA+C,CAAC;AAChF,YAAY,EAAE,gBAAgB,EAAE,MAAM,+CAA+C,CAAC;AACtF,YAAY,EAAE,aAAa,EAAE,MAAM,4CAA4C,CAAC;AAChF,OAAO,EACL,oBAAoB,EACpB,KAAK,2BAA2B,EAChC,KAAK,yBAAyB,GAC/B,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,KAAK,yBAAyB,EAAE,MAAM,qCAAqC,CAAC;AACzG,YAAY,EAAE,uBAAuB,EAAE,MAAM,uDAAuD,CAAC;AACrG,OAAO,EACL,4BAA4B,EAC5B,KAAK,mCAAmC,GACzC,MAAM,kDAAkD,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACtF,OAAO,EAAE,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAC5F,YAAY,EAAE,YAAY,EAAE,MAAM,qCAAqC,CAAC;AACxE,YAAY,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAC;AACpE,YAAY,EAAE,mBAAmB,EAAE,MAAM,6CAA6C,CAAC;AACvF,YAAY,EAAE,mBAAmB,EAAE,MAAM,6CAA6C,CAAC;AACvF,OAAO,EACL,mBAAmB,EACnB,KAAK,0BAA0B,EAC/B,KAAK,wBAAwB,GAC9B,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EACL,2BAA2B,EAC3B,KAAK,kCAAkC,GACxC,MAAM,+CAA+C,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,KAAK,0BAA0B,EAAE,MAAM,sCAAsC,CAAC;AAC5G,OAAO,EAAE,sBAAsB,EAAE,KAAK,6BAA6B,EAAE,MAAM,0CAA0C,CAAC;AACtH,YAAY,EAAE,2BAA2B,EAAE,MAAM,2DAA2D,CAAC;AAC7G,OAAO,EAAE,aAAa,EAAE,MAAM,2CAA2C,CAAC;AAC1E,OAAO,EAAE,kBAAkB,EAAE,KAAK,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AACxG,OAAO,EACL,uBAAuB,EACvB,KAAK,8BAA8B,GACpC,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,KAAK,yBAAyB,EAAE,MAAM,sCAAsC,CAAC;AAC1G,YAAY,EAAE,uBAAuB,EAAE,MAAM,yDAAyD,CAAC"}
|
package/dist/contracts.js
CHANGED
|
@@ -4,7 +4,12 @@ export { criteriaContract, } from './contracts/criteria-contract.js';
|
|
|
4
4
|
export { criteriaContractDefinition } from './contracts/criteria/criteria-contract-definition.js';
|
|
5
5
|
export { criteriaContractRows } from './contracts/criteria/criteria-contract-rows.js';
|
|
6
6
|
export { eventBusContract, } from './contracts/event-bus-contract.js';
|
|
7
|
+
export { fileStorageContract } from './contracts/file-storage-contract.js';
|
|
8
|
+
export { followServed } from './contracts/file-storage/follow-served.js';
|
|
9
|
+
export { followWithFetch } from './contracts/file-storage/follow-with-fetch.js';
|
|
7
10
|
export { jobSchedulerContract, } from './contracts/job-scheduler-contract.js';
|
|
11
|
+
export { eventStoreContract } from './contracts/event-store-contract.js';
|
|
12
|
+
export { eventStoreUnitOfWorkContract, } from './contracts/event-store-unit-of-work-contract.js';
|
|
8
13
|
export { lockContract } from './contracts/lock-contract.js';
|
|
9
14
|
export { loggerContract } from './contracts/logger-contract.js';
|
|
10
15
|
export { outboxStoreContract, } from './contracts/outbox-store-contract.js';
|
package/dist/contracts.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contracts.js","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAA6B,MAAM,+BAA+B,CAAC;AAEzF,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EACL,gBAAgB,GAGjB,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EAAE,0BAA0B,EAAE,MAAM,sDAAsD,CAAC;AAElG,OAAO,EAAE,oBAAoB,EAAE,MAAM,gDAAgD,CAAC;AACtF,OAAO,EACL,gBAAgB,GAGjB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACL,oBAAoB,GAGrB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAE,YAAY,EAA4B,MAAM,8BAA8B,CAAC;AACtF,OAAO,EAAE,cAAc,EAA8B,MAAM,gCAAgC,CAAC;AAK5F,OAAO,EACL,mBAAmB,GAGpB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EACL,2BAA2B,GAE5B,MAAM,+CAA+C,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAmC,MAAM,sCAAsC,CAAC;AAC5G,OAAO,EAAE,sBAAsB,EAAsC,MAAM,0CAA0C,CAAC;AAEtH,OAAO,EAAE,aAAa,EAAE,MAAM,2CAA2C,CAAC;AAC1E,OAAO,EAAE,kBAAkB,EAAkC,MAAM,oCAAoC,CAAC;AACxG,OAAO,EACL,uBAAuB,GAExB,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAkC,MAAM,sCAAsC,CAAC"}
|
|
1
|
+
{"version":3,"file":"contracts.js","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAA6B,MAAM,+BAA+B,CAAC;AAEzF,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EACL,gBAAgB,GAGjB,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EAAE,0BAA0B,EAAE,MAAM,sDAAsD,CAAC;AAElG,OAAO,EAAE,oBAAoB,EAAE,MAAM,gDAAgD,CAAC;AACtF,OAAO,EACL,gBAAgB,GAGjB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAE3E,OAAO,EAAE,YAAY,EAAE,MAAM,2CAA2C,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,+CAA+C,CAAC;AAGhF,OAAO,EACL,oBAAoB,GAGrB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAkC,MAAM,qCAAqC,CAAC;AAEzG,OAAO,EACL,4BAA4B,GAE7B,MAAM,kDAAkD,CAAC;AAC1D,OAAO,EAAE,YAAY,EAA4B,MAAM,8BAA8B,CAAC;AACtF,OAAO,EAAE,cAAc,EAA8B,MAAM,gCAAgC,CAAC;AAK5F,OAAO,EACL,mBAAmB,GAGpB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EACL,2BAA2B,GAE5B,MAAM,+CAA+C,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAmC,MAAM,sCAAsC,CAAC;AAC5G,OAAO,EAAE,sBAAsB,EAAsC,MAAM,0CAA0C,CAAC;AAEtH,OAAO,EAAE,aAAa,EAAE,MAAM,2CAA2C,CAAC;AAC1E,OAAO,EAAE,kBAAkB,EAAkC,MAAM,oCAAoC,CAAC;AACxG,OAAO,EACL,uBAAuB,GAExB,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAkC,MAAM,sCAAsC,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type DomainEvent } from '@ddd-ts-kit/kernel';
|
|
2
|
+
import type { SnapshotEquivalence } from './snapshot-equivalence.js';
|
|
3
|
+
/**
|
|
4
|
+
* Proves that the snapshots of an aggregate give the state a full replay gives. For every version
|
|
5
|
+
* of the history, the aggregate replayed up to it is encoded as its snapshot policy would store it,
|
|
6
|
+
* decoded, and rebuilt from that snapshot and the events after it: its state and its version must
|
|
7
|
+
* equal those of the aggregate replayed from the first event. Throws an AssertionError at the
|
|
8
|
+
* first version that differs. A personal value is read back as it was given, as a cipher would
|
|
9
|
+
* open it.
|
|
10
|
+
*/
|
|
11
|
+
export declare function expectSnapshotEquivalence<A extends {
|
|
12
|
+
readonly version: number;
|
|
13
|
+
}, E extends DomainEvent, S>(proof: SnapshotEquivalence<A, E, S>): void;
|
|
14
|
+
//# sourceMappingURL=expect-snapshot-equivalence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expect-snapshot-equivalence.d.ts","sourceRoot":"","sources":["../../src/event-sourcing/expect-snapshot-equivalence.ts"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,WAAW,EAGjB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAErE;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CAAC,CAAC,SAAS;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,SAAS,WAAW,EAAE,CAAC,EACxG,KAAK,EAAE,mBAAmB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAClC,IAAI,CAiBN"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { AssertionError } from 'node:assert';
|
|
2
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
3
|
+
import { StoredEventData, isStoredData, isStoredList, storedDataOf, } from '@ddd-ts-kit/kernel';
|
|
4
|
+
/**
|
|
5
|
+
* Proves that the snapshots of an aggregate give the state a full replay gives. For every version
|
|
6
|
+
* of the history, the aggregate replayed up to it is encoded as its snapshot policy would store it,
|
|
7
|
+
* decoded, and rebuilt from that snapshot and the events after it: its state and its version must
|
|
8
|
+
* equal those of the aggregate replayed from the first event. Throws an AssertionError at the
|
|
9
|
+
* first version that differs. A personal value is read back as it was given, as a cipher would
|
|
10
|
+
* open it.
|
|
11
|
+
*/
|
|
12
|
+
export function expectSnapshotEquivalence(proof) {
|
|
13
|
+
const { events } = proof;
|
|
14
|
+
const id = events[0]?.aggregateId ?? '';
|
|
15
|
+
const replayed = proof.rehydrate(id, { events });
|
|
16
|
+
for (let at = 1; at <= events.length; at += 1) {
|
|
17
|
+
const restored = fromSnapshotAt(proof, id, at);
|
|
18
|
+
if (restored.version !== replayed.version || !isDeepStrictEqual(proof.state(restored), proof.state(replayed))) {
|
|
19
|
+
throw new AssertionError({
|
|
20
|
+
message: `Rebuilt from a snapshot taken after event ${at} of ${events.length}, the aggregate differs from its full replay.`,
|
|
21
|
+
actual: { version: restored.version, state: proof.state(restored) },
|
|
22
|
+
expected: { version: replayed.version, state: proof.state(replayed) },
|
|
23
|
+
operator: 'expectSnapshotEquivalence',
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function fromSnapshotAt(proof, id, at) {
|
|
29
|
+
const { events, policy } = proof;
|
|
30
|
+
const kept = opened(storedDataOf(policy.encode(proof.rehydrate(id, { events: events.slice(0, at) }))));
|
|
31
|
+
const state = policy.decode(new StoredEventData(kept, `the snapshot after event ${at}`));
|
|
32
|
+
return proof.rehydrate(id, { snapshot: { version: at, state }, events: events.slice(at) });
|
|
33
|
+
}
|
|
34
|
+
/** The data as a store would give it back: a copy, each personal value in place of its marker. */
|
|
35
|
+
function opened(data) {
|
|
36
|
+
return Object.fromEntries(Object.entries(data).map(([key, value]) => [key, openedValue(value)]));
|
|
37
|
+
}
|
|
38
|
+
function openedValue(value) {
|
|
39
|
+
if (isStoredList(value)) {
|
|
40
|
+
return value.map(openedValue);
|
|
41
|
+
}
|
|
42
|
+
if (!isStoredData(value)) {
|
|
43
|
+
return value;
|
|
44
|
+
}
|
|
45
|
+
const personal = value['$personal'];
|
|
46
|
+
return isStoredData(personal) && typeof personal['value'] === 'string' ? personal['value'] : opened(value);
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=expect-snapshot-equivalence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expect-snapshot-equivalence.js","sourceRoot":"","sources":["../../src/event-sourcing/expect-snapshot-equivalence.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AggregateHistory, DomainEvent } from '@ddd-ts-kit/kernel';
|
|
2
|
+
import type { EventSource } from '../scenarios/event-source.js';
|
|
3
|
+
import { type Scenario } from '../scenarios/scenario.js';
|
|
4
|
+
/**
|
|
5
|
+
* Starts a scenario of an event-sourced aggregate from its history, without a database: the
|
|
6
|
+
* aggregate is rebuilt by replaying `events` through `rehydrate`, then `when` runs one command and
|
|
7
|
+
* `thenEvents` asserts what it recorded.
|
|
8
|
+
* `givenEvents((id, history) => Invoice.rehydrate(id, history), [issued]).when((invoice) => invoice.pay(now)).thenEvents([InvoicePaid])`.
|
|
9
|
+
* The id is the one the events carry; give it for an empty history.
|
|
10
|
+
*/
|
|
11
|
+
export declare function givenEvents<A extends EventSource, E extends DomainEvent>(rehydrate: (id: string, history: AggregateHistory<E>) => A, events: readonly E[], id?: string): Scenario<A>;
|
|
12
|
+
//# sourceMappingURL=given-events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"given-events.d.ts","sourceRoot":"","sources":["../../src/event-sourcing/given-events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAY,KAAK,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEnE;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,WAAW,EAAE,CAAC,SAAS,WAAW,EACtE,SAAS,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,KAAK,CAAC,EAC1D,MAAM,EAAE,SAAS,CAAC,EAAE,EACpB,EAAE,CAAC,EAAE,MAAM,GACV,QAAQ,CAAC,CAAC,CAAC,CAQb"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { scenario } from '../scenarios/scenario.js';
|
|
2
|
+
/**
|
|
3
|
+
* Starts a scenario of an event-sourced aggregate from its history, without a database: the
|
|
4
|
+
* aggregate is rebuilt by replaying `events` through `rehydrate`, then `when` runs one command and
|
|
5
|
+
* `thenEvents` asserts what it recorded.
|
|
6
|
+
* `givenEvents((id, history) => Invoice.rehydrate(id, history), [issued]).when((invoice) => invoice.pay(now)).thenEvents([InvoicePaid])`.
|
|
7
|
+
* The id is the one the events carry; give it for an empty history.
|
|
8
|
+
*/
|
|
9
|
+
export function givenEvents(rehydrate, events, id) {
|
|
10
|
+
const identity = id ?? events[0]?.aggregateId;
|
|
11
|
+
if (identity === undefined) {
|
|
12
|
+
throw new TypeError('givenEvents needs the id of the aggregate when the history is empty');
|
|
13
|
+
}
|
|
14
|
+
return scenario(() => rehydrate(identity, { events }));
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=given-events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"given-events.js","sourceRoot":"","sources":["../../src/event-sourcing/given-events.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAiB,MAAM,0BAA0B,CAAC;AAEnE;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CACzB,SAA0D,EAC1D,MAAoB,EACpB,EAAW;IAEX,MAAM,QAAQ,GAAG,EAAE,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC;IAE9C,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,MAAM,IAAI,SAAS,CAAC,qEAAqE,CAAC,CAAC;IAC7F,CAAC;IAED,OAAO,QAAQ,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;AACzD,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AggregateHistory, DomainEvent, SnapshotPolicy } from '@ddd-ts-kit/kernel';
|
|
2
|
+
/** What `expectSnapshotEquivalence` replays, both ways. */
|
|
3
|
+
export interface SnapshotEquivalence<A, E extends DomainEvent, S> {
|
|
4
|
+
/** A history long enough to cross the snapshot interval, in order. */
|
|
5
|
+
readonly events: readonly E[];
|
|
6
|
+
rehydrate(id: string, history: AggregateHistory<E, S>): A;
|
|
7
|
+
/** The snapshot policy of the repository: its `encode` and `decode` are what is proven. */
|
|
8
|
+
readonly policy: Pick<SnapshotPolicy<A, S>, 'encode' | 'decode'>;
|
|
9
|
+
/** What two aggregates must share: their state as a value. */
|
|
10
|
+
state(aggregate: A): unknown;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=snapshot-equivalence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot-equivalence.d.ts","sourceRoot":"","sources":["../../src/event-sourcing/snapshot-equivalence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAExF,2DAA2D;AAC3D,MAAM,WAAW,mBAAmB,CAAC,CAAC,EAAE,CAAC,SAAS,WAAW,EAAE,CAAC;IAC9D,sEAAsE;IACtE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,CAAC;IAC9B,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;IAC1D,2FAA2F;IAC3F,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC,CAAC;IACjE,8DAA8D;IAC9D,KAAK,CAAC,SAAS,EAAE,CAAC,GAAG,OAAO,CAAC;CAC9B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot-equivalence.js","sourceRoot":"","sources":["../../src/event-sourcing/snapshot-equivalence.ts"],"names":[],"mappings":""}
|
package/dist/index.d.ts
CHANGED
|
@@ -15,6 +15,9 @@ export { scoped } from './execution/scoped.js';
|
|
|
15
15
|
export { asTenant } from './execution/as-tenant.js';
|
|
16
16
|
export { SessionBuilder } from './execution/session-builder.js';
|
|
17
17
|
export { createTestBuses, type TestBuses, type TestBusesOptions } from './harness/create-test-buses.js';
|
|
18
|
+
export { expectSnapshotEquivalence } from './event-sourcing/expect-snapshot-equivalence.js';
|
|
19
|
+
export { givenEvents } from './event-sourcing/given-events.js';
|
|
20
|
+
export type { SnapshotEquivalence } from './event-sourcing/snapshot-equivalence.js';
|
|
18
21
|
export { expectRefusal } from './refusals/expect-refusal.js';
|
|
19
22
|
export type { ExpectedFacts } from './refusals/expected-facts.js';
|
|
20
23
|
export { InMemoryRepository, type InMemoryRepositoryOptions } from './repositories/in-memory-repository.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC5E,YAAY,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,YAAY,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC1C,YAAY,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AACzE,OAAO,EAAE,uBAAuB,EAAE,MAAM,0CAA0C,CAAC;AACnF,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,KAAK,SAAS,EAAE,KAAK,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACxG,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,YAAY,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,KAAK,yBAAyB,EAAE,MAAM,wCAAwC,CAAC;AAC5G,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,YAAY,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACjE,YAAY,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,YAAY,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACjE,YAAY,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAC7C,YAAY,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,KAAK,QAAQ,EAAE,MAAM,yBAAyB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC5E,YAAY,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,YAAY,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC1C,YAAY,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AACzE,OAAO,EAAE,uBAAuB,EAAE,MAAM,0CAA0C,CAAC;AACnF,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,KAAK,SAAS,EAAE,KAAK,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACxG,OAAO,EAAE,yBAAyB,EAAE,MAAM,iDAAiD,CAAC;AAC5F,OAAO,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAC/D,YAAY,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AACpF,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,YAAY,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,KAAK,yBAAyB,EAAE,MAAM,wCAAwC,CAAC;AAC5G,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,YAAY,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACjE,YAAY,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,YAAY,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACjE,YAAY,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAC7C,YAAY,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,KAAK,QAAQ,EAAE,MAAM,yBAAyB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -12,6 +12,8 @@ export { scoped } from './execution/scoped.js';
|
|
|
12
12
|
export { asTenant } from './execution/as-tenant.js';
|
|
13
13
|
export { SessionBuilder } from './execution/session-builder.js';
|
|
14
14
|
export { createTestBuses } from './harness/create-test-buses.js';
|
|
15
|
+
export { expectSnapshotEquivalence } from './event-sourcing/expect-snapshot-equivalence.js';
|
|
16
|
+
export { givenEvents } from './event-sourcing/given-events.js';
|
|
15
17
|
export { expectRefusal } from './refusals/expect-refusal.js';
|
|
16
18
|
export { InMemoryRepository } from './repositories/in-memory-repository.js';
|
|
17
19
|
export { snapshots } from './repositories/snapshots.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE5E,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAEhD,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAE1C,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AACzE,OAAO,EAAE,uBAAuB,EAAE,MAAM,0CAA0C,CAAC;AACnF,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,eAAe,EAAyC,MAAM,gCAAgC,CAAC;AACxG,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAE7D,OAAO,EAAE,kBAAkB,EAAkC,MAAM,wCAAwC,CAAC;AAC5G,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAK/D,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAE7C,OAAO,EAAE,QAAQ,EAAiB,MAAM,yBAAyB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE5E,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAEhD,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAE1C,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AACzE,OAAO,EAAE,uBAAuB,EAAE,MAAM,0CAA0C,CAAC;AACnF,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,eAAe,EAAyC,MAAM,gCAAgC,CAAC;AACxG,OAAO,EAAE,yBAAyB,EAAE,MAAM,iDAAiD,CAAC;AAC5F,OAAO,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAE/D,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAE7D,OAAO,EAAE,kBAAkB,EAAkC,MAAM,wCAAwC,CAAC;AAC5G,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAK/D,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAE7C,OAAO,EAAE,QAAQ,EAAiB,MAAM,yBAAyB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ddd-ts-kit/testing",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Readable tests without mocks: test data builders, given/when/then scenarios and contract suites shared by fakes and real adapters.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -46,11 +46,11 @@
|
|
|
46
46
|
"dist"
|
|
47
47
|
],
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@ddd-ts-kit/kernel": "0.
|
|
49
|
+
"@ddd-ts-kit/kernel": "0.10.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"@ddd-ts-kit/aspects": "0.
|
|
53
|
-
"@ddd-ts-kit/events": "0.
|
|
52
|
+
"@ddd-ts-kit/aspects": "0.10.0",
|
|
53
|
+
"@ddd-ts-kit/events": "0.10.0",
|
|
54
54
|
"@faker-js/faker": "^10.6.0"
|
|
55
55
|
},
|
|
56
56
|
"peerDependencies": {
|