@nestjs-transactional/outbox 1.0.0-alpha.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/LICENSE +21 -0
- package/README.md +396 -0
- package/dist/api/completed-event-publications.d.ts +31 -0
- package/dist/api/completed-event-publications.js +58 -0
- package/dist/api/completed-event-publications.js.map +1 -0
- package/dist/api/failed-event-publications.d.ts +36 -0
- package/dist/api/failed-event-publications.js +75 -0
- package/dist/api/failed-event-publications.js.map +1 -0
- package/dist/api/incomplete-event-publications.d.ts +28 -0
- package/dist/api/incomplete-event-publications.js +72 -0
- package/dist/api/incomplete-event-publications.js.map +1 -0
- package/dist/decorators/inject-decorators.d.ts +85 -0
- package/dist/decorators/inject-decorators.js +100 -0
- package/dist/decorators/inject-decorators.js.map +1 -0
- package/dist/decorators/outbox-events-handler.decorator.d.ts +97 -0
- package/dist/decorators/outbox-events-handler.decorator.js +58 -0
- package/dist/decorators/outbox-events-handler.decorator.js.map +1 -0
- package/dist/dispatcher/data-source-outbox-publisher.d.ts +69 -0
- package/dist/dispatcher/data-source-outbox-publisher.js +127 -0
- package/dist/dispatcher/data-source-outbox-publisher.js.map +1 -0
- package/dist/dispatcher/event-publication-processor.d.ts +69 -0
- package/dist/dispatcher/event-publication-processor.js +192 -0
- package/dist/dispatcher/event-publication-processor.js.map +1 -0
- package/dist/dispatcher/outbox-event-publisher.d.ts +129 -0
- package/dist/dispatcher/outbox-event-publisher.js +172 -0
- package/dist/dispatcher/outbox-event-publisher.js.map +1 -0
- package/dist/dispatcher/processor-options.d.ts +24 -0
- package/dist/dispatcher/processor-options.js +15 -0
- package/dist/dispatcher/processor-options.js.map +1 -0
- package/dist/externalization/errors.d.ts +21 -0
- package/dist/externalization/errors.js +30 -0
- package/dist/externalization/errors.js.map +1 -0
- package/dist/externalization/event-externalizer.d.ts +49 -0
- package/dist/externalization/event-externalizer.js +14 -0
- package/dist/externalization/event-externalizer.js.map +1 -0
- package/dist/externalization/externalization-registry.d.ts +56 -0
- package/dist/externalization/externalization-registry.js +103 -0
- package/dist/externalization/externalization-registry.js.map +1 -0
- package/dist/externalization/externalized.decorator.d.ts +121 -0
- package/dist/externalization/externalized.decorator.js +87 -0
- package/dist/externalization/externalized.decorator.js.map +1 -0
- package/dist/externalization/types.d.ts +39 -0
- package/dist/externalization/types.js +3 -0
- package/dist/externalization/types.js.map +1 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.js +58 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/outbox-event-handler.interface.d.ts +32 -0
- package/dist/interfaces/outbox-event-handler.interface.js +3 -0
- package/dist/interfaces/outbox-event-handler.interface.js.map +1 -0
- package/dist/module/outbox-processing.module.d.ts +29 -0
- package/dist/module/outbox-processing.module.js +66 -0
- package/dist/module/outbox-processing.module.js.map +1 -0
- package/dist/module/outbox.module.d.ts +196 -0
- package/dist/module/outbox.module.js +604 -0
- package/dist/module/outbox.module.js.map +1 -0
- package/dist/recovery/staleness-monitor.d.ts +39 -0
- package/dist/recovery/staleness-monitor.js +118 -0
- package/dist/recovery/staleness-monitor.js.map +1 -0
- package/dist/recovery/startup-recovery.d.ts +37 -0
- package/dist/recovery/startup-recovery.js +55 -0
- package/dist/recovery/startup-recovery.js.map +1 -0
- package/dist/registry/event-publication-registry.d.ts +70 -0
- package/dist/registry/event-publication-registry.js +138 -0
- package/dist/registry/event-publication-registry.js.map +1 -0
- package/dist/registry/listener-registry.d.ts +52 -0
- package/dist/registry/listener-registry.js +67 -0
- package/dist/registry/listener-registry.js.map +1 -0
- package/dist/registry/multi-ds-listener-registrar.d.ts +78 -0
- package/dist/registry/multi-ds-listener-registrar.js +112 -0
- package/dist/registry/multi-ds-listener-registrar.js.map +1 -0
- package/dist/registry/outbox-listener-scanner.d.ts +66 -0
- package/dist/registry/outbox-listener-scanner.js +192 -0
- package/dist/registry/outbox-listener-scanner.js.map +1 -0
- package/dist/repository/event-publication-repository.d.ts +112 -0
- package/dist/repository/event-publication-repository.js +6 -0
- package/dist/repository/event-publication-repository.js.map +1 -0
- package/dist/serialization/event-serializer.d.ts +28 -0
- package/dist/serialization/event-serializer.js +6 -0
- package/dist/serialization/event-serializer.js.map +1 -0
- package/dist/serialization/event-type-registry.d.ts +41 -0
- package/dist/serialization/event-type-registry.js +79 -0
- package/dist/serialization/event-type-registry.js.map +1 -0
- package/dist/serialization/event-type-resolver.d.ts +43 -0
- package/dist/serialization/event-type-resolver.js +66 -0
- package/dist/serialization/event-type-resolver.js.map +1 -0
- package/dist/serialization/json-event-serializer.d.ts +20 -0
- package/dist/serialization/json-event-serializer.js +64 -0
- package/dist/serialization/json-event-serializer.js.map +1 -0
- package/dist/testing/assertable-published-events.d.ts +71 -0
- package/dist/testing/assertable-published-events.js +124 -0
- package/dist/testing/assertable-published-events.js.map +1 -0
- package/dist/testing/in-memory-repository.d.ts +52 -0
- package/dist/testing/in-memory-repository.js +230 -0
- package/dist/testing/in-memory-repository.js.map +1 -0
- package/dist/testing/index.d.ts +4 -0
- package/dist/testing/index.js +20 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/published-events.d.ts +62 -0
- package/dist/testing/published-events.js +110 -0
- package/dist/testing/published-events.js.map +1 -0
- package/dist/tokens/index.d.ts +2 -0
- package/dist/tokens/index.js +14 -0
- package/dist/tokens/index.js.map +1 -0
- package/dist/tokens/token-utils.d.ts +68 -0
- package/dist/tokens/token-utils.js +98 -0
- package/dist/tokens/token-utils.js.map +1 -0
- package/dist/types/completion-mode.d.ts +16 -0
- package/dist/types/completion-mode.js +20 -0
- package/dist/types/completion-mode.js.map +1 -0
- package/dist/types/errors.d.ts +50 -0
- package/dist/types/errors.js +64 -0
- package/dist/types/errors.js.map +1 -0
- package/dist/types/event-publication.d.ts +47 -0
- package/dist/types/event-publication.js +3 -0
- package/dist/types/event-publication.js.map +1 -0
- package/dist/types/publication-status.d.ts +26 -0
- package/dist/types/publication-status.js +30 -0
- package/dist/types/publication-status.js.map +1 -0
- package/dist/types/resubmission-options.d.ts +37 -0
- package/dist/types/resubmission-options.js +62 -0
- package/dist/types/resubmission-options.js.map +1 -0
- package/dist/types/staleness-config.d.ts +18 -0
- package/dist/types/staleness-config.js +10 -0
- package/dist/types/staleness-config.js.map +1 -0
- package/package.json +77 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Type } from '@nestjs/common';
|
|
2
|
+
/**
|
|
3
|
+
* Registry that maps event class names to their constructors so the
|
|
4
|
+
* serializer can reconstruct class instances from stored JSON payloads.
|
|
5
|
+
*
|
|
6
|
+
* Event classes are registered at application startup, typically via
|
|
7
|
+
* `OutboxModule.forFeature([...])` in the feature module that owns the
|
|
8
|
+
* event class. Each event type can only be registered once — duplicate
|
|
9
|
+
* registrations throw at bootstrap, so a misconfigured module fails
|
|
10
|
+
* fast rather than silently shadowing an earlier registration.
|
|
11
|
+
*/
|
|
12
|
+
export declare class EventTypeRegistry {
|
|
13
|
+
private readonly registry;
|
|
14
|
+
/**
|
|
15
|
+
* Register a single event class, keyed by its constructor name.
|
|
16
|
+
*
|
|
17
|
+
* @throws `Error` when an event class with the same constructor name
|
|
18
|
+
* has already been registered. Duplicate registration almost always
|
|
19
|
+
* indicates a configuration bug (the same event type appearing in
|
|
20
|
+
* two `forFeature` calls) — fail fast rather than silently shadow.
|
|
21
|
+
*/
|
|
22
|
+
register(eventType: Type<object>): void;
|
|
23
|
+
/** Register many event classes at once. */
|
|
24
|
+
registerAll(eventTypes: Type<object>[]): void;
|
|
25
|
+
/** Return the registered class for the given name, or `undefined`. */
|
|
26
|
+
get(typeName: string): Type<object> | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Return the registered class for the given name.
|
|
29
|
+
*
|
|
30
|
+
* @throws `Error` with an actionable message when the type is
|
|
31
|
+
* unregistered — tells the caller how to register it.
|
|
32
|
+
*/
|
|
33
|
+
getOrThrow(typeName: string): Type<object>;
|
|
34
|
+
/** Whether the given type name is known to the registry. */
|
|
35
|
+
has(typeName: string): boolean;
|
|
36
|
+
/** Return a snapshot of all registered entries. Mutations are not observed. */
|
|
37
|
+
getAll(): Map<string, Type<object>>;
|
|
38
|
+
}
|
|
39
|
+
/** DI token for the {@link EventTypeRegistry}. */
|
|
40
|
+
export declare const EVENT_TYPE_REGISTRY: unique symbol;
|
|
41
|
+
//# sourceMappingURL=event-type-registry.d.ts.map
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.EVENT_TYPE_REGISTRY = exports.EventTypeRegistry = void 0;
|
|
10
|
+
const common_1 = require("@nestjs/common");
|
|
11
|
+
/**
|
|
12
|
+
* Registry that maps event class names to their constructors so the
|
|
13
|
+
* serializer can reconstruct class instances from stored JSON payloads.
|
|
14
|
+
*
|
|
15
|
+
* Event classes are registered at application startup, typically via
|
|
16
|
+
* `OutboxModule.forFeature([...])` in the feature module that owns the
|
|
17
|
+
* event class. Each event type can only be registered once — duplicate
|
|
18
|
+
* registrations throw at bootstrap, so a misconfigured module fails
|
|
19
|
+
* fast rather than silently shadowing an earlier registration.
|
|
20
|
+
*/
|
|
21
|
+
let EventTypeRegistry = class EventTypeRegistry {
|
|
22
|
+
registry = new Map();
|
|
23
|
+
/**
|
|
24
|
+
* Register a single event class, keyed by its constructor name.
|
|
25
|
+
*
|
|
26
|
+
* @throws `Error` when an event class with the same constructor name
|
|
27
|
+
* has already been registered. Duplicate registration almost always
|
|
28
|
+
* indicates a configuration bug (the same event type appearing in
|
|
29
|
+
* two `forFeature` calls) — fail fast rather than silently shadow.
|
|
30
|
+
*/
|
|
31
|
+
register(eventType) {
|
|
32
|
+
if (this.registry.has(eventType.name)) {
|
|
33
|
+
throw new Error(`Event type '${eventType.name}' already registered. ` +
|
|
34
|
+
`Each event type can only be registered once — check for ` +
|
|
35
|
+
`duplicate entries across OutboxModule.forFeature() calls.`);
|
|
36
|
+
}
|
|
37
|
+
this.registry.set(eventType.name, eventType);
|
|
38
|
+
}
|
|
39
|
+
/** Register many event classes at once. */
|
|
40
|
+
registerAll(eventTypes) {
|
|
41
|
+
for (const type of eventTypes) {
|
|
42
|
+
this.register(type);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/** Return the registered class for the given name, or `undefined`. */
|
|
46
|
+
get(typeName) {
|
|
47
|
+
return this.registry.get(typeName);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Return the registered class for the given name.
|
|
51
|
+
*
|
|
52
|
+
* @throws `Error` with an actionable message when the type is
|
|
53
|
+
* unregistered — tells the caller how to register it.
|
|
54
|
+
*/
|
|
55
|
+
getOrThrow(typeName) {
|
|
56
|
+
const type = this.registry.get(typeName);
|
|
57
|
+
if (!type) {
|
|
58
|
+
throw new Error(`Event type '${typeName}' not registered. ` +
|
|
59
|
+
`Ensure it's registered via OutboxModule.forFeature([...]) in ` +
|
|
60
|
+
`the feature module that owns this event class.`);
|
|
61
|
+
}
|
|
62
|
+
return type;
|
|
63
|
+
}
|
|
64
|
+
/** Whether the given type name is known to the registry. */
|
|
65
|
+
has(typeName) {
|
|
66
|
+
return this.registry.has(typeName);
|
|
67
|
+
}
|
|
68
|
+
/** Return a snapshot of all registered entries. Mutations are not observed. */
|
|
69
|
+
getAll() {
|
|
70
|
+
return new Map(this.registry);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
exports.EventTypeRegistry = EventTypeRegistry;
|
|
74
|
+
exports.EventTypeRegistry = EventTypeRegistry = __decorate([
|
|
75
|
+
(0, common_1.Injectable)()
|
|
76
|
+
], EventTypeRegistry);
|
|
77
|
+
/** DI token for the {@link EventTypeRegistry}. */
|
|
78
|
+
exports.EVENT_TYPE_REGISTRY = Symbol('EVENT_TYPE_REGISTRY');
|
|
79
|
+
//# sourceMappingURL=event-type-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-type-registry.js","sourceRoot":"","sources":["../../src/serialization/event-type-registry.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAkD;AAElD;;;;;;;;;GASG;AAEI,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;IACX,QAAQ,GAAG,IAAI,GAAG,EAAwB,CAAC;IAE5D;;;;;;;OAOG;IACH,QAAQ,CAAC,SAAuB;QAC9B,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CACb,eAAe,SAAS,CAAC,IAAI,wBAAwB;gBACnD,0DAA0D;gBAC1D,2DAA2D,CAC9D,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAC/C,CAAC;IAED,2CAA2C;IAC3C,WAAW,CAAC,UAA0B;QACpC,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;YAC9B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IAED,sEAAsE;IACtE,GAAG,CAAC,QAAgB;QAClB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACrC,CAAC;IAED;;;;;OAKG;IACH,UAAU,CAAC,QAAgB;QACzB,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACzC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CACb,eAAe,QAAQ,oBAAoB;gBACzC,+DAA+D;gBAC/D,gDAAgD,CACnD,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,4DAA4D;IAC5D,GAAG,CAAC,QAAgB;QAClB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACrC,CAAC;IAED,+EAA+E;IAC/E,MAAM;QACJ,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC;CACF,CAAA;AA7DY,8CAAiB;4BAAjB,iBAAiB;IAD7B,IAAA,mBAAU,GAAE;GACA,iBAAiB,CA6D7B;AAED,kDAAkD;AACrC,QAAA,mBAAmB,GAAG,MAAM,CAAC,qBAAqB,CAAC,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { EventTypeRegistry } from './event-type-registry';
|
|
2
|
+
/**
|
|
3
|
+
* Resolve the dataSource that owns a given event-type name by walking
|
|
4
|
+
* a Map of per-dataSource {@link EventTypeRegistry} instances. Returns
|
|
5
|
+
* the dataSource name as a string when exactly one registry contains
|
|
6
|
+
* the event-type — otherwise throws {@link OutboxError} with an
|
|
7
|
+
* actionable message.
|
|
8
|
+
*
|
|
9
|
+
* Single source of truth shared by three consumers (Phase 14.3.1):
|
|
10
|
+
*
|
|
11
|
+
* - {@link OutboxEventPublisher.resolveDataSource} — smart-facade
|
|
12
|
+
* publisher routes events to the dataSource that registered them.
|
|
13
|
+
* - `OutboxListenerScanner` — decorator-driven `@OutboxEventsHandler`
|
|
14
|
+
* handlers register with the per-dataSource
|
|
15
|
+
* `OutboxListenerRegistry` whose dataSource owns the event class.
|
|
16
|
+
* - `MultiDsOutboxListenerRegistrar` — bridges
|
|
17
|
+
* `@IntegrationEventsHandler` from the cqrs package's structural
|
|
18
|
+
* port to the per-dataSource registry.
|
|
19
|
+
*
|
|
20
|
+
* Failure modes:
|
|
21
|
+
*
|
|
22
|
+
* - **Zero matches** (event not registered anywhere): the caller is
|
|
23
|
+
* almost always missing an `OutboxModule.forFeature([X], { dataSource })`
|
|
24
|
+
* call. The thrown message names the event and suggests the fix.
|
|
25
|
+
* - **Multiple matches** (event registered in more than one dataSource):
|
|
26
|
+
* ambiguous routing. The thrown message names the event, lists the
|
|
27
|
+
* candidate dataSources, and suggests either restricting the
|
|
28
|
+
* registration to one dataSource or using an explicit
|
|
29
|
+
* `{ dataSource }` option (in publisher contexts) / programmatic
|
|
30
|
+
* per-DS listener registration (in scanner contexts).
|
|
31
|
+
*
|
|
32
|
+
* The same throw policy is applied across all three consumers so the
|
|
33
|
+
* mental model is uniform: an event class belongs to exactly one
|
|
34
|
+
* dataSource by registration.
|
|
35
|
+
*
|
|
36
|
+
* @param eventTypeName The event class's `constructor.name`.
|
|
37
|
+
* @param registries Map of dataSource name → {@link EventTypeRegistry}.
|
|
38
|
+
* @returns The dataSource name.
|
|
39
|
+
* @throws {OutboxError} when zero or multiple registries contain the
|
|
40
|
+
* event-type.
|
|
41
|
+
*/
|
|
42
|
+
export declare function resolveDataSourceByEventTypeName(eventTypeName: string, registries: ReadonlyMap<string, EventTypeRegistry>): string;
|
|
43
|
+
//# sourceMappingURL=event-type-resolver.d.ts.map
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveDataSourceByEventTypeName = resolveDataSourceByEventTypeName;
|
|
4
|
+
const errors_1 = require("../types/errors");
|
|
5
|
+
/**
|
|
6
|
+
* Resolve the dataSource that owns a given event-type name by walking
|
|
7
|
+
* a Map of per-dataSource {@link EventTypeRegistry} instances. Returns
|
|
8
|
+
* the dataSource name as a string when exactly one registry contains
|
|
9
|
+
* the event-type — otherwise throws {@link OutboxError} with an
|
|
10
|
+
* actionable message.
|
|
11
|
+
*
|
|
12
|
+
* Single source of truth shared by three consumers (Phase 14.3.1):
|
|
13
|
+
*
|
|
14
|
+
* - {@link OutboxEventPublisher.resolveDataSource} — smart-facade
|
|
15
|
+
* publisher routes events to the dataSource that registered them.
|
|
16
|
+
* - `OutboxListenerScanner` — decorator-driven `@OutboxEventsHandler`
|
|
17
|
+
* handlers register with the per-dataSource
|
|
18
|
+
* `OutboxListenerRegistry` whose dataSource owns the event class.
|
|
19
|
+
* - `MultiDsOutboxListenerRegistrar` — bridges
|
|
20
|
+
* `@IntegrationEventsHandler` from the cqrs package's structural
|
|
21
|
+
* port to the per-dataSource registry.
|
|
22
|
+
*
|
|
23
|
+
* Failure modes:
|
|
24
|
+
*
|
|
25
|
+
* - **Zero matches** (event not registered anywhere): the caller is
|
|
26
|
+
* almost always missing an `OutboxModule.forFeature([X], { dataSource })`
|
|
27
|
+
* call. The thrown message names the event and suggests the fix.
|
|
28
|
+
* - **Multiple matches** (event registered in more than one dataSource):
|
|
29
|
+
* ambiguous routing. The thrown message names the event, lists the
|
|
30
|
+
* candidate dataSources, and suggests either restricting the
|
|
31
|
+
* registration to one dataSource or using an explicit
|
|
32
|
+
* `{ dataSource }` option (in publisher contexts) / programmatic
|
|
33
|
+
* per-DS listener registration (in scanner contexts).
|
|
34
|
+
*
|
|
35
|
+
* The same throw policy is applied across all three consumers so the
|
|
36
|
+
* mental model is uniform: an event class belongs to exactly one
|
|
37
|
+
* dataSource by registration.
|
|
38
|
+
*
|
|
39
|
+
* @param eventTypeName The event class's `constructor.name`.
|
|
40
|
+
* @param registries Map of dataSource name → {@link EventTypeRegistry}.
|
|
41
|
+
* @returns The dataSource name.
|
|
42
|
+
* @throws {OutboxError} when zero or multiple registries contain the
|
|
43
|
+
* event-type.
|
|
44
|
+
*/
|
|
45
|
+
function resolveDataSourceByEventTypeName(eventTypeName, registries) {
|
|
46
|
+
const matches = [];
|
|
47
|
+
for (const [dataSource, registry] of registries) {
|
|
48
|
+
if (registry.has(eventTypeName)) {
|
|
49
|
+
matches.push(dataSource);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (matches.length === 0) {
|
|
53
|
+
throw new errors_1.OutboxError(`Event type '${eventTypeName}' is not registered in any dataSource. ` +
|
|
54
|
+
`Add it to OutboxModule.forFeature([...], { dataSource: '...' }) ` +
|
|
55
|
+
`in the feature module that owns the event class.`);
|
|
56
|
+
}
|
|
57
|
+
if (matches.length > 1) {
|
|
58
|
+
throw new errors_1.OutboxError(`Event type '${eventTypeName}' is registered in multiple dataSources ` +
|
|
59
|
+
`(${matches.join(', ')}). Pass an explicit { dataSource } option to ` +
|
|
60
|
+
`disambiguate, or register the event in only one dataSource.`);
|
|
61
|
+
}
|
|
62
|
+
// Exactly one match — narrow safe.
|
|
63
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
64
|
+
return matches[0];
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=event-type-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-type-resolver.js","sourceRoot":"","sources":["../../src/serialization/event-type-resolver.ts"],"names":[],"mappings":";;AA4CA,4EA4BC;AAxED,4CAA8C;AAI9C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,SAAgB,gCAAgC,CAC9C,aAAqB,EACrB,UAAkD;IAElD,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,IAAI,UAAU,EAAE,CAAC;QAChD,IAAI,QAAQ,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC;YAChC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,oBAAW,CACnB,eAAe,aAAa,yCAAyC;YACnE,kEAAkE;YAClE,kDAAkD,CACrD,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,oBAAW,CACnB,eAAe,aAAa,0CAA0C;YACpE,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,+CAA+C;YACrE,6DAA6D,CAChE,CAAC;IACJ,CAAC;IACD,mCAAmC;IACnC,oEAAoE;IACpE,OAAO,OAAO,CAAC,CAAC,CAAE,CAAC;AACrB,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { EventSerializer } from './event-serializer';
|
|
2
|
+
import { EventTypeRegistry } from './event-type-registry';
|
|
3
|
+
/**
|
|
4
|
+
* Default JSON-based {@link EventSerializer}. Uses `JSON.stringify` for
|
|
5
|
+
* encoding and `JSON.parse` + `Object.create` for decoding, consulting
|
|
6
|
+
* an {@link EventTypeRegistry} to restore the class prototype when
|
|
7
|
+
* possible.
|
|
8
|
+
*
|
|
9
|
+
* This implementation is intentionally simple: it restores the
|
|
10
|
+
* prototype but does not call the constructor, so classes with private
|
|
11
|
+
* fields, Value-Object invariants, or custom deserialization must
|
|
12
|
+
* provide their own `EventSerializer`.
|
|
13
|
+
*/
|
|
14
|
+
export declare class JsonEventSerializer implements EventSerializer {
|
|
15
|
+
private readonly registry;
|
|
16
|
+
constructor(registry: EventTypeRegistry);
|
|
17
|
+
serialize(event: unknown): string;
|
|
18
|
+
deserialize(serialized: string, eventType: string): unknown;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=json-event-serializer.d.ts.map
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.JsonEventSerializer = void 0;
|
|
13
|
+
const common_1 = require("@nestjs/common");
|
|
14
|
+
const errors_1 = require("../types/errors");
|
|
15
|
+
const event_type_registry_1 = require("./event-type-registry");
|
|
16
|
+
/**
|
|
17
|
+
* Default JSON-based {@link EventSerializer}. Uses `JSON.stringify` for
|
|
18
|
+
* encoding and `JSON.parse` + `Object.create` for decoding, consulting
|
|
19
|
+
* an {@link EventTypeRegistry} to restore the class prototype when
|
|
20
|
+
* possible.
|
|
21
|
+
*
|
|
22
|
+
* This implementation is intentionally simple: it restores the
|
|
23
|
+
* prototype but does not call the constructor, so classes with private
|
|
24
|
+
* fields, Value-Object invariants, or custom deserialization must
|
|
25
|
+
* provide their own `EventSerializer`.
|
|
26
|
+
*/
|
|
27
|
+
let JsonEventSerializer = class JsonEventSerializer {
|
|
28
|
+
registry;
|
|
29
|
+
constructor(registry) {
|
|
30
|
+
this.registry = registry;
|
|
31
|
+
}
|
|
32
|
+
serialize(event) {
|
|
33
|
+
if (!event || typeof event !== 'object') {
|
|
34
|
+
throw new errors_1.SerializationError(`Cannot serialize non-object: ${typeof event}`);
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
return JSON.stringify(event);
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
throw new errors_1.SerializationError(`Failed to serialize event: ${err.message}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
deserialize(serialized, eventType) {
|
|
44
|
+
const EventClass = this.registry.get(eventType);
|
|
45
|
+
let data;
|
|
46
|
+
try {
|
|
47
|
+
data = JSON.parse(serialized);
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
throw new errors_1.DeserializationError(`Failed to deserialize event '${eventType}': ${err.message}`);
|
|
51
|
+
}
|
|
52
|
+
if (!EventClass) {
|
|
53
|
+
return data;
|
|
54
|
+
}
|
|
55
|
+
const prototype = EventClass.prototype;
|
|
56
|
+
return Object.assign(Object.create(prototype), data);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
exports.JsonEventSerializer = JsonEventSerializer;
|
|
60
|
+
exports.JsonEventSerializer = JsonEventSerializer = __decorate([
|
|
61
|
+
(0, common_1.Injectable)(),
|
|
62
|
+
__metadata("design:paramtypes", [event_type_registry_1.EventTypeRegistry])
|
|
63
|
+
], JsonEventSerializer);
|
|
64
|
+
//# sourceMappingURL=json-event-serializer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-event-serializer.js","sourceRoot":"","sources":["../../src/serialization/json-event-serializer.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA4C;AAE5C,4CAA2E;AAG3E,+DAA0D;AAE1D;;;;;;;;;;GAUG;AAEI,IAAM,mBAAmB,GAAzB,MAAM,mBAAmB;IACD;IAA7B,YAA6B,QAA2B;QAA3B,aAAQ,GAAR,QAAQ,CAAmB;IAAG,CAAC;IAE5D,SAAS,CAAC,KAAc;QACtB,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YACxC,MAAM,IAAI,2BAAkB,CAAC,gCAAgC,OAAO,KAAK,EAAE,CAAC,CAAC;QAC/E,CAAC;QACD,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC/B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,2BAAkB,CAC1B,8BAA+B,GAAa,CAAC,OAAO,EAAE,CACvD,CAAC;QACJ,CAAC;IACH,CAAC;IAED,WAAW,CAAC,UAAkB,EAAE,SAAiB;QAC/C,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAEhD,IAAI,IAAa,CAAC;QAClB,IAAI,CAAC;YACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAChC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,6BAAoB,CAC5B,gCAAgC,SAAS,MAAO,GAAa,CAAC,OAAO,EAAE,CACxE,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,SAAS,GAAW,UAAU,CAAC,SAAmB,CAAC;QACzD,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAW,EAAE,IAAI,CAAC,CAAC;IACjE,CAAC;CACF,CAAA;AAnCY,kDAAmB;8BAAnB,mBAAmB;IAD/B,IAAA,mBAAU,GAAE;qCAE4B,uCAAiB;GAD7C,mBAAmB,CAmC/B"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { type Type } from '@nestjs/common';
|
|
2
|
+
import { PublishedEvents, type PublishedEventsView } from './published-events';
|
|
3
|
+
/**
|
|
4
|
+
* Thrown when an assertion made against the published-events view does
|
|
5
|
+
* not hold. A separate class (instead of a plain `Error`) so tests can
|
|
6
|
+
* pattern-match with `rejects.toBeInstanceOf(PublishedEventsAssertionError)`
|
|
7
|
+
* when they want to assert on failure modes.
|
|
8
|
+
*/
|
|
9
|
+
export declare class PublishedEventsAssertionError extends Error {
|
|
10
|
+
constructor(message: string);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Jest-friendly fluent assertions over {@link PublishedEvents}. Inspired
|
|
14
|
+
* by Spring Modulith's `AssertablePublishedEvents`. Designed to read
|
|
15
|
+
* naturally at the call site:
|
|
16
|
+
*
|
|
17
|
+
* ```ts
|
|
18
|
+
* const view = await assertablePublishedEvents.contains(OrderPlacedEvent);
|
|
19
|
+
* view.matching((e) => e.orderId, 'order-123').hasSize(1);
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* Both assertions throw {@link PublishedEventsAssertionError} on
|
|
23
|
+
* failure, which Jest renders as a normal test failure.
|
|
24
|
+
*/
|
|
25
|
+
export declare class AssertablePublishedEvents {
|
|
26
|
+
private readonly events;
|
|
27
|
+
constructor(events: PublishedEvents);
|
|
28
|
+
/**
|
|
29
|
+
* Assert that at least one event of the given class was published,
|
|
30
|
+
* then return a view over those events for further assertions.
|
|
31
|
+
*
|
|
32
|
+
* @throws {PublishedEventsAssertionError} when no matching event
|
|
33
|
+
* was published.
|
|
34
|
+
*/
|
|
35
|
+
contains<T extends object>(eventType: Type<T>): Promise<AssertionView<T>>;
|
|
36
|
+
/**
|
|
37
|
+
* Assert that NO event of the given class was published.
|
|
38
|
+
*
|
|
39
|
+
* @throws {PublishedEventsAssertionError} when one or more matching
|
|
40
|
+
* events were published.
|
|
41
|
+
*/
|
|
42
|
+
doesNotContain<T extends object>(eventType: Type<T>): Promise<void>;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Materialised, filtered view returned by
|
|
46
|
+
* {@link AssertablePublishedEvents.contains}. Further filtering /
|
|
47
|
+
* sizing runs in memory — no additional repository reads.
|
|
48
|
+
*/
|
|
49
|
+
export declare class AssertionView<T extends object> {
|
|
50
|
+
private readonly view;
|
|
51
|
+
private readonly events;
|
|
52
|
+
private readonly eventType;
|
|
53
|
+
constructor(view: PublishedEventsView<T>, events: readonly T[], eventType: Type<T>);
|
|
54
|
+
/**
|
|
55
|
+
* Narrow the view to events whose derived value equals `expected`.
|
|
56
|
+
* Returns a new {@link AssertionView} so assertions can chain.
|
|
57
|
+
*
|
|
58
|
+
* @throws {PublishedEventsAssertionError} when no event in the
|
|
59
|
+
* current view matches.
|
|
60
|
+
*/
|
|
61
|
+
matching<K>(getter: (event: T) => K, expected: K): AssertionView<T>;
|
|
62
|
+
/**
|
|
63
|
+
* Assert the view contains exactly `expected` events.
|
|
64
|
+
*
|
|
65
|
+
* @throws {PublishedEventsAssertionError} when the count differs.
|
|
66
|
+
*/
|
|
67
|
+
hasSize(expected: number): this;
|
|
68
|
+
/** Read the current events. Useful for ad-hoc assertions with Jest's matchers. */
|
|
69
|
+
toArray(): T[];
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=assertable-published-events.d.ts.map
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.AssertionView = exports.AssertablePublishedEvents = exports.PublishedEventsAssertionError = void 0;
|
|
13
|
+
const common_1 = require("@nestjs/common");
|
|
14
|
+
const published_events_1 = require("./published-events");
|
|
15
|
+
/**
|
|
16
|
+
* Thrown when an assertion made against the published-events view does
|
|
17
|
+
* not hold. A separate class (instead of a plain `Error`) so tests can
|
|
18
|
+
* pattern-match with `rejects.toBeInstanceOf(PublishedEventsAssertionError)`
|
|
19
|
+
* when they want to assert on failure modes.
|
|
20
|
+
*/
|
|
21
|
+
class PublishedEventsAssertionError extends Error {
|
|
22
|
+
constructor(message) {
|
|
23
|
+
super(message);
|
|
24
|
+
this.name = 'PublishedEventsAssertionError';
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
exports.PublishedEventsAssertionError = PublishedEventsAssertionError;
|
|
28
|
+
/**
|
|
29
|
+
* Jest-friendly fluent assertions over {@link PublishedEvents}. Inspired
|
|
30
|
+
* by Spring Modulith's `AssertablePublishedEvents`. Designed to read
|
|
31
|
+
* naturally at the call site:
|
|
32
|
+
*
|
|
33
|
+
* ```ts
|
|
34
|
+
* const view = await assertablePublishedEvents.contains(OrderPlacedEvent);
|
|
35
|
+
* view.matching((e) => e.orderId, 'order-123').hasSize(1);
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* Both assertions throw {@link PublishedEventsAssertionError} on
|
|
39
|
+
* failure, which Jest renders as a normal test failure.
|
|
40
|
+
*/
|
|
41
|
+
let AssertablePublishedEvents = class AssertablePublishedEvents {
|
|
42
|
+
events;
|
|
43
|
+
constructor(events) {
|
|
44
|
+
this.events = events;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Assert that at least one event of the given class was published,
|
|
48
|
+
* then return a view over those events for further assertions.
|
|
49
|
+
*
|
|
50
|
+
* @throws {PublishedEventsAssertionError} when no matching event
|
|
51
|
+
* was published.
|
|
52
|
+
*/
|
|
53
|
+
async contains(eventType) {
|
|
54
|
+
const view = this.events.ofType(eventType);
|
|
55
|
+
const events = await view.get();
|
|
56
|
+
if (events.length === 0) {
|
|
57
|
+
throw new PublishedEventsAssertionError(`Expected at least one event of type ${eventType.name}, but found none`);
|
|
58
|
+
}
|
|
59
|
+
return new AssertionView(view, events, eventType);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Assert that NO event of the given class was published.
|
|
63
|
+
*
|
|
64
|
+
* @throws {PublishedEventsAssertionError} when one or more matching
|
|
65
|
+
* events were published.
|
|
66
|
+
*/
|
|
67
|
+
async doesNotContain(eventType) {
|
|
68
|
+
const events = await this.events.ofType(eventType).get();
|
|
69
|
+
if (events.length > 0) {
|
|
70
|
+
throw new PublishedEventsAssertionError(`Expected no events of type ${eventType.name}, but found ${events.length}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
exports.AssertablePublishedEvents = AssertablePublishedEvents;
|
|
75
|
+
exports.AssertablePublishedEvents = AssertablePublishedEvents = __decorate([
|
|
76
|
+
(0, common_1.Injectable)(),
|
|
77
|
+
__metadata("design:paramtypes", [published_events_1.PublishedEvents])
|
|
78
|
+
], AssertablePublishedEvents);
|
|
79
|
+
/**
|
|
80
|
+
* Materialised, filtered view returned by
|
|
81
|
+
* {@link AssertablePublishedEvents.contains}. Further filtering /
|
|
82
|
+
* sizing runs in memory — no additional repository reads.
|
|
83
|
+
*/
|
|
84
|
+
class AssertionView {
|
|
85
|
+
view;
|
|
86
|
+
events;
|
|
87
|
+
eventType;
|
|
88
|
+
constructor(view, events, eventType) {
|
|
89
|
+
this.view = view;
|
|
90
|
+
this.events = events;
|
|
91
|
+
this.eventType = eventType;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Narrow the view to events whose derived value equals `expected`.
|
|
95
|
+
* Returns a new {@link AssertionView} so assertions can chain.
|
|
96
|
+
*
|
|
97
|
+
* @throws {PublishedEventsAssertionError} when no event in the
|
|
98
|
+
* current view matches.
|
|
99
|
+
*/
|
|
100
|
+
matching(getter, expected) {
|
|
101
|
+
const filtered = this.events.filter((event) => getter(event) === expected);
|
|
102
|
+
if (filtered.length === 0) {
|
|
103
|
+
throw new PublishedEventsAssertionError(`Expected at least one event of type ${this.eventType.name} matching the predicate, but none found`);
|
|
104
|
+
}
|
|
105
|
+
return new AssertionView(this.view, filtered, this.eventType);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Assert the view contains exactly `expected` events.
|
|
109
|
+
*
|
|
110
|
+
* @throws {PublishedEventsAssertionError} when the count differs.
|
|
111
|
+
*/
|
|
112
|
+
hasSize(expected) {
|
|
113
|
+
if (this.events.length !== expected) {
|
|
114
|
+
throw new PublishedEventsAssertionError(`Expected ${expected} events of type ${this.eventType.name}, but found ${this.events.length}`);
|
|
115
|
+
}
|
|
116
|
+
return this;
|
|
117
|
+
}
|
|
118
|
+
/** Read the current events. Useful for ad-hoc assertions with Jest's matchers. */
|
|
119
|
+
toArray() {
|
|
120
|
+
return [...this.events];
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
exports.AssertionView = AssertionView;
|
|
124
|
+
//# sourceMappingURL=assertable-published-events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assertable-published-events.js","sourceRoot":"","sources":["../../src/testing/assertable-published-events.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAAuD;AAEvD,yDAA+E;AAE/E;;;;;GAKG;AACH,MAAa,6BAA8B,SAAQ,KAAK;IACtD,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,+BAA+B,CAAC;IAC9C,CAAC;CACF;AALD,sEAKC;AAED;;;;;;;;;;;;GAYG;AAEI,IAAM,yBAAyB,GAA/B,MAAM,yBAAyB;IACP;IAA7B,YAA6B,MAAuB;QAAvB,WAAM,GAAN,MAAM,CAAiB;IAAG,CAAC;IAExD;;;;;;OAMG;IACH,KAAK,CAAC,QAAQ,CAAmB,SAAkB;QACjD,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAC3C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC;QAChC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,MAAM,IAAI,6BAA6B,CACrC,uCAAuC,SAAS,CAAC,IAAI,kBAAkB,CACxE,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,aAAa,CAAI,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;IACvD,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,cAAc,CAAmB,SAAkB;QACvD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,GAAG,EAAE,CAAC;QACzD,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,MAAM,IAAI,6BAA6B,CACrC,8BAA8B,SAAS,CAAC,IAAI,eAAe,MAAM,CAAC,MAAM,EAAE,CAC3E,CAAC;QACJ,CAAC;IACH,CAAC;CACF,CAAA;AAnCY,8DAAyB;oCAAzB,yBAAyB;IADrC,IAAA,mBAAU,GAAE;qCAE0B,kCAAe;GADzC,yBAAyB,CAmCrC;AAED;;;;GAIG;AACH,MAAa,aAAa;IAEL;IACA;IACA;IAHnB,YACmB,IAA4B,EAC5B,MAAoB,EACpB,SAAkB;QAFlB,SAAI,GAAJ,IAAI,CAAwB;QAC5B,WAAM,GAAN,MAAM,CAAc;QACpB,cAAS,GAAT,SAAS,CAAS;IAClC,CAAC;IAEJ;;;;;;OAMG;IACH,QAAQ,CAAI,MAAuB,EAAE,QAAW;QAC9C,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,QAAQ,CAAC,CAAC;QAC3E,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,6BAA6B,CACrC,uCAAuC,IAAI,CAAC,SAAS,CAAC,IAAI,yCAAyC,CACpG,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,aAAa,CAAI,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IACnE,CAAC;IAED;;;;OAIG;IACH,OAAO,CAAC,QAAgB;QACtB,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YACpC,MAAM,IAAI,6BAA6B,CACrC,YAAY,QAAQ,mBAAmB,IAAI,CAAC,SAAS,CAAC,IAAI,eAAe,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAC9F,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,kFAAkF;IAClF,OAAO;QACL,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;IAC1B,CAAC;CACF;AA1CD,sCA0CC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { TransactionManager } from '@nestjs-transactional/core';
|
|
2
|
+
import type { EventPublicationRepository, FindCompletedOptions, FindFailedOptions, UpdateStatusOptions } from '../repository/event-publication-repository';
|
|
3
|
+
import type { EventPublication, NewEventPublication } from '../types/event-publication';
|
|
4
|
+
import { PublicationStatus } from '../types/publication-status';
|
|
5
|
+
/**
|
|
6
|
+
* In-memory reference implementation of {@link EventPublicationRepository}.
|
|
7
|
+
*
|
|
8
|
+
* Intended for unit and integration tests of outbox consumers that
|
|
9
|
+
* do not want to spin up a real database. Not thread-safe — do not use
|
|
10
|
+
* in production.
|
|
11
|
+
*
|
|
12
|
+
* Optional `TransactionManager` enables transaction-aware behaviour:
|
|
13
|
+
* when a mutating method is called inside an active transaction, the
|
|
14
|
+
* repository registers an `afterRollback` hook that undoes the change
|
|
15
|
+
* — so the visible state after rollback matches what a real
|
|
16
|
+
* transactional backend would show. When no `TransactionManager` is
|
|
17
|
+
* provided (or no transaction is active), mutations apply immediately
|
|
18
|
+
* and are not undone.
|
|
19
|
+
*
|
|
20
|
+
* Exposes a few extra methods beyond the SPI (`reset`, `getAll`,
|
|
21
|
+
* `count`) to help tests set up and assert on state.
|
|
22
|
+
*/
|
|
23
|
+
export declare class InMemoryEventPublicationRepository implements EventPublicationRepository {
|
|
24
|
+
private readonly transactionManager?;
|
|
25
|
+
private readonly publications;
|
|
26
|
+
constructor(transactionManager?: TransactionManager | undefined);
|
|
27
|
+
createAll(inputs: NewEventPublication[]): Promise<EventPublication[]>;
|
|
28
|
+
findById(id: string): Promise<EventPublication | null>;
|
|
29
|
+
updateStatus(id: string, status: PublicationStatus, options?: UpdateStatusOptions): Promise<void>;
|
|
30
|
+
tryClaim(id: string): Promise<boolean>;
|
|
31
|
+
findReadyForProcessing(limit: number): Promise<EventPublication[]>;
|
|
32
|
+
findStale(beforeDate: Date, statuses: PublicationStatus[]): Promise<EventPublication[]>;
|
|
33
|
+
findCompleted(options?: FindCompletedOptions): Promise<EventPublication[]>;
|
|
34
|
+
findIncomplete(): Promise<EventPublication[]>;
|
|
35
|
+
findFailed(options?: FindFailedOptions): Promise<EventPublication[]>;
|
|
36
|
+
deleteCompleted(olderThan?: Date): Promise<number>;
|
|
37
|
+
archiveCompleted(id: string): Promise<void>;
|
|
38
|
+
delete(id: string): Promise<void>;
|
|
39
|
+
/** Drop every stored publication. Does not interact with transactions. */
|
|
40
|
+
reset(): void;
|
|
41
|
+
/** Snapshot of every stored publication, in insertion order. */
|
|
42
|
+
getAll(): EventPublication[];
|
|
43
|
+
/** Number of stored publications. */
|
|
44
|
+
count(): number;
|
|
45
|
+
/**
|
|
46
|
+
* If a `TransactionManager` was provided and a transaction is active,
|
|
47
|
+
* register the given `undo` closure to fire on rollback. Otherwise
|
|
48
|
+
* this is a no-op.
|
|
49
|
+
*/
|
|
50
|
+
private trackRollback;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=in-memory-repository.d.ts.map
|