@beignet/core 0.0.1 → 0.0.2
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/CHANGELOG.md +11 -0
- package/README.md +149 -4
- package/dist/application/index.d.ts +93 -9
- package/dist/application/index.d.ts.map +1 -1
- package/dist/application/index.js +11 -11
- package/dist/application/index.js.map +1 -1
- package/dist/client/client.d.ts +73 -12
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/client.js +37 -12
- package/dist/client/client.js.map +1 -1
- package/dist/client/index.d.ts +12 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +6 -0
- package/dist/client/index.js.map +1 -1
- package/dist/client/types.d.ts +69 -8
- package/dist/client/types.d.ts.map +1 -1
- package/dist/config/index.d.ts +84 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +36 -0
- package/dist/config/index.js.map +1 -1
- package/dist/contracts/contract-builder.d.ts +49 -22
- package/dist/contracts/contract-builder.d.ts.map +1 -1
- package/dist/contracts/contract-builder.js +48 -21
- package/dist/contracts/contract-builder.js.map +1 -1
- package/dist/contracts/contract-group.d.ts +35 -19
- package/dist/contracts/contract-group.d.ts.map +1 -1
- package/dist/contracts/contract-group.js +35 -19
- package/dist/contracts/contract-group.js.map +1 -1
- package/dist/contracts/contract-like.d.ts +4 -4
- package/dist/contracts/contract-like.d.ts.map +1 -1
- package/dist/contracts/contract-like.js +2 -1
- package/dist/contracts/contract-like.js.map +1 -1
- package/dist/contracts/index.d.ts +28 -0
- package/dist/contracts/index.d.ts.map +1 -1
- package/dist/contracts/index.js +12 -0
- package/dist/contracts/index.js.map +1 -1
- package/dist/contracts/openapi-meta.d.ts +8 -8
- package/dist/contracts/openapi-meta.d.ts.map +1 -1
- package/dist/contracts/path-template.d.ts +27 -0
- package/dist/contracts/path-template.d.ts.map +1 -1
- package/dist/contracts/path-template.js +6 -0
- package/dist/contracts/path-template.js.map +1 -1
- package/dist/contracts/types.d.ts +104 -10
- package/dist/contracts/types.d.ts.map +1 -1
- package/dist/contracts/types.js +15 -0
- package/dist/contracts/types.js.map +1 -1
- package/dist/contracts/utils.d.ts +6 -0
- package/dist/contracts/utils.d.ts.map +1 -1
- package/dist/contracts/utils.js +6 -0
- package/dist/contracts/utils.js.map +1 -1
- package/dist/domain/entity.d.ts +22 -11
- package/dist/domain/entity.d.ts.map +1 -1
- package/dist/domain/entity.js +5 -1
- package/dist/domain/entity.js.map +1 -1
- package/dist/domain/events.d.ts +5 -2
- package/dist/domain/events.d.ts.map +1 -1
- package/dist/domain/events.js +4 -1
- package/dist/domain/events.js.map +1 -1
- package/dist/domain/value-object.d.ts +19 -9
- package/dist/domain/value-object.d.ts.map +1 -1
- package/dist/domain/value-object.js +5 -1
- package/dist/domain/value-object.js.map +1 -1
- package/dist/errors/catalog.d.ts +40 -16
- package/dist/errors/catalog.d.ts.map +1 -1
- package/dist/errors/catalog.js +18 -7
- package/dist/errors/catalog.js.map +1 -1
- package/dist/errors/response.d.ts +16 -4
- package/dist/errors/response.d.ts.map +1 -1
- package/dist/errors/response.js +3 -3
- package/dist/errors/response.js.map +1 -1
- package/dist/errors/validation.d.ts +10 -1
- package/dist/errors/validation.d.ts.map +1 -1
- package/dist/errors/validation.js +3 -0
- package/dist/errors/validation.js.map +1 -1
- package/dist/events/index.d.ts +133 -0
- package/dist/events/index.d.ts.map +1 -1
- package/dist/events/index.js +30 -0
- package/dist/events/index.js.map +1 -1
- package/dist/idempotency/index.d.ts +355 -0
- package/dist/idempotency/index.d.ts.map +1 -0
- package/dist/idempotency/index.js +360 -0
- package/dist/idempotency/index.js.map +1 -0
- package/dist/jobs/index.d.ts +110 -0
- package/dist/jobs/index.d.ts.map +1 -1
- package/dist/jobs/index.js +22 -0
- package/dist/jobs/index.js.map +1 -1
- package/dist/mail/index.d.ts +149 -0
- package/dist/mail/index.d.ts.map +1 -1
- package/dist/mail/index.js +30 -0
- package/dist/mail/index.js.map +1 -1
- package/dist/notifications/index.d.ts +369 -0
- package/dist/notifications/index.d.ts.map +1 -0
- package/dist/notifications/index.js +310 -0
- package/dist/notifications/index.js.map +1 -0
- package/dist/openapi/index.d.ts +132 -16
- package/dist/openapi/index.d.ts.map +1 -1
- package/dist/openapi/index.js +1 -1
- package/dist/openapi/index.js.map +1 -1
- package/dist/outbox/index.d.ts +469 -0
- package/dist/outbox/index.d.ts.map +1 -0
- package/dist/outbox/index.js +482 -0
- package/dist/outbox/index.js.map +1 -0
- package/dist/pagination/index.d.ts +166 -0
- package/dist/pagination/index.d.ts.map +1 -0
- package/dist/pagination/index.js +96 -0
- package/dist/pagination/index.js.map +1 -0
- package/dist/ports/audit.d.ts +271 -0
- package/dist/ports/audit.d.ts.map +1 -1
- package/dist/ports/audit.js +128 -0
- package/dist/ports/audit.js.map +1 -1
- package/dist/ports/auth.d.ts +70 -0
- package/dist/ports/auth.d.ts.map +1 -1
- package/dist/ports/auth.js +30 -0
- package/dist/ports/auth.js.map +1 -1
- package/dist/ports/cache.d.ts +41 -0
- package/dist/ports/cache.d.ts.map +1 -1
- package/dist/ports/cache.js +10 -0
- package/dist/ports/cache.js.map +1 -1
- package/dist/ports/clock.d.ts +38 -0
- package/dist/ports/clock.d.ts.map +1 -1
- package/dist/ports/clock.js +20 -0
- package/dist/ports/clock.js.map +1 -1
- package/dist/ports/id-generator.d.ts +37 -0
- package/dist/ports/id-generator.d.ts.map +1 -1
- package/dist/ports/id-generator.js +22 -0
- package/dist/ports/id-generator.js.map +1 -1
- package/dist/ports/index.d.ts +83 -0
- package/dist/ports/index.d.ts.map +1 -1
- package/dist/ports/index.js +41 -5
- package/dist/ports/index.js.map +1 -1
- package/dist/ports/logger.d.ts +56 -0
- package/dist/ports/logger.d.ts.map +1 -1
- package/dist/ports/logger.js +17 -0
- package/dist/ports/logger.js.map +1 -1
- package/dist/ports/policy.d.ts +132 -0
- package/dist/ports/policy.d.ts.map +1 -1
- package/dist/ports/policy.js +45 -0
- package/dist/ports/policy.js.map +1 -1
- package/dist/ports/rate-limit.d.ts +25 -0
- package/dist/ports/rate-limit.d.ts.map +1 -1
- package/dist/ports/rate-limit.js +10 -0
- package/dist/ports/rate-limit.js.map +1 -1
- package/dist/ports/redaction.d.ts +101 -0
- package/dist/ports/redaction.d.ts.map +1 -1
- package/dist/ports/redaction.js +59 -0
- package/dist/ports/redaction.js.map +1 -1
- package/dist/ports/storage.d.ts +100 -0
- package/dist/ports/storage.d.ts.map +1 -1
- package/dist/ports/storage.js +10 -0
- package/dist/ports/storage.js.map +1 -1
- package/dist/ports/testing.d.ts +47 -0
- package/dist/ports/testing.d.ts.map +1 -1
- package/dist/ports/testing.js +23 -0
- package/dist/ports/testing.js.map +1 -1
- package/dist/ports/unit-of-work.d.ts +60 -3
- package/dist/ports/unit-of-work.d.ts.map +1 -1
- package/dist/ports/unit-of-work.js +11 -2
- package/dist/ports/unit-of-work.js.map +1 -1
- package/dist/providers/instrumentation.d.ts +204 -0
- package/dist/providers/instrumentation.d.ts.map +1 -1
- package/dist/providers/instrumentation.js +14 -0
- package/dist/providers/instrumentation.js.map +1 -1
- package/dist/providers/provider.d.ts +14 -1
- package/dist/providers/provider.d.ts.map +1 -1
- package/dist/providers/provider.js.map +1 -1
- package/dist/schedules/index.d.ts +246 -0
- package/dist/schedules/index.d.ts.map +1 -1
- package/dist/schedules/index.js +27 -0
- package/dist/schedules/index.js.map +1 -1
- package/dist/server/health.d.ts +14 -5
- package/dist/server/health.d.ts.map +1 -1
- package/dist/server/health.js +5 -2
- package/dist/server/health.js.map +1 -1
- package/dist/server/hooks/auth.d.ts +57 -0
- package/dist/server/hooks/auth.d.ts.map +1 -1
- package/dist/server/hooks/auth.js.map +1 -1
- package/dist/server/hooks/cors.d.ts +27 -0
- package/dist/server/hooks/cors.d.ts.map +1 -1
- package/dist/server/hooks/cors.js +12 -0
- package/dist/server/hooks/cors.js.map +1 -1
- package/dist/server/hooks/errors.d.ts +15 -6
- package/dist/server/hooks/errors.d.ts.map +1 -1
- package/dist/server/hooks/errors.js.map +1 -1
- package/dist/server/hooks/index.d.ts +3 -0
- package/dist/server/hooks/index.d.ts.map +1 -1
- package/dist/server/hooks/index.js +3 -0
- package/dist/server/hooks/index.js.map +1 -1
- package/dist/server/hooks/logging.d.ts +36 -0
- package/dist/server/hooks/logging.d.ts.map +1 -1
- package/dist/server/hooks/logging.js +6 -0
- package/dist/server/hooks/logging.js.map +1 -1
- package/dist/server/hooks/rate-limit.d.ts +33 -0
- package/dist/server/hooks/rate-limit.d.ts.map +1 -1
- package/dist/server/hooks/rate-limit.js +11 -0
- package/dist/server/hooks/rate-limit.js.map +1 -1
- package/dist/server/http.d.ts +170 -0
- package/dist/server/http.d.ts.map +1 -1
- package/dist/server/index.d.ts +18 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +6 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/openapi.d.ts +5 -3
- package/dist/server/openapi.d.ts.map +1 -1
- package/dist/server/openapi.js +4 -2
- package/dist/server/openapi.js.map +1 -1
- package/dist/server/providers/loadProviderConfig.d.ts +9 -0
- package/dist/server/providers/loadProviderConfig.d.ts.map +1 -1
- package/dist/server/providers/loadProviderConfig.js +9 -0
- package/dist/server/providers/loadProviderConfig.js.map +1 -1
- package/dist/server/server.d.ts +107 -8
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +27 -7
- package/dist/server/server.js.map +1 -1
- package/dist/testing/index.d.ts +167 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +119 -0
- package/dist/testing/index.js.map +1 -0
- package/package.json +21 -1
- package/src/application/index.ts +85 -22
- package/src/client/client.ts +73 -12
- package/src/client/index.ts +12 -0
- package/src/client/types.ts +70 -9
- package/src/config/index.ts +86 -0
- package/src/contracts/contract-builder.ts +49 -22
- package/src/contracts/contract-group.ts +35 -19
- package/src/contracts/contract-like.ts +4 -4
- package/src/contracts/index.ts +28 -1
- package/src/contracts/openapi-meta.ts +8 -8
- package/src/contracts/path-template.ts +27 -0
- package/src/contracts/types.ts +111 -10
- package/src/contracts/utils.ts +6 -0
- package/src/domain/entity.ts +22 -11
- package/src/domain/events.ts +5 -2
- package/src/domain/value-object.ts +19 -9
- package/src/errors/catalog.ts +40 -16
- package/src/errors/response.ts +16 -4
- package/src/errors/validation.ts +10 -1
- package/src/events/index.ts +134 -0
- package/src/idempotency/index.ts +767 -0
- package/src/jobs/index.ts +111 -0
- package/src/mail/index.ts +149 -0
- package/src/notifications/index.ts +771 -0
- package/src/openapi/index.ts +133 -16
- package/src/outbox/index.ts +1024 -0
- package/src/pagination/index.ts +278 -0
- package/src/ports/audit.ts +271 -0
- package/src/ports/auth.ts +70 -0
- package/src/ports/cache.ts +41 -0
- package/src/ports/clock.ts +38 -0
- package/src/ports/id-generator.ts +37 -0
- package/src/ports/index.ts +106 -11
- package/src/ports/logger.ts +56 -0
- package/src/ports/policy.ts +133 -0
- package/src/ports/rate-limit.ts +25 -0
- package/src/ports/redaction.ts +101 -0
- package/src/ports/storage.ts +100 -0
- package/src/ports/testing.ts +47 -0
- package/src/ports/unit-of-work.ts +60 -3
- package/src/providers/instrumentation.ts +204 -0
- package/src/providers/provider.ts +14 -1
- package/src/schedules/index.ts +247 -0
- package/src/server/health.ts +14 -5
- package/src/server/hooks/auth.ts +58 -0
- package/src/server/hooks/cors.ts +27 -0
- package/src/server/hooks/errors.ts +15 -6
- package/src/server/hooks/index.ts +3 -0
- package/src/server/hooks/logging.ts +36 -0
- package/src/server/hooks/rate-limit.ts +33 -0
- package/src/server/http.ts +170 -1
- package/src/server/index.ts +18 -1
- package/src/server/openapi.ts +5 -3
- package/src/server/providers/loadProviderConfig.ts +9 -0
- package/src/server/server.ts +107 -9
- package/src/testing/index.ts +337 -0
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @beignet/core/outbox
|
|
3
|
+
*
|
|
4
|
+
* Durable outbox primitives for transactionally recording events and jobs that
|
|
5
|
+
* should be delivered after the owning database transaction commits.
|
|
6
|
+
*/
|
|
7
|
+
import { parseEventPayload, } from "../events";
|
|
8
|
+
import { parseJobPayload } from "../jobs";
|
|
9
|
+
/**
|
|
10
|
+
* Default lease duration for claimed outbox messages.
|
|
11
|
+
*/
|
|
12
|
+
export const DEFAULT_OUTBOX_LEASE_MS = 30_000;
|
|
13
|
+
/**
|
|
14
|
+
* Default maximum delivery attempts before a message is dead-lettered.
|
|
15
|
+
*/
|
|
16
|
+
export const DEFAULT_OUTBOX_MAX_ATTEMPTS = 3;
|
|
17
|
+
/**
|
|
18
|
+
* Error thrown when an outbox payload is not JSON serializable.
|
|
19
|
+
*/
|
|
20
|
+
export class OutboxSerializationError extends Error {
|
|
21
|
+
constructor(message) {
|
|
22
|
+
super(message);
|
|
23
|
+
this.name = "OutboxSerializationError";
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Error thrown when an outbox message cannot be resolved through the registry.
|
|
28
|
+
*/
|
|
29
|
+
export class OutboxRegistryError extends Error {
|
|
30
|
+
constructor(message) {
|
|
31
|
+
super(message);
|
|
32
|
+
this.name = "OutboxRegistryError";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Error thrown when a claimed message cannot be updated with the supplied token.
|
|
37
|
+
*/
|
|
38
|
+
export class OutboxClaimError extends Error {
|
|
39
|
+
/**
|
|
40
|
+
* Message ID involved in the claim error.
|
|
41
|
+
*/
|
|
42
|
+
id;
|
|
43
|
+
constructor(args) {
|
|
44
|
+
super(args.message);
|
|
45
|
+
this.name = "OutboxClaimError";
|
|
46
|
+
this.id = args.id;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function assertNonEmptyString(name, value) {
|
|
50
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
51
|
+
throw new Error(`${name} must be a non-empty string`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function assertPositiveInteger(name, value) {
|
|
55
|
+
if (!Number.isInteger(value) || value <= 0) {
|
|
56
|
+
throw new Error(`${name} must be a positive integer`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function cloneDate(value) {
|
|
60
|
+
return new Date(value.getTime());
|
|
61
|
+
}
|
|
62
|
+
function createId() {
|
|
63
|
+
if (!globalThis.crypto?.randomUUID) {
|
|
64
|
+
throw new Error("crypto.randomUUID is required to create outbox IDs.");
|
|
65
|
+
}
|
|
66
|
+
return globalThis.crypto.randomUUID();
|
|
67
|
+
}
|
|
68
|
+
function assertJsonValue(value, path = [], seen = new WeakSet()) {
|
|
69
|
+
const label = path.length > 0 ? path.join(".") : "payload";
|
|
70
|
+
if (value === null)
|
|
71
|
+
return null;
|
|
72
|
+
if (typeof value === "string" ||
|
|
73
|
+
typeof value === "boolean" ||
|
|
74
|
+
typeof value === "number") {
|
|
75
|
+
if (typeof value === "number" && !Number.isFinite(value)) {
|
|
76
|
+
throw new OutboxSerializationError(`Outbox ${label} must be a finite number.`);
|
|
77
|
+
}
|
|
78
|
+
return value;
|
|
79
|
+
}
|
|
80
|
+
if (Array.isArray(value)) {
|
|
81
|
+
if (seen.has(value)) {
|
|
82
|
+
throw new OutboxSerializationError(`Outbox ${label} must be JSON serializable. Circular references are not supported.`);
|
|
83
|
+
}
|
|
84
|
+
seen.add(value);
|
|
85
|
+
try {
|
|
86
|
+
return value.map((item, index) => assertJsonValue(item, [...path, String(index)], seen));
|
|
87
|
+
}
|
|
88
|
+
finally {
|
|
89
|
+
seen.delete(value);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (typeof value === "object") {
|
|
93
|
+
if (value instanceof Date) {
|
|
94
|
+
throw new OutboxSerializationError(`Outbox ${label} must be JSON serializable. Convert Date values to strings before enqueueing.`);
|
|
95
|
+
}
|
|
96
|
+
if (seen.has(value)) {
|
|
97
|
+
throw new OutboxSerializationError(`Outbox ${label} must be JSON serializable. Circular references are not supported.`);
|
|
98
|
+
}
|
|
99
|
+
seen.add(value);
|
|
100
|
+
try {
|
|
101
|
+
const record = value;
|
|
102
|
+
const output = {};
|
|
103
|
+
for (const key of Object.keys(record)) {
|
|
104
|
+
const child = record[key];
|
|
105
|
+
if (child === undefined) {
|
|
106
|
+
throw new OutboxSerializationError(`Outbox ${[...path, key].join(".")} cannot be undefined.`);
|
|
107
|
+
}
|
|
108
|
+
output[key] = assertJsonValue(child, [...path, key], seen);
|
|
109
|
+
}
|
|
110
|
+
return output;
|
|
111
|
+
}
|
|
112
|
+
finally {
|
|
113
|
+
seen.delete(value);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
throw new OutboxSerializationError(`Outbox ${label} must be JSON serializable. Received ${typeof value}.`);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Convert an unknown value to an outbox-safe JSON value.
|
|
120
|
+
*
|
|
121
|
+
* Dates, undefined values, functions, non-finite numbers, symbols, and circular
|
|
122
|
+
* references are rejected so durable adapters can store the payload safely.
|
|
123
|
+
*/
|
|
124
|
+
export function toOutboxJsonValue(value) {
|
|
125
|
+
const jsonValue = assertJsonValue(value);
|
|
126
|
+
return JSON.parse(JSON.stringify(jsonValue));
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Serialize an unknown delivery error into outbox error metadata.
|
|
130
|
+
*/
|
|
131
|
+
export function serializeOutboxError(error) {
|
|
132
|
+
if (error instanceof Error) {
|
|
133
|
+
return {
|
|
134
|
+
name: error.name,
|
|
135
|
+
message: error.message,
|
|
136
|
+
stack: error.stack,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
if (typeof error === "string") {
|
|
140
|
+
return { message: error };
|
|
141
|
+
}
|
|
142
|
+
return { message: "Unknown outbox delivery error" };
|
|
143
|
+
}
|
|
144
|
+
function copyMessage(message) {
|
|
145
|
+
return {
|
|
146
|
+
...message,
|
|
147
|
+
availableAt: cloneDate(message.availableAt),
|
|
148
|
+
claimedAt: message.claimedAt ? cloneDate(message.claimedAt) : null,
|
|
149
|
+
lockedUntil: message.lockedUntil ? cloneDate(message.lockedUntil) : null,
|
|
150
|
+
deliveredAt: message.deliveredAt ? cloneDate(message.deliveredAt) : null,
|
|
151
|
+
createdAt: cloneDate(message.createdAt),
|
|
152
|
+
updatedAt: cloneDate(message.updatedAt),
|
|
153
|
+
lastError: message.lastError ? { ...message.lastError } : null,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
function toClaimedMessage(message) {
|
|
157
|
+
if (message.status !== "claimed" ||
|
|
158
|
+
!message.claimToken ||
|
|
159
|
+
!message.claimedAt ||
|
|
160
|
+
!message.lockedUntil) {
|
|
161
|
+
throw new OutboxClaimError({
|
|
162
|
+
id: message.id,
|
|
163
|
+
message: `Outbox message "${message.id}" is not claimed.`,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
...copyMessage(message),
|
|
168
|
+
status: "claimed",
|
|
169
|
+
claimToken: message.claimToken,
|
|
170
|
+
claimedAt: cloneDate(message.claimedAt),
|
|
171
|
+
lockedUntil: cloneDate(message.lockedUntil),
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Create a validated pending outbox message.
|
|
176
|
+
*/
|
|
177
|
+
export function createOutboxMessage(input, options = {}) {
|
|
178
|
+
assertNonEmptyString("kind", input.kind);
|
|
179
|
+
assertNonEmptyString("name", input.name);
|
|
180
|
+
if (input.id !== undefined)
|
|
181
|
+
assertNonEmptyString("id", input.id);
|
|
182
|
+
if (input.maxAttempts !== undefined) {
|
|
183
|
+
assertPositiveInteger("maxAttempts", input.maxAttempts);
|
|
184
|
+
}
|
|
185
|
+
const now = options.now ?? new Date();
|
|
186
|
+
return {
|
|
187
|
+
id: options.id ?? input.id ?? createId(),
|
|
188
|
+
kind: input.kind,
|
|
189
|
+
name: input.name,
|
|
190
|
+
payload: toOutboxJsonValue(input.payload),
|
|
191
|
+
status: "pending",
|
|
192
|
+
attempts: 0,
|
|
193
|
+
maxAttempts: input.maxAttempts ?? DEFAULT_OUTBOX_MAX_ATTEMPTS,
|
|
194
|
+
availableAt: input.availableAt
|
|
195
|
+
? cloneDate(input.availableAt)
|
|
196
|
+
: cloneDate(now),
|
|
197
|
+
claimedAt: null,
|
|
198
|
+
lockedUntil: null,
|
|
199
|
+
claimToken: null,
|
|
200
|
+
deliveredAt: null,
|
|
201
|
+
lastError: null,
|
|
202
|
+
createdAt: cloneDate(now),
|
|
203
|
+
updatedAt: cloneDate(now),
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
function isEligible(message, now) {
|
|
207
|
+
if (message.status === "pending") {
|
|
208
|
+
return message.availableAt.getTime() <= now.getTime();
|
|
209
|
+
}
|
|
210
|
+
return (message.status === "claimed" &&
|
|
211
|
+
message.lockedUntil !== null &&
|
|
212
|
+
message.lockedUntil.getTime() <= now.getTime());
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Create an in-memory outbox for tests and local examples.
|
|
216
|
+
*
|
|
217
|
+
* The memory outbox is process-local and not durable.
|
|
218
|
+
*/
|
|
219
|
+
export function createMemoryOutbox() {
|
|
220
|
+
const messages = new Map();
|
|
221
|
+
function getClaimedOrThrow(id, claimToken) {
|
|
222
|
+
const message = messages.get(id);
|
|
223
|
+
if (!message) {
|
|
224
|
+
throw new OutboxClaimError({
|
|
225
|
+
id,
|
|
226
|
+
message: `Outbox message "${id}" does not exist.`,
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
if (message.status !== "claimed" || message.claimToken !== claimToken) {
|
|
230
|
+
throw new OutboxClaimError({
|
|
231
|
+
id,
|
|
232
|
+
message: `Outbox message "${id}" is not claimed by this worker.`,
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
return message;
|
|
236
|
+
}
|
|
237
|
+
return {
|
|
238
|
+
get messages() {
|
|
239
|
+
return [...messages.values()].map(copyMessage);
|
|
240
|
+
},
|
|
241
|
+
async enqueue(input) {
|
|
242
|
+
const message = createOutboxMessage(input);
|
|
243
|
+
if (messages.has(message.id)) {
|
|
244
|
+
throw new Error(`Outbox message "${message.id}" already exists.`);
|
|
245
|
+
}
|
|
246
|
+
messages.set(message.id, message);
|
|
247
|
+
return copyMessage(message);
|
|
248
|
+
},
|
|
249
|
+
async claimBatch(options) {
|
|
250
|
+
assertPositiveInteger("limit", options.limit);
|
|
251
|
+
const now = options.now ?? new Date();
|
|
252
|
+
const leaseMs = options.leaseMs ?? DEFAULT_OUTBOX_LEASE_MS;
|
|
253
|
+
assertPositiveInteger("leaseMs", leaseMs);
|
|
254
|
+
const lockedUntil = new Date(now.getTime() + leaseMs);
|
|
255
|
+
const claimed = [];
|
|
256
|
+
const eligible = [...messages.values()]
|
|
257
|
+
.filter((message) => isEligible(message, now))
|
|
258
|
+
.sort((a, b) => {
|
|
259
|
+
const available = a.availableAt.getTime() - b.availableAt.getTime();
|
|
260
|
+
if (available !== 0)
|
|
261
|
+
return available;
|
|
262
|
+
return a.createdAt.getTime() - b.createdAt.getTime();
|
|
263
|
+
})
|
|
264
|
+
.slice(0, options.limit);
|
|
265
|
+
for (const message of eligible) {
|
|
266
|
+
message.status = "claimed";
|
|
267
|
+
message.attempts += 1;
|
|
268
|
+
message.claimToken = createId();
|
|
269
|
+
message.claimedAt = cloneDate(now);
|
|
270
|
+
message.lockedUntil = cloneDate(lockedUntil);
|
|
271
|
+
message.updatedAt = cloneDate(now);
|
|
272
|
+
claimed.push(toClaimedMessage(message));
|
|
273
|
+
}
|
|
274
|
+
return claimed;
|
|
275
|
+
},
|
|
276
|
+
async markDelivered(input) {
|
|
277
|
+
assertNonEmptyString("id", input.id);
|
|
278
|
+
assertNonEmptyString("claimToken", input.claimToken);
|
|
279
|
+
const message = getClaimedOrThrow(input.id, input.claimToken);
|
|
280
|
+
const now = input.now ?? new Date();
|
|
281
|
+
message.status = "delivered";
|
|
282
|
+
message.deliveredAt = cloneDate(now);
|
|
283
|
+
message.claimToken = null;
|
|
284
|
+
message.claimedAt = null;
|
|
285
|
+
message.lockedUntil = null;
|
|
286
|
+
message.updatedAt = cloneDate(now);
|
|
287
|
+
},
|
|
288
|
+
async markFailed(input) {
|
|
289
|
+
assertNonEmptyString("id", input.id);
|
|
290
|
+
assertNonEmptyString("claimToken", input.claimToken);
|
|
291
|
+
const message = getClaimedOrThrow(input.id, input.claimToken);
|
|
292
|
+
const now = input.now ?? new Date();
|
|
293
|
+
message.status = input.deadLetter ? "deadLettered" : "pending";
|
|
294
|
+
message.lastError = serializeOutboxError(input.error);
|
|
295
|
+
message.availableAt = input.retryAt
|
|
296
|
+
? cloneDate(input.retryAt)
|
|
297
|
+
: cloneDate(now);
|
|
298
|
+
message.claimToken = null;
|
|
299
|
+
message.claimedAt = null;
|
|
300
|
+
message.lockedUntil = null;
|
|
301
|
+
message.updatedAt = cloneDate(now);
|
|
302
|
+
},
|
|
303
|
+
clear() {
|
|
304
|
+
messages.clear();
|
|
305
|
+
},
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
function mapDefinitions(kind, defs) {
|
|
309
|
+
const map = new Map();
|
|
310
|
+
for (const def of defs) {
|
|
311
|
+
if (map.has(def.name)) {
|
|
312
|
+
throw new OutboxRegistryError(`Duplicate ${kind} definition "${def.name}" in outbox registry.`);
|
|
313
|
+
}
|
|
314
|
+
map.set(def.name, def);
|
|
315
|
+
}
|
|
316
|
+
return map;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Define the events and jobs that an outbox drain worker can deliver.
|
|
320
|
+
*
|
|
321
|
+
* Duplicate names throw because message delivery resolves by name.
|
|
322
|
+
*/
|
|
323
|
+
export function defineOutboxRegistry(input) {
|
|
324
|
+
return {
|
|
325
|
+
events: mapDefinitions("event", input.events ?? []),
|
|
326
|
+
jobs: mapDefinitions("job", input.jobs ?? []),
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Validate an event payload and enqueue it as an outbox message.
|
|
331
|
+
*/
|
|
332
|
+
export async function enqueueEvent(outbox, event, payload, options = {}) {
|
|
333
|
+
const parsed = await parseEventPayload(event, payload);
|
|
334
|
+
return outbox.enqueue({
|
|
335
|
+
id: options.id,
|
|
336
|
+
kind: "event",
|
|
337
|
+
name: event.name,
|
|
338
|
+
payload: toOutboxJsonValue(parsed),
|
|
339
|
+
availableAt: options.availableAt,
|
|
340
|
+
maxAttempts: options.maxAttempts,
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Validate a job payload and enqueue it as an outbox message.
|
|
345
|
+
*/
|
|
346
|
+
export async function enqueueJob(outbox, job, payload, options = {}) {
|
|
347
|
+
const parsed = await parseJobPayload(job, payload);
|
|
348
|
+
return outbox.enqueue({
|
|
349
|
+
id: options.id,
|
|
350
|
+
kind: "job",
|
|
351
|
+
name: job.name,
|
|
352
|
+
payload: toOutboxJsonValue(parsed),
|
|
353
|
+
availableAt: options.availableAt,
|
|
354
|
+
maxAttempts: options.maxAttempts,
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Create a domain event recorder that writes events to the outbox.
|
|
359
|
+
*/
|
|
360
|
+
export function createOutboxEventRecorder(outbox, options = {}) {
|
|
361
|
+
return {
|
|
362
|
+
async record(event, payload) {
|
|
363
|
+
await enqueueEvent(outbox, event, payload, options);
|
|
364
|
+
},
|
|
365
|
+
entries() {
|
|
366
|
+
return [];
|
|
367
|
+
},
|
|
368
|
+
clear() { },
|
|
369
|
+
async flush() { },
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Create a job dispatcher that writes jobs to the outbox.
|
|
374
|
+
*/
|
|
375
|
+
export function createOutboxJobDispatcher(outbox, options = {}) {
|
|
376
|
+
return {
|
|
377
|
+
async dispatch(job, payload) {
|
|
378
|
+
await enqueueJob(outbox, job, payload, options);
|
|
379
|
+
},
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
function resolveRetryDelayMs(options, message, error, now) {
|
|
383
|
+
if (typeof options.retryDelayMs === "function") {
|
|
384
|
+
const delay = options.retryDelayMs({ message, error, now });
|
|
385
|
+
assertPositiveInteger("retryDelayMs", delay);
|
|
386
|
+
return delay;
|
|
387
|
+
}
|
|
388
|
+
if (options.retryDelayMs !== undefined) {
|
|
389
|
+
assertPositiveInteger("retryDelayMs", options.retryDelayMs);
|
|
390
|
+
return options.retryDelayMs;
|
|
391
|
+
}
|
|
392
|
+
return Math.min(60_000, 1000 * 2 ** Math.max(0, message.attempts - 1));
|
|
393
|
+
}
|
|
394
|
+
async function deliverOutboxMessage(options, message) {
|
|
395
|
+
if (message.kind === "event") {
|
|
396
|
+
if (!options.eventBus) {
|
|
397
|
+
throw new OutboxRegistryError(`Cannot deliver event "${message.name}" without an event bus.`);
|
|
398
|
+
}
|
|
399
|
+
const event = options.registry.events.get(message.name);
|
|
400
|
+
if (!event) {
|
|
401
|
+
throw new OutboxRegistryError(`Outbox registry does not include event "${message.name}".`);
|
|
402
|
+
}
|
|
403
|
+
const payload = await parseEventPayload(event, message.payload);
|
|
404
|
+
await options.eventBus.publish(event, payload);
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
if (!options.jobs) {
|
|
408
|
+
throw new OutboxRegistryError(`Cannot deliver job "${message.name}" without a job dispatcher.`);
|
|
409
|
+
}
|
|
410
|
+
const job = options.registry.jobs.get(message.name);
|
|
411
|
+
if (!job) {
|
|
412
|
+
throw new OutboxRegistryError(`Outbox registry does not include job "${message.name}".`);
|
|
413
|
+
}
|
|
414
|
+
const payload = await parseJobPayload(job, message.payload);
|
|
415
|
+
await options.jobs.dispatch(job, payload);
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Claim and deliver one batch of outbox messages.
|
|
419
|
+
*
|
|
420
|
+
* This does not loop forever; production workers should call it on their own
|
|
421
|
+
* polling cadence. Event and job messages require matching registry entries.
|
|
422
|
+
* Failed messages are retried with backoff until `maxAttempts`, then
|
|
423
|
+
* dead-lettered.
|
|
424
|
+
*/
|
|
425
|
+
export async function drainOutbox(options) {
|
|
426
|
+
const batchSize = options.batchSize ?? 100;
|
|
427
|
+
assertPositiveInteger("batchSize", batchSize);
|
|
428
|
+
const now = options.now ?? new Date();
|
|
429
|
+
const messages = await options.outbox.claimBatch({
|
|
430
|
+
limit: batchSize,
|
|
431
|
+
now,
|
|
432
|
+
leaseMs: options.leaseMs,
|
|
433
|
+
});
|
|
434
|
+
const result = {
|
|
435
|
+
claimed: messages.length,
|
|
436
|
+
delivered: 0,
|
|
437
|
+
retried: 0,
|
|
438
|
+
deadLettered: 0,
|
|
439
|
+
};
|
|
440
|
+
for (const message of messages) {
|
|
441
|
+
try {
|
|
442
|
+
await deliverOutboxMessage(options, message);
|
|
443
|
+
await options.outbox.markDelivered({
|
|
444
|
+
id: message.id,
|
|
445
|
+
claimToken: message.claimToken,
|
|
446
|
+
now,
|
|
447
|
+
});
|
|
448
|
+
result.delivered += 1;
|
|
449
|
+
}
|
|
450
|
+
catch (error) {
|
|
451
|
+
try {
|
|
452
|
+
await options.onError?.(error, message);
|
|
453
|
+
}
|
|
454
|
+
catch {
|
|
455
|
+
// Preserve the delivery failure path so the message is retried or
|
|
456
|
+
// dead-lettered even if the observer fails.
|
|
457
|
+
}
|
|
458
|
+
const deadLetter = message.attempts >= message.maxAttempts;
|
|
459
|
+
const retryDelayMs = deadLetter
|
|
460
|
+
? 0
|
|
461
|
+
: resolveRetryDelayMs(options, message, error, now);
|
|
462
|
+
await options.outbox.markFailed({
|
|
463
|
+
id: message.id,
|
|
464
|
+
claimToken: message.claimToken,
|
|
465
|
+
error,
|
|
466
|
+
deadLetter,
|
|
467
|
+
now,
|
|
468
|
+
retryAt: deadLetter
|
|
469
|
+
? undefined
|
|
470
|
+
: new Date(now.getTime() + retryDelayMs),
|
|
471
|
+
});
|
|
472
|
+
if (deadLetter) {
|
|
473
|
+
result.deadLettered += 1;
|
|
474
|
+
}
|
|
475
|
+
else {
|
|
476
|
+
result.retried += 1;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
return result;
|
|
481
|
+
}
|
|
482
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/outbox/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sort direction for list queries.
|
|
3
|
+
*/
|
|
4
|
+
export type SortDirection = "asc" | "desc";
|
|
5
|
+
/**
|
|
6
|
+
* Sort option for a whitelisted field.
|
|
7
|
+
*/
|
|
8
|
+
export type SortOption<Field extends string = string> = {
|
|
9
|
+
/**
|
|
10
|
+
* Field to sort by.
|
|
11
|
+
*/
|
|
12
|
+
field: Field;
|
|
13
|
+
/**
|
|
14
|
+
* Sort direction.
|
|
15
|
+
*/
|
|
16
|
+
direction: SortDirection;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Normalized offset pagination request.
|
|
20
|
+
*/
|
|
21
|
+
export interface OffsetPage {
|
|
22
|
+
/**
|
|
23
|
+
* Pagination mode.
|
|
24
|
+
*/
|
|
25
|
+
readonly kind: "offset";
|
|
26
|
+
/**
|
|
27
|
+
* Page size after defaulting and max-limit clamping.
|
|
28
|
+
*/
|
|
29
|
+
readonly limit: number;
|
|
30
|
+
/**
|
|
31
|
+
* Zero-based item offset.
|
|
32
|
+
*/
|
|
33
|
+
readonly offset: number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Normalized cursor pagination request.
|
|
37
|
+
*/
|
|
38
|
+
export interface CursorPage {
|
|
39
|
+
/**
|
|
40
|
+
* Pagination mode.
|
|
41
|
+
*/
|
|
42
|
+
readonly kind: "cursor";
|
|
43
|
+
/**
|
|
44
|
+
* Page size after defaulting and max-limit clamping.
|
|
45
|
+
*/
|
|
46
|
+
readonly limit: number;
|
|
47
|
+
/**
|
|
48
|
+
* Cursor for the current page, or null for the first page.
|
|
49
|
+
*/
|
|
50
|
+
readonly cursor: string | null;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Normalized pagination request.
|
|
54
|
+
*/
|
|
55
|
+
export type Page = OffsetPage | CursorPage;
|
|
56
|
+
/**
|
|
57
|
+
* Offset pagination response metadata.
|
|
58
|
+
*/
|
|
59
|
+
export type OffsetPageInfo = OffsetPage & {
|
|
60
|
+
/**
|
|
61
|
+
* Total item count.
|
|
62
|
+
*/
|
|
63
|
+
readonly total: number;
|
|
64
|
+
/**
|
|
65
|
+
* Whether another page exists.
|
|
66
|
+
*/
|
|
67
|
+
readonly hasMore: boolean;
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* Cursor pagination response metadata.
|
|
71
|
+
*/
|
|
72
|
+
export type CursorPageInfo = CursorPage & {
|
|
73
|
+
/**
|
|
74
|
+
* Cursor for the next page, or null when there is no next page.
|
|
75
|
+
*/
|
|
76
|
+
readonly nextCursor: string | null;
|
|
77
|
+
/**
|
|
78
|
+
* Whether another page exists.
|
|
79
|
+
*/
|
|
80
|
+
readonly hasMore: boolean;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Pagination response metadata.
|
|
84
|
+
*/
|
|
85
|
+
export type PageInfo = OffsetPageInfo | CursorPageInfo;
|
|
86
|
+
/**
|
|
87
|
+
* Paginated list result.
|
|
88
|
+
*/
|
|
89
|
+
export interface PageResult<TItem, TPage extends PageInfo = PageInfo> {
|
|
90
|
+
/**
|
|
91
|
+
* Page items. Result helpers clone the input array.
|
|
92
|
+
*/
|
|
93
|
+
readonly items: TItem[];
|
|
94
|
+
/**
|
|
95
|
+
* Page metadata.
|
|
96
|
+
*/
|
|
97
|
+
readonly page: TPage;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Options for normalizing pagination input.
|
|
101
|
+
*/
|
|
102
|
+
export interface NormalizePageOptions {
|
|
103
|
+
/**
|
|
104
|
+
* Limit used when the caller does not provide one.
|
|
105
|
+
*/
|
|
106
|
+
readonly defaultLimit: number;
|
|
107
|
+
/**
|
|
108
|
+
* Maximum allowed limit. Larger caller values are clamped.
|
|
109
|
+
*/
|
|
110
|
+
readonly maxLimit: number;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Raw offset pagination input.
|
|
114
|
+
*/
|
|
115
|
+
export interface OffsetPageInput {
|
|
116
|
+
/**
|
|
117
|
+
* Requested page size.
|
|
118
|
+
*/
|
|
119
|
+
readonly limit?: number | null;
|
|
120
|
+
/**
|
|
121
|
+
* Requested zero-based offset.
|
|
122
|
+
*/
|
|
123
|
+
readonly offset?: number | null;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Raw cursor pagination input.
|
|
127
|
+
*/
|
|
128
|
+
export interface CursorPageInput {
|
|
129
|
+
/**
|
|
130
|
+
* Requested page size.
|
|
131
|
+
*/
|
|
132
|
+
readonly limit?: number | null;
|
|
133
|
+
/**
|
|
134
|
+
* Requested cursor.
|
|
135
|
+
*/
|
|
136
|
+
readonly cursor?: string | null;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Error thrown when pagination input is invalid.
|
|
140
|
+
*/
|
|
141
|
+
export declare class PaginationError extends Error {
|
|
142
|
+
constructor(message: string);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Normalize offset pagination input.
|
|
146
|
+
*
|
|
147
|
+
* The limit is defaulted and clamped to `maxLimit`; offset must be a
|
|
148
|
+
* non-negative integer.
|
|
149
|
+
*/
|
|
150
|
+
export declare function normalizeOffsetPage(input: OffsetPageInput, options: NormalizePageOptions): OffsetPage;
|
|
151
|
+
/**
|
|
152
|
+
* Normalize cursor pagination input.
|
|
153
|
+
*
|
|
154
|
+
* The limit is defaulted and clamped to `maxLimit`; cursor must be a string or
|
|
155
|
+
* null.
|
|
156
|
+
*/
|
|
157
|
+
export declare function normalizeCursorPage(input: CursorPageInput, options: NormalizePageOptions): CursorPage;
|
|
158
|
+
/**
|
|
159
|
+
* Create an offset page result and derive `hasMore`.
|
|
160
|
+
*/
|
|
161
|
+
export declare function offsetPageResult<TItem>(items: readonly TItem[], page: OffsetPage, total: number): PageResult<TItem, OffsetPageInfo>;
|
|
162
|
+
/**
|
|
163
|
+
* Create a cursor page result and derive `hasMore` from `nextCursor`.
|
|
164
|
+
*/
|
|
165
|
+
export declare function cursorPageResult<TItem>(items: readonly TItem[], page: CursorPage, nextCursor: string | null): PageResult<TItem, CursorPageInfo>;
|
|
166
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pagination/index.ts"],"names":[],"mappings":"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"}
|