@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,230 @@
|
|
|
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
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.InMemoryEventPublicationRepository = void 0;
|
|
16
|
+
/* eslint-disable @typescript-eslint/require-await --
|
|
17
|
+
* This in-memory reference implementation has synchronous method
|
|
18
|
+
* bodies but must return Promises per the EventPublicationRepository
|
|
19
|
+
* SPI contract. Real persistence backends (TypeORM, Prisma, ...) will
|
|
20
|
+
* have awaits throughout.
|
|
21
|
+
*/
|
|
22
|
+
const node_crypto_1 = require("node:crypto");
|
|
23
|
+
const common_1 = require("@nestjs/common");
|
|
24
|
+
const core_1 = require("@nestjs-transactional/core");
|
|
25
|
+
const errors_1 = require("../types/errors");
|
|
26
|
+
const publication_status_1 = require("../types/publication-status");
|
|
27
|
+
/**
|
|
28
|
+
* In-memory reference implementation of {@link EventPublicationRepository}.
|
|
29
|
+
*
|
|
30
|
+
* Intended for unit and integration tests of outbox consumers that
|
|
31
|
+
* do not want to spin up a real database. Not thread-safe — do not use
|
|
32
|
+
* in production.
|
|
33
|
+
*
|
|
34
|
+
* Optional `TransactionManager` enables transaction-aware behaviour:
|
|
35
|
+
* when a mutating method is called inside an active transaction, the
|
|
36
|
+
* repository registers an `afterRollback` hook that undoes the change
|
|
37
|
+
* — so the visible state after rollback matches what a real
|
|
38
|
+
* transactional backend would show. When no `TransactionManager` is
|
|
39
|
+
* provided (or no transaction is active), mutations apply immediately
|
|
40
|
+
* and are not undone.
|
|
41
|
+
*
|
|
42
|
+
* Exposes a few extra methods beyond the SPI (`reset`, `getAll`,
|
|
43
|
+
* `count`) to help tests set up and assert on state.
|
|
44
|
+
*/
|
|
45
|
+
let InMemoryEventPublicationRepository = class InMemoryEventPublicationRepository {
|
|
46
|
+
transactionManager;
|
|
47
|
+
publications = new Map();
|
|
48
|
+
constructor(transactionManager) {
|
|
49
|
+
this.transactionManager = transactionManager;
|
|
50
|
+
}
|
|
51
|
+
async createAll(inputs) {
|
|
52
|
+
const created = [];
|
|
53
|
+
for (const input of inputs) {
|
|
54
|
+
const publication = {
|
|
55
|
+
id: (0, node_crypto_1.randomUUID)(),
|
|
56
|
+
listenerId: input.listenerId,
|
|
57
|
+
eventType: input.eventType,
|
|
58
|
+
serializedEvent: input.serializedEvent,
|
|
59
|
+
publicationDate: input.publicationDate ?? new Date(),
|
|
60
|
+
status: publication_status_1.PublicationStatus.PUBLISHED,
|
|
61
|
+
completionDate: null,
|
|
62
|
+
lastResubmissionDate: null,
|
|
63
|
+
completionAttempts: 0,
|
|
64
|
+
failureReason: null,
|
|
65
|
+
};
|
|
66
|
+
this.publications.set(publication.id, publication);
|
|
67
|
+
created.push(publication);
|
|
68
|
+
}
|
|
69
|
+
this.trackRollback(() => {
|
|
70
|
+
for (const p of created) {
|
|
71
|
+
this.publications.delete(p.id);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
return created;
|
|
75
|
+
}
|
|
76
|
+
async findById(id) {
|
|
77
|
+
return this.publications.get(id) ?? null;
|
|
78
|
+
}
|
|
79
|
+
async updateStatus(id, status, options = {}) {
|
|
80
|
+
const existing = this.publications.get(id);
|
|
81
|
+
if (!existing) {
|
|
82
|
+
throw new errors_1.PublicationNotFoundError(id);
|
|
83
|
+
}
|
|
84
|
+
const updated = {
|
|
85
|
+
...existing,
|
|
86
|
+
status,
|
|
87
|
+
completionDate: options.completionDate ?? existing.completionDate,
|
|
88
|
+
failureReason: options.failureReason ?? existing.failureReason,
|
|
89
|
+
completionAttempts: options.incrementAttempts
|
|
90
|
+
? existing.completionAttempts + 1
|
|
91
|
+
: existing.completionAttempts,
|
|
92
|
+
lastResubmissionDate: options.lastResubmissionDate ?? existing.lastResubmissionDate,
|
|
93
|
+
};
|
|
94
|
+
this.publications.set(id, updated);
|
|
95
|
+
this.trackRollback(() => {
|
|
96
|
+
this.publications.set(id, existing);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
async tryClaim(id) {
|
|
100
|
+
const existing = this.publications.get(id);
|
|
101
|
+
if (!existing) {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
if (existing.status !== publication_status_1.PublicationStatus.PUBLISHED &&
|
|
105
|
+
existing.status !== publication_status_1.PublicationStatus.RESUBMITTED) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
await this.updateStatus(id, publication_status_1.PublicationStatus.PROCESSING, { incrementAttempts: true });
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
async findReadyForProcessing(limit) {
|
|
112
|
+
return Array.from(this.publications.values())
|
|
113
|
+
.filter((p) => p.status === publication_status_1.PublicationStatus.PUBLISHED ||
|
|
114
|
+
p.status === publication_status_1.PublicationStatus.RESUBMITTED)
|
|
115
|
+
.slice(0, limit);
|
|
116
|
+
}
|
|
117
|
+
async findStale(beforeDate, statuses) {
|
|
118
|
+
return Array.from(this.publications.values()).filter((p) => statuses.includes(p.status) && p.publicationDate < beforeDate);
|
|
119
|
+
}
|
|
120
|
+
async findCompleted(options) {
|
|
121
|
+
let result = Array.from(this.publications.values()).filter((p) => p.status === publication_status_1.PublicationStatus.COMPLETED);
|
|
122
|
+
const olderThan = options?.olderThan;
|
|
123
|
+
if (olderThan) {
|
|
124
|
+
result = result.filter((p) => p.completionDate !== null && p.completionDate < olderThan);
|
|
125
|
+
}
|
|
126
|
+
const limit = options?.limit;
|
|
127
|
+
if (limit !== undefined) {
|
|
128
|
+
result = result.slice(0, limit);
|
|
129
|
+
}
|
|
130
|
+
return result;
|
|
131
|
+
}
|
|
132
|
+
async findIncomplete() {
|
|
133
|
+
return Array.from(this.publications.values()).filter((p) => p.status !== publication_status_1.PublicationStatus.COMPLETED);
|
|
134
|
+
}
|
|
135
|
+
async findFailed(options) {
|
|
136
|
+
let result = Array.from(this.publications.values()).filter((p) => p.status === publication_status_1.PublicationStatus.FAILED);
|
|
137
|
+
const minAge = options?.minAge;
|
|
138
|
+
if (minAge) {
|
|
139
|
+
const threshold = new Date(Date.now() - minAge);
|
|
140
|
+
result = result.filter((p) => p.publicationDate < threshold);
|
|
141
|
+
}
|
|
142
|
+
const maxAttempts = options?.maxAttempts;
|
|
143
|
+
if (maxAttempts !== undefined) {
|
|
144
|
+
result = result.filter((p) => p.completionAttempts <= maxAttempts);
|
|
145
|
+
}
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
async deleteCompleted(olderThan) {
|
|
149
|
+
const deleted = [];
|
|
150
|
+
for (const [id, p] of this.publications.entries()) {
|
|
151
|
+
if (p.status !== publication_status_1.PublicationStatus.COMPLETED) {
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
if (olderThan && (p.completionDate === null || p.completionDate >= olderThan)) {
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
deleted.push([id, p]);
|
|
158
|
+
}
|
|
159
|
+
for (const [id] of deleted) {
|
|
160
|
+
this.publications.delete(id);
|
|
161
|
+
}
|
|
162
|
+
if (deleted.length > 0) {
|
|
163
|
+
this.trackRollback(() => {
|
|
164
|
+
for (const [id, p] of deleted) {
|
|
165
|
+
this.publications.set(id, p);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
return deleted.length;
|
|
170
|
+
}
|
|
171
|
+
async archiveCompleted(id) {
|
|
172
|
+
const existing = this.publications.get(id);
|
|
173
|
+
this.publications.delete(id);
|
|
174
|
+
if (existing !== undefined) {
|
|
175
|
+
this.trackRollback(() => {
|
|
176
|
+
this.publications.set(id, existing);
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
async delete(id) {
|
|
181
|
+
const existing = this.publications.get(id);
|
|
182
|
+
this.publications.delete(id);
|
|
183
|
+
if (existing !== undefined) {
|
|
184
|
+
this.trackRollback(() => {
|
|
185
|
+
this.publications.set(id, existing);
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
// --- Testing helpers (not part of the SPI) ---
|
|
190
|
+
/** Drop every stored publication. Does not interact with transactions. */
|
|
191
|
+
reset() {
|
|
192
|
+
this.publications.clear();
|
|
193
|
+
}
|
|
194
|
+
/** Snapshot of every stored publication, in insertion order. */
|
|
195
|
+
getAll() {
|
|
196
|
+
return Array.from(this.publications.values());
|
|
197
|
+
}
|
|
198
|
+
/** Number of stored publications. */
|
|
199
|
+
count() {
|
|
200
|
+
return this.publications.size;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* If a `TransactionManager` was provided and a transaction is active,
|
|
204
|
+
* register the given `undo` closure to fire on rollback. Otherwise
|
|
205
|
+
* this is a no-op.
|
|
206
|
+
*/
|
|
207
|
+
trackRollback(undo) {
|
|
208
|
+
if (this.transactionManager === undefined) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
try {
|
|
212
|
+
this.transactionManager.registerAfterRollback(async () => {
|
|
213
|
+
undo();
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
catch (err) {
|
|
217
|
+
if (err instanceof core_1.IllegalTransactionStateError) {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
throw err;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
exports.InMemoryEventPublicationRepository = InMemoryEventPublicationRepository;
|
|
225
|
+
exports.InMemoryEventPublicationRepository = InMemoryEventPublicationRepository = __decorate([
|
|
226
|
+
(0, common_1.Injectable)(),
|
|
227
|
+
__param(0, (0, common_1.Optional)()),
|
|
228
|
+
__metadata("design:paramtypes", [core_1.TransactionManager])
|
|
229
|
+
], InMemoryEventPublicationRepository);
|
|
230
|
+
//# sourceMappingURL=in-memory-repository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"in-memory-repository.js","sourceRoot":"","sources":["../../src/testing/in-memory-repository.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./in-memory-repository"), exports);
|
|
18
|
+
__exportStar(require("./published-events"), exports);
|
|
19
|
+
__exportStar(require("./assertable-published-events"), exports);
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,yDAAuC;AACvC,qDAAmC;AACnC,gEAA8C"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { type Type } from '@nestjs/common';
|
|
2
|
+
import { type EventPublicationRepository } from '../repository/event-publication-repository';
|
|
3
|
+
import { type EventSerializer } from '../serialization/event-serializer';
|
|
4
|
+
import type { EventPublication } from '../types/event-publication';
|
|
5
|
+
/**
|
|
6
|
+
* Test utility for inspecting events that were published through the
|
|
7
|
+
* outbox during a test run.
|
|
8
|
+
*
|
|
9
|
+
* Inspired by Spring Modulith's `PublishedEvents`. Reads from whichever
|
|
10
|
+
* `EventPublicationRepository` implementation is wired — typically
|
|
11
|
+
* {@link InMemoryEventPublicationRepository} for unit-level tests, or
|
|
12
|
+
* the TypeORM-backed repository for integration tests against a real
|
|
13
|
+
* database. The events are deserialized back into application objects
|
|
14
|
+
* via the configured {@link EventSerializer} so tests can assert on
|
|
15
|
+
* the same typed payloads the listeners would receive.
|
|
16
|
+
*/
|
|
17
|
+
export declare class PublishedEvents {
|
|
18
|
+
private readonly repository;
|
|
19
|
+
private readonly serializer;
|
|
20
|
+
constructor(repository: EventPublicationRepository, serializer: EventSerializer);
|
|
21
|
+
/**
|
|
22
|
+
* Every publication visible to the repository, regardless of status.
|
|
23
|
+
* Events are returned as deserialized application objects. Ordering
|
|
24
|
+
* mirrors the repository's own — typically insertion order for the
|
|
25
|
+
* in-memory impl, unspecified for SQL-backed ones.
|
|
26
|
+
*/
|
|
27
|
+
all(): Promise<unknown[]>;
|
|
28
|
+
/**
|
|
29
|
+
* Narrow the view to events of a specific class. Subsequent
|
|
30
|
+
* `matching(...)` / `count()` / `get()` calls filter only within
|
|
31
|
+
* that class.
|
|
32
|
+
*/
|
|
33
|
+
ofType<T extends object>(eventType: Type<T>): PublishedEventsView<T>;
|
|
34
|
+
private collectAll;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Fluent filter view returned by {@link PublishedEvents.ofType}. Each
|
|
38
|
+
* `matching(...)` call produces a new view with the extra predicate
|
|
39
|
+
* appended — predicates are conjunctive (all must hold). Materialise
|
|
40
|
+
* the view with `get()` or `count()`.
|
|
41
|
+
*/
|
|
42
|
+
export declare class PublishedEventsView<T extends object> {
|
|
43
|
+
private readonly fetchAll;
|
|
44
|
+
private readonly serializer;
|
|
45
|
+
private readonly eventType;
|
|
46
|
+
private readonly predicates;
|
|
47
|
+
constructor(fetchAll: () => Promise<EventPublication[]>, serializer: EventSerializer, eventType: Type<T>, predicates: readonly ((event: T) => boolean)[]);
|
|
48
|
+
/**
|
|
49
|
+
* Filter on a boolean predicate over the deserialized event.
|
|
50
|
+
*/
|
|
51
|
+
matching(predicate: (event: T) => boolean): PublishedEventsView<T>;
|
|
52
|
+
/**
|
|
53
|
+
* Filter on equality of a derived value. Equivalent to
|
|
54
|
+
* `matching((e) => getter(e) === expected)` but cheaper to read.
|
|
55
|
+
*/
|
|
56
|
+
matching<K>(getter: (event: T) => K, expected: K): PublishedEventsView<T>;
|
|
57
|
+
/** Number of matching events. Materialises the view. */
|
|
58
|
+
count(): Promise<number>;
|
|
59
|
+
/** Deserialized, filtered events. Materialises the view. */
|
|
60
|
+
get(): Promise<T[]>;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=published-events.d.ts.map
|
|
@@ -0,0 +1,110 @@
|
|
|
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
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.PublishedEventsView = exports.PublishedEvents = void 0;
|
|
16
|
+
const common_1 = require("@nestjs/common");
|
|
17
|
+
const event_publication_repository_1 = require("../repository/event-publication-repository");
|
|
18
|
+
const event_serializer_1 = require("../serialization/event-serializer");
|
|
19
|
+
/**
|
|
20
|
+
* Test utility for inspecting events that were published through the
|
|
21
|
+
* outbox during a test run.
|
|
22
|
+
*
|
|
23
|
+
* Inspired by Spring Modulith's `PublishedEvents`. Reads from whichever
|
|
24
|
+
* `EventPublicationRepository` implementation is wired — typically
|
|
25
|
+
* {@link InMemoryEventPublicationRepository} for unit-level tests, or
|
|
26
|
+
* the TypeORM-backed repository for integration tests against a real
|
|
27
|
+
* database. The events are deserialized back into application objects
|
|
28
|
+
* via the configured {@link EventSerializer} so tests can assert on
|
|
29
|
+
* the same typed payloads the listeners would receive.
|
|
30
|
+
*/
|
|
31
|
+
let PublishedEvents = class PublishedEvents {
|
|
32
|
+
repository;
|
|
33
|
+
serializer;
|
|
34
|
+
constructor(repository, serializer) {
|
|
35
|
+
this.repository = repository;
|
|
36
|
+
this.serializer = serializer;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Every publication visible to the repository, regardless of status.
|
|
40
|
+
* Events are returned as deserialized application objects. Ordering
|
|
41
|
+
* mirrors the repository's own — typically insertion order for the
|
|
42
|
+
* in-memory impl, unspecified for SQL-backed ones.
|
|
43
|
+
*/
|
|
44
|
+
async all() {
|
|
45
|
+
const rows = await this.collectAll();
|
|
46
|
+
return rows.map((pub) => this.serializer.deserialize(pub.serializedEvent, pub.eventType));
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Narrow the view to events of a specific class. Subsequent
|
|
50
|
+
* `matching(...)` / `count()` / `get()` calls filter only within
|
|
51
|
+
* that class.
|
|
52
|
+
*/
|
|
53
|
+
ofType(eventType) {
|
|
54
|
+
return new PublishedEventsView(() => this.collectAll(), this.serializer, eventType, []);
|
|
55
|
+
}
|
|
56
|
+
async collectAll() {
|
|
57
|
+
const [incomplete, completed] = await Promise.all([
|
|
58
|
+
this.repository.findIncomplete(),
|
|
59
|
+
this.repository.findCompleted(),
|
|
60
|
+
]);
|
|
61
|
+
return [...incomplete, ...completed];
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
exports.PublishedEvents = PublishedEvents;
|
|
65
|
+
exports.PublishedEvents = PublishedEvents = __decorate([
|
|
66
|
+
(0, common_1.Injectable)(),
|
|
67
|
+
__param(0, (0, common_1.Inject)(event_publication_repository_1.EVENT_PUBLICATION_REPOSITORY)),
|
|
68
|
+
__param(1, (0, common_1.Inject)(event_serializer_1.EVENT_SERIALIZER)),
|
|
69
|
+
__metadata("design:paramtypes", [Object, Object])
|
|
70
|
+
], PublishedEvents);
|
|
71
|
+
/**
|
|
72
|
+
* Fluent filter view returned by {@link PublishedEvents.ofType}. Each
|
|
73
|
+
* `matching(...)` call produces a new view with the extra predicate
|
|
74
|
+
* appended — predicates are conjunctive (all must hold). Materialise
|
|
75
|
+
* the view with `get()` or `count()`.
|
|
76
|
+
*/
|
|
77
|
+
class PublishedEventsView {
|
|
78
|
+
fetchAll;
|
|
79
|
+
serializer;
|
|
80
|
+
eventType;
|
|
81
|
+
predicates;
|
|
82
|
+
constructor(fetchAll, serializer, eventType, predicates) {
|
|
83
|
+
this.fetchAll = fetchAll;
|
|
84
|
+
this.serializer = serializer;
|
|
85
|
+
this.eventType = eventType;
|
|
86
|
+
this.predicates = predicates;
|
|
87
|
+
}
|
|
88
|
+
matching(fnOrGetter, expected) {
|
|
89
|
+
// eslint-disable-next-line prefer-rest-params -- arguments.length distinguishes the two overloads reliably, including when `expected` is intentionally `undefined`.
|
|
90
|
+
const argCount = arguments.length;
|
|
91
|
+
const predicate = argCount > 1
|
|
92
|
+
? (event) => fnOrGetter(event) === expected
|
|
93
|
+
: fnOrGetter;
|
|
94
|
+
return new PublishedEventsView(this.fetchAll, this.serializer, this.eventType, [...this.predicates, predicate]);
|
|
95
|
+
}
|
|
96
|
+
/** Number of matching events. Materialises the view. */
|
|
97
|
+
async count() {
|
|
98
|
+
return (await this.get()).length;
|
|
99
|
+
}
|
|
100
|
+
/** Deserialized, filtered events. Materialises the view. */
|
|
101
|
+
async get() {
|
|
102
|
+
const rows = await this.fetchAll();
|
|
103
|
+
const typed = rows
|
|
104
|
+
.filter((pub) => pub.eventType === this.eventType.name)
|
|
105
|
+
.map((pub) => this.serializer.deserialize(pub.serializedEvent, pub.eventType));
|
|
106
|
+
return typed.filter((event) => this.predicates.every((pred) => pred(event)));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
exports.PublishedEventsView = PublishedEventsView;
|
|
110
|
+
//# sourceMappingURL=published-events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"published-events.js","sourceRoot":"","sources":["../../src/testing/published-events.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { getEventExternalizerToken, getEventPublicationProcessorToken, getEventPublicationRegistryToken, getEventPublicationRepositoryToken, getEventTypeRegistryToken, getExternalizationRegistryToken, getOutboxEventSerializerToken, getOutboxListenerRegistryToken, getOutboxPublisherToken, } from './token-utils';
|
|
2
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getOutboxPublisherToken = exports.getOutboxListenerRegistryToken = exports.getOutboxEventSerializerToken = exports.getExternalizationRegistryToken = exports.getEventTypeRegistryToken = exports.getEventPublicationRepositoryToken = exports.getEventPublicationRegistryToken = exports.getEventPublicationProcessorToken = exports.getEventExternalizerToken = void 0;
|
|
4
|
+
var token_utils_1 = require("./token-utils");
|
|
5
|
+
Object.defineProperty(exports, "getEventExternalizerToken", { enumerable: true, get: function () { return token_utils_1.getEventExternalizerToken; } });
|
|
6
|
+
Object.defineProperty(exports, "getEventPublicationProcessorToken", { enumerable: true, get: function () { return token_utils_1.getEventPublicationProcessorToken; } });
|
|
7
|
+
Object.defineProperty(exports, "getEventPublicationRegistryToken", { enumerable: true, get: function () { return token_utils_1.getEventPublicationRegistryToken; } });
|
|
8
|
+
Object.defineProperty(exports, "getEventPublicationRepositoryToken", { enumerable: true, get: function () { return token_utils_1.getEventPublicationRepositoryToken; } });
|
|
9
|
+
Object.defineProperty(exports, "getEventTypeRegistryToken", { enumerable: true, get: function () { return token_utils_1.getEventTypeRegistryToken; } });
|
|
10
|
+
Object.defineProperty(exports, "getExternalizationRegistryToken", { enumerable: true, get: function () { return token_utils_1.getExternalizationRegistryToken; } });
|
|
11
|
+
Object.defineProperty(exports, "getOutboxEventSerializerToken", { enumerable: true, get: function () { return token_utils_1.getOutboxEventSerializerToken; } });
|
|
12
|
+
Object.defineProperty(exports, "getOutboxListenerRegistryToken", { enumerable: true, get: function () { return token_utils_1.getOutboxListenerRegistryToken; } });
|
|
13
|
+
Object.defineProperty(exports, "getOutboxPublisherToken", { enumerable: true, get: function () { return token_utils_1.getOutboxPublisherToken; } });
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tokens/index.ts"],"names":[],"mappings":";;;AAAA,6CAUuB;AATrB,wHAAA,yBAAyB,OAAA;AACzB,gIAAA,iCAAiC,OAAA;AACjC,+HAAA,gCAAgC,OAAA;AAChC,iIAAA,kCAAkC,OAAA;AAClC,wHAAA,yBAAyB,OAAA;AACzB,8HAAA,+BAA+B,OAAA;AAC/B,4HAAA,6BAA6B,OAAA;AAC7B,6HAAA,8BAA8B,OAAA;AAC9B,sHAAA,uBAAuB,OAAA"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Outbox-side token utilities. Mirror the core utilities (ADR-018) —
|
|
3
|
+
* deterministic DI tokens derived from a dataSource name, default
|
|
4
|
+
* `'default'`, format `${dataSource}${Component}`.
|
|
5
|
+
*
|
|
6
|
+
* One per outbox component the application can have a per-dataSource
|
|
7
|
+
* instance of: publisher, registries, processor, repository,
|
|
8
|
+
* externalizer, serializer. Per-dataSource scoping is what lets a
|
|
9
|
+
* modular monolith run separate outbox stacks per bounded context
|
|
10
|
+
* without contention on a single `event_publication` table.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* DI token for the per-dataSource `OutboxEventPublisher`. The
|
|
14
|
+
* default-injected publisher is the smart facade (DD-024); this
|
|
15
|
+
* token resolves to the underlying per-dataSource publisher.
|
|
16
|
+
*/
|
|
17
|
+
export declare function getOutboxPublisherToken(dataSource?: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* DI token for the per-dataSource `EventTypeRegistry`. Event-type
|
|
20
|
+
* registrations from `OutboxModule.forFeature(...)` accumulate into
|
|
21
|
+
* the registry bound to the same dataSource — they do not bleed
|
|
22
|
+
* across dataSources.
|
|
23
|
+
*/
|
|
24
|
+
export declare function getEventTypeRegistryToken(dataSource?: string): string;
|
|
25
|
+
/**
|
|
26
|
+
* DI token for the per-dataSource `EventPublicationRegistry` — the
|
|
27
|
+
* lifecycle coordinator that owns publication state transitions.
|
|
28
|
+
*/
|
|
29
|
+
export declare function getEventPublicationRegistryToken(dataSource?: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* DI token for the per-dataSource `EventPublicationProcessor` —
|
|
32
|
+
* the async worker that drains publications and dispatches them to
|
|
33
|
+
* listeners + externalizer.
|
|
34
|
+
*/
|
|
35
|
+
export declare function getEventPublicationProcessorToken(dataSource?: string): string;
|
|
36
|
+
/**
|
|
37
|
+
* DI token for the per-dataSource `OutboxListenerRegistry` —
|
|
38
|
+
* registry of listener entries scanned from `@OutboxEventsHandler`
|
|
39
|
+
* classes (and, when wired, `@IntegrationEventsHandler` classes
|
|
40
|
+
* routed via the outbox).
|
|
41
|
+
*/
|
|
42
|
+
export declare function getOutboxListenerRegistryToken(dataSource?: string): string;
|
|
43
|
+
/**
|
|
44
|
+
* DI token for the per-dataSource `ExternalizationRegistry`.
|
|
45
|
+
*/
|
|
46
|
+
export declare function getExternalizationRegistryToken(dataSource?: string): string;
|
|
47
|
+
/**
|
|
48
|
+
* DI token for the per-dataSource `EventPublicationRepository`.
|
|
49
|
+
* Adapter packages (`outbox-typeorm`, future `outbox-prisma`, etc.)
|
|
50
|
+
* register their concrete repository under this token.
|
|
51
|
+
*/
|
|
52
|
+
export declare function getEventPublicationRepositoryToken(dataSource?: string): string;
|
|
53
|
+
/**
|
|
54
|
+
* DI token for the per-dataSource `EventExternalizer`. Multi-adapter
|
|
55
|
+
* processes can wire externalization independently per outbox stack
|
|
56
|
+
* — e.g. the `'billing'` outbox emits to Kafka, the `'audit'` outbox
|
|
57
|
+
* is internal-only and binds no externalizer.
|
|
58
|
+
*/
|
|
59
|
+
export declare function getEventExternalizerToken(dataSource?: string): string;
|
|
60
|
+
/**
|
|
61
|
+
* DI token for the per-dataSource `EventSerializer`. Distinct
|
|
62
|
+
* dataSources may use distinct serialization strategies (e.g.
|
|
63
|
+
* one JSON, another schema-validated) — the token-per-dataSource
|
|
64
|
+
* pattern keeps that pluggable without forcing one strategy
|
|
65
|
+
* process-wide.
|
|
66
|
+
*/
|
|
67
|
+
export declare function getOutboxEventSerializerToken(dataSource?: string): string;
|
|
68
|
+
//# sourceMappingURL=token-utils.d.ts.map
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getOutboxPublisherToken = getOutboxPublisherToken;
|
|
4
|
+
exports.getEventTypeRegistryToken = getEventTypeRegistryToken;
|
|
5
|
+
exports.getEventPublicationRegistryToken = getEventPublicationRegistryToken;
|
|
6
|
+
exports.getEventPublicationProcessorToken = getEventPublicationProcessorToken;
|
|
7
|
+
exports.getOutboxListenerRegistryToken = getOutboxListenerRegistryToken;
|
|
8
|
+
exports.getExternalizationRegistryToken = getExternalizationRegistryToken;
|
|
9
|
+
exports.getEventPublicationRepositoryToken = getEventPublicationRepositoryToken;
|
|
10
|
+
exports.getEventExternalizerToken = getEventExternalizerToken;
|
|
11
|
+
exports.getOutboxEventSerializerToken = getOutboxEventSerializerToken;
|
|
12
|
+
const core_1 = require("@nestjs-transactional/core");
|
|
13
|
+
/**
|
|
14
|
+
* Outbox-side token utilities. Mirror the core utilities (ADR-018) —
|
|
15
|
+
* deterministic DI tokens derived from a dataSource name, default
|
|
16
|
+
* `'default'`, format `${dataSource}${Component}`.
|
|
17
|
+
*
|
|
18
|
+
* One per outbox component the application can have a per-dataSource
|
|
19
|
+
* instance of: publisher, registries, processor, repository,
|
|
20
|
+
* externalizer, serializer. Per-dataSource scoping is what lets a
|
|
21
|
+
* modular monolith run separate outbox stacks per bounded context
|
|
22
|
+
* without contention on a single `event_publication` table.
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* DI token for the per-dataSource `OutboxEventPublisher`. The
|
|
26
|
+
* default-injected publisher is the smart facade (DD-024); this
|
|
27
|
+
* token resolves to the underlying per-dataSource publisher.
|
|
28
|
+
*/
|
|
29
|
+
function getOutboxPublisherToken(dataSource = core_1.DEFAULT_DATA_SOURCE_NAME) {
|
|
30
|
+
return `${dataSource}OutboxEventPublisher`;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* DI token for the per-dataSource `EventTypeRegistry`. Event-type
|
|
34
|
+
* registrations from `OutboxModule.forFeature(...)` accumulate into
|
|
35
|
+
* the registry bound to the same dataSource — they do not bleed
|
|
36
|
+
* across dataSources.
|
|
37
|
+
*/
|
|
38
|
+
function getEventTypeRegistryToken(dataSource = core_1.DEFAULT_DATA_SOURCE_NAME) {
|
|
39
|
+
return `${dataSource}EventTypeRegistry`;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* DI token for the per-dataSource `EventPublicationRegistry` — the
|
|
43
|
+
* lifecycle coordinator that owns publication state transitions.
|
|
44
|
+
*/
|
|
45
|
+
function getEventPublicationRegistryToken(dataSource = core_1.DEFAULT_DATA_SOURCE_NAME) {
|
|
46
|
+
return `${dataSource}EventPublicationRegistry`;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* DI token for the per-dataSource `EventPublicationProcessor` —
|
|
50
|
+
* the async worker that drains publications and dispatches them to
|
|
51
|
+
* listeners + externalizer.
|
|
52
|
+
*/
|
|
53
|
+
function getEventPublicationProcessorToken(dataSource = core_1.DEFAULT_DATA_SOURCE_NAME) {
|
|
54
|
+
return `${dataSource}EventPublicationProcessor`;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* DI token for the per-dataSource `OutboxListenerRegistry` —
|
|
58
|
+
* registry of listener entries scanned from `@OutboxEventsHandler`
|
|
59
|
+
* classes (and, when wired, `@IntegrationEventsHandler` classes
|
|
60
|
+
* routed via the outbox).
|
|
61
|
+
*/
|
|
62
|
+
function getOutboxListenerRegistryToken(dataSource = core_1.DEFAULT_DATA_SOURCE_NAME) {
|
|
63
|
+
return `${dataSource}OutboxListenerRegistry`;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* DI token for the per-dataSource `ExternalizationRegistry`.
|
|
67
|
+
*/
|
|
68
|
+
function getExternalizationRegistryToken(dataSource = core_1.DEFAULT_DATA_SOURCE_NAME) {
|
|
69
|
+
return `${dataSource}ExternalizationRegistry`;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* DI token for the per-dataSource `EventPublicationRepository`.
|
|
73
|
+
* Adapter packages (`outbox-typeorm`, future `outbox-prisma`, etc.)
|
|
74
|
+
* register their concrete repository under this token.
|
|
75
|
+
*/
|
|
76
|
+
function getEventPublicationRepositoryToken(dataSource = core_1.DEFAULT_DATA_SOURCE_NAME) {
|
|
77
|
+
return `${dataSource}EventPublicationRepository`;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* DI token for the per-dataSource `EventExternalizer`. Multi-adapter
|
|
81
|
+
* processes can wire externalization independently per outbox stack
|
|
82
|
+
* — e.g. the `'billing'` outbox emits to Kafka, the `'audit'` outbox
|
|
83
|
+
* is internal-only and binds no externalizer.
|
|
84
|
+
*/
|
|
85
|
+
function getEventExternalizerToken(dataSource = core_1.DEFAULT_DATA_SOURCE_NAME) {
|
|
86
|
+
return `${dataSource}EventExternalizer`;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* DI token for the per-dataSource `EventSerializer`. Distinct
|
|
90
|
+
* dataSources may use distinct serialization strategies (e.g.
|
|
91
|
+
* one JSON, another schema-validated) — the token-per-dataSource
|
|
92
|
+
* pattern keeps that pluggable without forcing one strategy
|
|
93
|
+
* process-wide.
|
|
94
|
+
*/
|
|
95
|
+
function getOutboxEventSerializerToken(dataSource = core_1.DEFAULT_DATA_SOURCE_NAME) {
|
|
96
|
+
return `${dataSource}OutboxEventSerializer`;
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=token-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-utils.js","sourceRoot":"","sources":["../../src/tokens/token-utils.ts"],"names":[],"mappings":";;AAmBA,0DAIC;AAQD,8DAIC;AAMD,4EAIC;AAOD,8EAIC;AAQD,wEAIC;AAKD,0EAIC;AAOD,gFAIC;AAQD,8DAIC;AASD,sEAIC;AAjHD,qDAAsE;AAEtE;;;;;;;;;;GAUG;AAEH;;;;GAIG;AACH,SAAgB,uBAAuB,CACrC,aAAqB,+BAAwB;IAE7C,OAAO,GAAG,UAAU,sBAAsB,CAAC;AAC7C,CAAC;AAED;;;;;GAKG;AACH,SAAgB,yBAAyB,CACvC,aAAqB,+BAAwB;IAE7C,OAAO,GAAG,UAAU,mBAAmB,CAAC;AAC1C,CAAC;AAED;;;GAGG;AACH,SAAgB,gCAAgC,CAC9C,aAAqB,+BAAwB;IAE7C,OAAO,GAAG,UAAU,0BAA0B,CAAC;AACjD,CAAC;AAED;;;;GAIG;AACH,SAAgB,iCAAiC,CAC/C,aAAqB,+BAAwB;IAE7C,OAAO,GAAG,UAAU,2BAA2B,CAAC;AAClD,CAAC;AAED;;;;;GAKG;AACH,SAAgB,8BAA8B,CAC5C,aAAqB,+BAAwB;IAE7C,OAAO,GAAG,UAAU,wBAAwB,CAAC;AAC/C,CAAC;AAED;;GAEG;AACH,SAAgB,+BAA+B,CAC7C,aAAqB,+BAAwB;IAE7C,OAAO,GAAG,UAAU,yBAAyB,CAAC;AAChD,CAAC;AAED;;;;GAIG;AACH,SAAgB,kCAAkC,CAChD,aAAqB,+BAAwB;IAE7C,OAAO,GAAG,UAAU,4BAA4B,CAAC;AACnD,CAAC;AAED;;;;;GAKG;AACH,SAAgB,yBAAyB,CACvC,aAAqB,+BAAwB;IAE7C,OAAO,GAAG,UAAU,mBAAmB,CAAC;AAC1C,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,6BAA6B,CAC3C,aAAqB,+BAAwB;IAE7C,OAAO,GAAG,UAAU,uBAAuB,CAAC;AAC9C,CAAC"}
|