@beignet/core 0.0.1 → 0.0.3

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.
Files changed (287) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/README.md +202 -8
  3. package/dist/application/index.d.ts +93 -9
  4. package/dist/application/index.d.ts.map +1 -1
  5. package/dist/application/index.js +11 -11
  6. package/dist/application/index.js.map +1 -1
  7. package/dist/client/client.d.ts +73 -12
  8. package/dist/client/client.d.ts.map +1 -1
  9. package/dist/client/client.js +37 -12
  10. package/dist/client/client.js.map +1 -1
  11. package/dist/client/index.d.ts +12 -0
  12. package/dist/client/index.d.ts.map +1 -1
  13. package/dist/client/index.js +6 -0
  14. package/dist/client/index.js.map +1 -1
  15. package/dist/client/types.d.ts +69 -8
  16. package/dist/client/types.d.ts.map +1 -1
  17. package/dist/config/index.d.ts +84 -0
  18. package/dist/config/index.d.ts.map +1 -1
  19. package/dist/config/index.js +36 -0
  20. package/dist/config/index.js.map +1 -1
  21. package/dist/contracts/contract-builder.d.ts +49 -22
  22. package/dist/contracts/contract-builder.d.ts.map +1 -1
  23. package/dist/contracts/contract-builder.js +48 -21
  24. package/dist/contracts/contract-builder.js.map +1 -1
  25. package/dist/contracts/contract-group.d.ts +35 -19
  26. package/dist/contracts/contract-group.d.ts.map +1 -1
  27. package/dist/contracts/contract-group.js +35 -19
  28. package/dist/contracts/contract-group.js.map +1 -1
  29. package/dist/contracts/contract-like.d.ts +4 -4
  30. package/dist/contracts/contract-like.d.ts.map +1 -1
  31. package/dist/contracts/contract-like.js +2 -1
  32. package/dist/contracts/contract-like.js.map +1 -1
  33. package/dist/contracts/index.d.ts +28 -0
  34. package/dist/contracts/index.d.ts.map +1 -1
  35. package/dist/contracts/index.js +12 -0
  36. package/dist/contracts/index.js.map +1 -1
  37. package/dist/contracts/openapi-meta.d.ts +8 -8
  38. package/dist/contracts/openapi-meta.d.ts.map +1 -1
  39. package/dist/contracts/path-template.d.ts +27 -0
  40. package/dist/contracts/path-template.d.ts.map +1 -1
  41. package/dist/contracts/path-template.js +6 -0
  42. package/dist/contracts/path-template.js.map +1 -1
  43. package/dist/contracts/types.d.ts +104 -10
  44. package/dist/contracts/types.d.ts.map +1 -1
  45. package/dist/contracts/types.js +15 -0
  46. package/dist/contracts/types.js.map +1 -1
  47. package/dist/contracts/utils.d.ts +6 -0
  48. package/dist/contracts/utils.d.ts.map +1 -1
  49. package/dist/contracts/utils.js +6 -0
  50. package/dist/contracts/utils.js.map +1 -1
  51. package/dist/domain/entity.d.ts +22 -11
  52. package/dist/domain/entity.d.ts.map +1 -1
  53. package/dist/domain/entity.js +5 -1
  54. package/dist/domain/entity.js.map +1 -1
  55. package/dist/domain/events.d.ts +5 -2
  56. package/dist/domain/events.d.ts.map +1 -1
  57. package/dist/domain/events.js +4 -1
  58. package/dist/domain/events.js.map +1 -1
  59. package/dist/domain/value-object.d.ts +19 -9
  60. package/dist/domain/value-object.d.ts.map +1 -1
  61. package/dist/domain/value-object.js +5 -1
  62. package/dist/domain/value-object.js.map +1 -1
  63. package/dist/errors/catalog.d.ts +40 -16
  64. package/dist/errors/catalog.d.ts.map +1 -1
  65. package/dist/errors/catalog.js +18 -7
  66. package/dist/errors/catalog.js.map +1 -1
  67. package/dist/errors/response.d.ts +16 -4
  68. package/dist/errors/response.d.ts.map +1 -1
  69. package/dist/errors/response.js +3 -3
  70. package/dist/errors/response.js.map +1 -1
  71. package/dist/errors/validation.d.ts +10 -1
  72. package/dist/errors/validation.d.ts.map +1 -1
  73. package/dist/errors/validation.js +3 -0
  74. package/dist/errors/validation.js.map +1 -1
  75. package/dist/events/index.d.ts +133 -0
  76. package/dist/events/index.d.ts.map +1 -1
  77. package/dist/events/index.js +30 -0
  78. package/dist/events/index.js.map +1 -1
  79. package/dist/idempotency/index.d.ts +355 -0
  80. package/dist/idempotency/index.d.ts.map +1 -0
  81. package/dist/idempotency/index.js +360 -0
  82. package/dist/idempotency/index.js.map +1 -0
  83. package/dist/jobs/index.d.ts +248 -4
  84. package/dist/jobs/index.d.ts.map +1 -1
  85. package/dist/jobs/index.js +183 -1
  86. package/dist/jobs/index.js.map +1 -1
  87. package/dist/mail/index.d.ts +149 -0
  88. package/dist/mail/index.d.ts.map +1 -1
  89. package/dist/mail/index.js +30 -0
  90. package/dist/mail/index.js.map +1 -1
  91. package/dist/notifications/index.d.ts +369 -0
  92. package/dist/notifications/index.d.ts.map +1 -0
  93. package/dist/notifications/index.js +310 -0
  94. package/dist/notifications/index.js.map +1 -0
  95. package/dist/openapi/index.d.ts +132 -16
  96. package/dist/openapi/index.d.ts.map +1 -1
  97. package/dist/openapi/index.js +1 -1
  98. package/dist/openapi/index.js.map +1 -1
  99. package/dist/outbox/index.d.ts +474 -0
  100. package/dist/outbox/index.d.ts.map +1 -0
  101. package/dist/outbox/index.js +538 -0
  102. package/dist/outbox/index.js.map +1 -0
  103. package/dist/pagination/index.d.ts +166 -0
  104. package/dist/pagination/index.d.ts.map +1 -0
  105. package/dist/pagination/index.js +96 -0
  106. package/dist/pagination/index.js.map +1 -0
  107. package/dist/ports/audit.d.ts +271 -0
  108. package/dist/ports/audit.d.ts.map +1 -1
  109. package/dist/ports/audit.js +128 -0
  110. package/dist/ports/audit.js.map +1 -1
  111. package/dist/ports/auth.d.ts +70 -0
  112. package/dist/ports/auth.d.ts.map +1 -1
  113. package/dist/ports/auth.js +30 -0
  114. package/dist/ports/auth.js.map +1 -1
  115. package/dist/ports/cache.d.ts +41 -0
  116. package/dist/ports/cache.d.ts.map +1 -1
  117. package/dist/ports/cache.js +10 -0
  118. package/dist/ports/cache.js.map +1 -1
  119. package/dist/ports/clock.d.ts +38 -0
  120. package/dist/ports/clock.d.ts.map +1 -1
  121. package/dist/ports/clock.js +20 -0
  122. package/dist/ports/clock.js.map +1 -1
  123. package/dist/ports/id-generator.d.ts +37 -0
  124. package/dist/ports/id-generator.d.ts.map +1 -1
  125. package/dist/ports/id-generator.js +22 -0
  126. package/dist/ports/id-generator.js.map +1 -1
  127. package/dist/ports/index.d.ts +83 -0
  128. package/dist/ports/index.d.ts.map +1 -1
  129. package/dist/ports/index.js +41 -5
  130. package/dist/ports/index.js.map +1 -1
  131. package/dist/ports/logger.d.ts +56 -0
  132. package/dist/ports/logger.d.ts.map +1 -1
  133. package/dist/ports/logger.js +17 -0
  134. package/dist/ports/logger.js.map +1 -1
  135. package/dist/ports/policy.d.ts +132 -0
  136. package/dist/ports/policy.d.ts.map +1 -1
  137. package/dist/ports/policy.js +45 -0
  138. package/dist/ports/policy.js.map +1 -1
  139. package/dist/ports/rate-limit.d.ts +25 -0
  140. package/dist/ports/rate-limit.d.ts.map +1 -1
  141. package/dist/ports/rate-limit.js +10 -0
  142. package/dist/ports/rate-limit.js.map +1 -1
  143. package/dist/ports/redaction.d.ts +101 -0
  144. package/dist/ports/redaction.d.ts.map +1 -1
  145. package/dist/ports/redaction.js +59 -0
  146. package/dist/ports/redaction.js.map +1 -1
  147. package/dist/ports/storage.d.ts +100 -0
  148. package/dist/ports/storage.d.ts.map +1 -1
  149. package/dist/ports/storage.js +10 -0
  150. package/dist/ports/storage.js.map +1 -1
  151. package/dist/ports/testing.d.ts +47 -0
  152. package/dist/ports/testing.d.ts.map +1 -1
  153. package/dist/ports/testing.js +23 -0
  154. package/dist/ports/testing.js.map +1 -1
  155. package/dist/ports/unit-of-work.d.ts +60 -3
  156. package/dist/ports/unit-of-work.d.ts.map +1 -1
  157. package/dist/ports/unit-of-work.js +11 -2
  158. package/dist/ports/unit-of-work.js.map +1 -1
  159. package/dist/providers/instrumentation.d.ts +205 -1
  160. package/dist/providers/instrumentation.d.ts.map +1 -1
  161. package/dist/providers/instrumentation.js +14 -0
  162. package/dist/providers/instrumentation.js.map +1 -1
  163. package/dist/providers/provider.d.ts +14 -1
  164. package/dist/providers/provider.d.ts.map +1 -1
  165. package/dist/providers/provider.js.map +1 -1
  166. package/dist/schedules/index.d.ts +246 -0
  167. package/dist/schedules/index.d.ts.map +1 -1
  168. package/dist/schedules/index.js +27 -0
  169. package/dist/schedules/index.js.map +1 -1
  170. package/dist/server/health.d.ts +14 -5
  171. package/dist/server/health.d.ts.map +1 -1
  172. package/dist/server/health.js +5 -2
  173. package/dist/server/health.js.map +1 -1
  174. package/dist/server/hooks/auth.d.ts +68 -26
  175. package/dist/server/hooks/auth.d.ts.map +1 -1
  176. package/dist/server/hooks/auth.js +44 -55
  177. package/dist/server/hooks/auth.js.map +1 -1
  178. package/dist/server/hooks/cors.d.ts +27 -0
  179. package/dist/server/hooks/cors.d.ts.map +1 -1
  180. package/dist/server/hooks/cors.js +12 -0
  181. package/dist/server/hooks/cors.js.map +1 -1
  182. package/dist/server/hooks/errors.d.ts +15 -6
  183. package/dist/server/hooks/errors.d.ts.map +1 -1
  184. package/dist/server/hooks/errors.js.map +1 -1
  185. package/dist/server/hooks/index.d.ts +4 -1
  186. package/dist/server/hooks/index.d.ts.map +1 -1
  187. package/dist/server/hooks/index.js +3 -0
  188. package/dist/server/hooks/index.js.map +1 -1
  189. package/dist/server/hooks/logging.d.ts +36 -0
  190. package/dist/server/hooks/logging.d.ts.map +1 -1
  191. package/dist/server/hooks/logging.js +6 -0
  192. package/dist/server/hooks/logging.js.map +1 -1
  193. package/dist/server/hooks/rate-limit.d.ts +33 -0
  194. package/dist/server/hooks/rate-limit.d.ts.map +1 -1
  195. package/dist/server/hooks/rate-limit.js +11 -0
  196. package/dist/server/hooks/rate-limit.js.map +1 -1
  197. package/dist/server/http.d.ts +222 -0
  198. package/dist/server/http.d.ts.map +1 -1
  199. package/dist/server/http.js +20 -1
  200. package/dist/server/http.js.map +1 -1
  201. package/dist/server/index.d.ts +19 -1
  202. package/dist/server/index.d.ts.map +1 -1
  203. package/dist/server/index.js +7 -1
  204. package/dist/server/index.js.map +1 -1
  205. package/dist/server/openapi.d.ts +5 -3
  206. package/dist/server/openapi.d.ts.map +1 -1
  207. package/dist/server/openapi.js +4 -2
  208. package/dist/server/openapi.js.map +1 -1
  209. package/dist/server/providers/loadProviderConfig.d.ts +9 -0
  210. package/dist/server/providers/loadProviderConfig.d.ts.map +1 -1
  211. package/dist/server/providers/loadProviderConfig.js +9 -0
  212. package/dist/server/providers/loadProviderConfig.js.map +1 -1
  213. package/dist/server/server.d.ts +159 -19
  214. package/dist/server/server.d.ts.map +1 -1
  215. package/dist/server/server.js +72 -31
  216. package/dist/server/server.js.map +1 -1
  217. package/dist/testing/index.d.ts +171 -0
  218. package/dist/testing/index.d.ts.map +1 -0
  219. package/dist/testing/index.js +127 -0
  220. package/dist/testing/index.js.map +1 -0
  221. package/dist/uploads/client.d.ts +278 -0
  222. package/dist/uploads/client.d.ts.map +1 -0
  223. package/dist/uploads/client.js +428 -0
  224. package/dist/uploads/client.js.map +1 -0
  225. package/dist/uploads/index.d.ts +361 -0
  226. package/dist/uploads/index.d.ts.map +1 -0
  227. package/dist/uploads/index.js +543 -0
  228. package/dist/uploads/index.js.map +1 -0
  229. package/package.json +31 -2
  230. package/src/application/index.ts +85 -22
  231. package/src/client/client.ts +73 -12
  232. package/src/client/index.ts +12 -0
  233. package/src/client/types.ts +70 -9
  234. package/src/config/index.ts +86 -0
  235. package/src/contracts/contract-builder.ts +49 -22
  236. package/src/contracts/contract-group.ts +35 -19
  237. package/src/contracts/contract-like.ts +4 -4
  238. package/src/contracts/index.ts +28 -1
  239. package/src/contracts/openapi-meta.ts +8 -8
  240. package/src/contracts/path-template.ts +27 -0
  241. package/src/contracts/types.ts +111 -10
  242. package/src/contracts/utils.ts +6 -0
  243. package/src/domain/entity.ts +22 -11
  244. package/src/domain/events.ts +5 -2
  245. package/src/domain/value-object.ts +19 -9
  246. package/src/errors/catalog.ts +40 -16
  247. package/src/errors/response.ts +16 -4
  248. package/src/errors/validation.ts +10 -1
  249. package/src/events/index.ts +134 -0
  250. package/src/idempotency/index.ts +767 -0
  251. package/src/jobs/index.ts +437 -5
  252. package/src/mail/index.ts +149 -0
  253. package/src/notifications/index.ts +771 -0
  254. package/src/openapi/index.ts +133 -16
  255. package/src/outbox/index.ts +1104 -0
  256. package/src/pagination/index.ts +278 -0
  257. package/src/ports/audit.ts +271 -0
  258. package/src/ports/auth.ts +70 -0
  259. package/src/ports/cache.ts +41 -0
  260. package/src/ports/clock.ts +38 -0
  261. package/src/ports/id-generator.ts +37 -0
  262. package/src/ports/index.ts +106 -11
  263. package/src/ports/logger.ts +56 -0
  264. package/src/ports/policy.ts +133 -0
  265. package/src/ports/rate-limit.ts +25 -0
  266. package/src/ports/redaction.ts +101 -0
  267. package/src/ports/storage.ts +100 -0
  268. package/src/ports/testing.ts +47 -0
  269. package/src/ports/unit-of-work.ts +60 -3
  270. package/src/providers/instrumentation.ts +211 -1
  271. package/src/providers/provider.ts +14 -1
  272. package/src/schedules/index.ts +247 -0
  273. package/src/server/health.ts +14 -5
  274. package/src/server/hooks/auth.ts +105 -120
  275. package/src/server/hooks/cors.ts +27 -0
  276. package/src/server/hooks/errors.ts +15 -6
  277. package/src/server/hooks/index.ts +4 -5
  278. package/src/server/hooks/logging.ts +36 -0
  279. package/src/server/hooks/rate-limit.ts +33 -0
  280. package/src/server/http.ts +249 -1
  281. package/src/server/index.ts +19 -1
  282. package/src/server/openapi.ts +5 -3
  283. package/src/server/providers/loadProviderConfig.ts +9 -0
  284. package/src/server/server.ts +296 -30
  285. package/src/testing/index.ts +348 -0
  286. package/src/uploads/client.ts +861 -0
  287. package/src/uploads/index.ts +1067 -0
@@ -0,0 +1,360 @@
1
+ /**
2
+ * @beignet/core/idempotency
3
+ *
4
+ * Idempotency primitives for retry-safe commands, webhooks, and jobs.
5
+ */
6
+ /**
7
+ * Error thrown when an idempotency key is reused with a different fingerprint.
8
+ */
9
+ export class IdempotencyConflictError extends Error {
10
+ namespace;
11
+ key;
12
+ scopeKey;
13
+ storedFingerprint;
14
+ receivedFingerprint;
15
+ constructor(args) {
16
+ super(`Idempotency key "${args.key}" conflicts with a different payload in namespace "${args.namespace}".`);
17
+ this.name = "IdempotencyConflictError";
18
+ this.namespace = args.namespace;
19
+ this.key = args.key;
20
+ this.scopeKey = args.scopeKey;
21
+ this.storedFingerprint = args.storedFingerprint;
22
+ this.receivedFingerprint = args.receivedFingerprint;
23
+ }
24
+ }
25
+ /**
26
+ * Error thrown when an idempotency key is already reserved by in-progress work.
27
+ */
28
+ export class IdempotencyInProgressError extends Error {
29
+ namespace;
30
+ key;
31
+ scopeKey;
32
+ constructor(args) {
33
+ super(`Idempotency key "${args.key}" is already in progress in namespace "${args.namespace}".`);
34
+ this.name = "IdempotencyInProgressError";
35
+ this.namespace = args.namespace;
36
+ this.key = args.key;
37
+ this.scopeKey = args.scopeKey;
38
+ }
39
+ }
40
+ /**
41
+ * Error thrown when replay is disabled for a completed idempotency key.
42
+ */
43
+ export class IdempotencyReplayError extends Error {
44
+ namespace;
45
+ key;
46
+ scopeKey;
47
+ constructor(args) {
48
+ super(`Idempotency key "${args.key}" already completed in namespace "${args.namespace}".`);
49
+ this.name = "IdempotencyReplayError";
50
+ this.namespace = args.namespace;
51
+ this.key = args.key;
52
+ this.scopeKey = args.scopeKey;
53
+ }
54
+ }
55
+ /**
56
+ * Error thrown when fingerprint input cannot be canonicalized.
57
+ */
58
+ export class IdempotencyFingerprintError extends Error {
59
+ constructor(message) {
60
+ super(message);
61
+ this.name = "IdempotencyFingerprintError";
62
+ }
63
+ }
64
+ function assertNonEmptyString(name, value) {
65
+ if (typeof value !== "string" || value.trim().length === 0) {
66
+ throw new Error(`${name} must be a non-empty string`);
67
+ }
68
+ }
69
+ function assertTtl(ttlSec) {
70
+ if (ttlSec === undefined)
71
+ return;
72
+ if (!Number.isInteger(ttlSec) || ttlSec <= 0) {
73
+ throw new Error("ttlSec must be a positive integer when provided");
74
+ }
75
+ }
76
+ function normalizeScopeValue(value) {
77
+ if (value === undefined)
78
+ return "";
79
+ if (value === null)
80
+ return "null";
81
+ return String(value);
82
+ }
83
+ /**
84
+ * Normalize an idempotency scope into a stable string.
85
+ */
86
+ export function normalizeIdempotencyScope(scope) {
87
+ if (scope === undefined)
88
+ return "global";
89
+ if (typeof scope === "string")
90
+ return scope;
91
+ return Object.keys(scope)
92
+ .sort()
93
+ .map((key) => `${key}:${normalizeScopeValue(scope[key])}`)
94
+ .join("|");
95
+ }
96
+ /**
97
+ * Create the stable storage key for an idempotency operation.
98
+ */
99
+ export function createIdempotencyStorageKey(input) {
100
+ assertNonEmptyString("namespace", input.namespace);
101
+ assertNonEmptyString("key", input.key);
102
+ return [
103
+ input.namespace,
104
+ normalizeIdempotencyScope(input.scope),
105
+ input.key,
106
+ ].join("\u0000");
107
+ }
108
+ function resolveExpiresAt(ttlSec, now) {
109
+ assertTtl(ttlSec);
110
+ return ttlSec === undefined ? null : new Date(now.getTime() + ttlSec * 1000);
111
+ }
112
+ function isExpired(entry, now) {
113
+ return entry.expiresAt !== null && entry.expiresAt.getTime() <= now.getTime();
114
+ }
115
+ function reservationFromRecord(record, receivedFingerprint) {
116
+ if (record.fingerprint !== receivedFingerprint) {
117
+ return {
118
+ status: "conflict",
119
+ namespace: record.namespace,
120
+ key: record.key,
121
+ scopeKey: record.scopeKey,
122
+ storedFingerprint: record.fingerprint,
123
+ receivedFingerprint,
124
+ reservedAt: record.reservedAt,
125
+ completedAt: record.completedAt,
126
+ expiresAt: record.expiresAt,
127
+ };
128
+ }
129
+ if (record.status === "completed" && record.completedAt) {
130
+ return {
131
+ status: "replay",
132
+ namespace: record.namespace,
133
+ key: record.key,
134
+ scopeKey: record.scopeKey,
135
+ fingerprint: record.fingerprint,
136
+ result: record.result,
137
+ reservedAt: record.reservedAt,
138
+ completedAt: record.completedAt,
139
+ expiresAt: record.expiresAt,
140
+ };
141
+ }
142
+ return {
143
+ status: "inProgress",
144
+ namespace: record.namespace,
145
+ key: record.key,
146
+ scopeKey: record.scopeKey,
147
+ fingerprint: record.fingerprint,
148
+ reservedAt: record.reservedAt,
149
+ expiresAt: record.expiresAt,
150
+ };
151
+ }
152
+ /**
153
+ * Create an in-memory idempotency store for tests and local examples.
154
+ *
155
+ * The memory store is process-local and not suitable for multi-process
156
+ * production deployments.
157
+ */
158
+ export function createMemoryIdempotencyStore() {
159
+ const records = new Map();
160
+ return {
161
+ get entries() {
162
+ return [...records.values()];
163
+ },
164
+ async reserve(input) {
165
+ assertNonEmptyString("namespace", input.namespace);
166
+ assertNonEmptyString("key", input.key);
167
+ assertNonEmptyString("fingerprint", input.fingerprint);
168
+ assertTtl(input.ttlSec);
169
+ const now = new Date();
170
+ const storageKey = createIdempotencyStorageKey(input);
171
+ const existing = records.get(storageKey);
172
+ if (existing && !isExpired(existing, now)) {
173
+ return reservationFromRecord(existing, input.fingerprint);
174
+ }
175
+ if (existing) {
176
+ records.delete(storageKey);
177
+ }
178
+ const record = {
179
+ namespace: input.namespace,
180
+ key: input.key,
181
+ scopeKey: normalizeIdempotencyScope(input.scope),
182
+ fingerprint: input.fingerprint,
183
+ status: "in-progress",
184
+ reservedAt: now,
185
+ expiresAt: resolveExpiresAt(input.ttlSec, now),
186
+ };
187
+ records.set(storageKey, record);
188
+ return {
189
+ status: "reserved",
190
+ namespace: record.namespace,
191
+ key: record.key,
192
+ scopeKey: record.scopeKey,
193
+ fingerprint: record.fingerprint,
194
+ reservedAt: record.reservedAt,
195
+ expiresAt: record.expiresAt,
196
+ };
197
+ },
198
+ async complete(input) {
199
+ assertNonEmptyString("namespace", input.namespace);
200
+ assertNonEmptyString("key", input.key);
201
+ assertNonEmptyString("fingerprint", input.fingerprint);
202
+ const storageKey = createIdempotencyStorageKey(input);
203
+ const existing = records.get(storageKey);
204
+ if (!existing || existing.fingerprint !== input.fingerprint)
205
+ return;
206
+ existing.status = "completed";
207
+ existing.result = input.result;
208
+ existing.completedAt = new Date();
209
+ },
210
+ async fail(input) {
211
+ assertNonEmptyString("namespace", input.namespace);
212
+ assertNonEmptyString("key", input.key);
213
+ assertNonEmptyString("fingerprint", input.fingerprint);
214
+ const storageKey = createIdempotencyStorageKey(input);
215
+ const existing = records.get(storageKey);
216
+ if (!existing || existing.fingerprint !== input.fingerprint)
217
+ return;
218
+ if (existing.status === "completed")
219
+ return;
220
+ records.delete(storageKey);
221
+ },
222
+ clear() {
223
+ records.clear();
224
+ },
225
+ };
226
+ }
227
+ /**
228
+ * Run an operation behind an idempotency reservation.
229
+ *
230
+ * The flow is: reserve the key, replay completed matching results, reject
231
+ * in-progress/conflicting keys, run the operation for new reservations, then
232
+ * complete or fail the reservation. Callers are responsible for choosing a
233
+ * namespace, scope, key, and fingerprint that match their business operation.
234
+ */
235
+ export async function runIdempotently(idempotency, options) {
236
+ const operation = {
237
+ namespace: options.namespace,
238
+ key: options.key,
239
+ scope: options.scope,
240
+ fingerprint: options.fingerprint,
241
+ ttlSec: options.ttlSec,
242
+ };
243
+ const reservation = await idempotency.reserve(operation);
244
+ switch (reservation.status) {
245
+ case "replay": {
246
+ if (options.replay === "error") {
247
+ throw new IdempotencyReplayError(reservation);
248
+ }
249
+ return reservation.result;
250
+ }
251
+ case "inProgress": {
252
+ throw new IdempotencyInProgressError(reservation);
253
+ }
254
+ case "conflict": {
255
+ throw new IdempotencyConflictError(reservation);
256
+ }
257
+ case "reserved": {
258
+ try {
259
+ const result = await options.run();
260
+ await idempotency.complete({
261
+ namespace: operation.namespace,
262
+ key: operation.key,
263
+ scope: operation.scope,
264
+ fingerprint: operation.fingerprint,
265
+ result,
266
+ });
267
+ return result;
268
+ }
269
+ catch (error) {
270
+ await idempotency.fail({
271
+ namespace: operation.namespace,
272
+ key: operation.key,
273
+ scope: operation.scope,
274
+ fingerprint: operation.fingerprint,
275
+ error,
276
+ });
277
+ throw error;
278
+ }
279
+ }
280
+ }
281
+ }
282
+ function normalizeOmitPath(path) {
283
+ if (typeof path === "string")
284
+ return path.split(".").filter(Boolean);
285
+ return path.map(String);
286
+ }
287
+ function shouldOmitPath(path, omit) {
288
+ return omit.some((entry) => {
289
+ const omitPath = normalizeOmitPath(entry);
290
+ if (omitPath.length !== path.length)
291
+ return false;
292
+ return omitPath.every((segment, index) => segment === path[index]);
293
+ });
294
+ }
295
+ function canonicalize(value, options, path, seen) {
296
+ if (shouldOmitPath(path, options.omit ?? [])) {
297
+ return undefined;
298
+ }
299
+ if (value === undefined || typeof value === "function") {
300
+ return undefined;
301
+ }
302
+ if (value === null ||
303
+ typeof value === "string" ||
304
+ typeof value === "boolean") {
305
+ return value;
306
+ }
307
+ if (typeof value === "number") {
308
+ if (!Number.isFinite(value)) {
309
+ throw new IdempotencyFingerprintError("Cannot fingerprint non-finite numeric values.");
310
+ }
311
+ return value;
312
+ }
313
+ if (typeof value === "bigint") {
314
+ return value.toString();
315
+ }
316
+ if (value instanceof Date) {
317
+ return value.toISOString();
318
+ }
319
+ if (Array.isArray(value)) {
320
+ return value.map((item, index) => canonicalize(item, options, [...path, String(index)], seen) ?? null);
321
+ }
322
+ if (typeof value === "object") {
323
+ if (seen.has(value)) {
324
+ throw new IdempotencyFingerprintError("Cannot fingerprint circular values.");
325
+ }
326
+ seen.add(value);
327
+ const result = {};
328
+ for (const key of Object.keys(value).sort()) {
329
+ const nestedValue = canonicalize(value[key], options, [...path, key], seen);
330
+ if (nestedValue !== undefined) {
331
+ result[key] = nestedValue;
332
+ }
333
+ }
334
+ seen.delete(value);
335
+ return result;
336
+ }
337
+ throw new IdempotencyFingerprintError(`Cannot fingerprint value of type "${typeof value}".`);
338
+ }
339
+ function bytesToHex(bytes) {
340
+ return [...new Uint8Array(bytes)]
341
+ .map((byte) => byte.toString(16).padStart(2, "0"))
342
+ .join("");
343
+ }
344
+ /**
345
+ * Create a SHA-256 fingerprint from a canonicalized value.
346
+ *
347
+ * Object keys are sorted, `undefined` and functions are omitted, `Date` values
348
+ * become ISO strings, BigInts become strings, and circular or non-finite values
349
+ * throw. Exact omit paths may be supplied as dotted strings or string arrays.
350
+ */
351
+ export async function createIdempotencyFingerprint(value, options = {}) {
352
+ if (!globalThis.crypto?.subtle) {
353
+ throw new IdempotencyFingerprintError("Cannot create an idempotency fingerprint because Web Crypto is unavailable.");
354
+ }
355
+ const canonical = canonicalize(value, options, [], new WeakSet());
356
+ const json = JSON.stringify(canonical ?? null);
357
+ const digest = await globalThis.crypto.subtle.digest("SHA-256", new TextEncoder().encode(json));
358
+ return `sha256:${bytesToHex(digest)}`;
359
+ }
360
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/idempotency/index.ts"],"names":[],"mappings":"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"}
@@ -1,56 +1,300 @@
1
1
  import type { StandardSchemaV1 } from "@standard-schema/spec";
2
+ /**
3
+ * Any Standard Schema compatible validator.
4
+ */
2
5
  export type StandardSchema = StandardSchemaV1<unknown, unknown>;
6
+ /**
7
+ * Value or promise of that value.
8
+ */
3
9
  export type MaybePromise<T> = T | Promise<T>;
10
+ /**
11
+ * Infer the parsed output type from a Standard Schema.
12
+ */
4
13
  export type InferSchemaOutput<T extends StandardSchemaV1> = StandardSchemaV1.InferOutput<T>;
14
+ /**
15
+ * Duration accepted by retry helpers. Numbers are milliseconds.
16
+ */
17
+ export type JobRetryDuration = number | `${number}ms` | `${number}s` | `${number}m` | `${number}h`;
18
+ /**
19
+ * Retry strategy understood by Beignet job adapters.
20
+ */
21
+ export type JobRetryStrategy = "none" | "fixed" | "exponential";
22
+ /**
23
+ * Arguments passed to a retry predicate.
24
+ */
25
+ export interface JobRetryPredicateArgs {
26
+ /**
27
+ * Error thrown by the previous attempt.
28
+ */
29
+ error: unknown;
30
+ /**
31
+ * One-based attempt number that just failed.
32
+ */
33
+ attempt: number;
34
+ /**
35
+ * Maximum attempts allowed for this delivery.
36
+ */
37
+ maxAttempts: number;
38
+ /**
39
+ * Job name when the retry decision is for a job.
40
+ */
41
+ jobName?: string;
42
+ }
43
+ /**
44
+ * Return whether a failed attempt should be retried.
45
+ */
46
+ export type JobRetryPredicate = (args: JobRetryPredicateArgs) => boolean;
47
+ /**
48
+ * Job definition created by `defineJob(...)`.
49
+ */
5
50
  export interface JobDef<Name extends string = string, Payload extends StandardSchema = StandardSchema, Ctx = unknown> {
51
+ /**
52
+ * Discriminator for job definitions.
53
+ */
6
54
  readonly kind: "job";
55
+ /**
56
+ * Stable job name used by dispatchers and provider adapters.
57
+ */
7
58
  readonly name: Name;
59
+ /**
60
+ * Standard Schema payload validator.
61
+ */
8
62
  readonly payload: Payload;
63
+ /**
64
+ * Optional human-readable description for docs and tooling.
65
+ */
9
66
  readonly description?: string;
67
+ /**
68
+ * Retry metadata for durable job providers.
69
+ */
10
70
  readonly retry?: JobRetryOptions;
71
+ /**
72
+ * Handle a parsed job payload.
73
+ */
11
74
  handle(args: JobHandleArgs<JobDef<Name, Payload, Ctx>, Ctx>): MaybePromise<void>;
12
75
  }
76
+ /**
77
+ * Infer the parsed payload type for a job definition.
78
+ */
13
79
  export type InferJobPayload<J extends JobDef> = J["payload"] extends StandardSchemaV1<unknown, infer Output> ? Output : never;
80
+ /**
81
+ * Arguments passed to a job handler.
82
+ */
14
83
  export interface JobHandleArgs<J extends JobDef, Ctx> {
84
+ /**
85
+ * Job definition being handled.
86
+ */
15
87
  job: J;
88
+ /**
89
+ * Parsed job payload.
90
+ */
16
91
  payload: InferJobPayload<J>;
92
+ /**
93
+ * Handler context.
94
+ */
17
95
  ctx: Ctx;
18
96
  }
97
+ /**
98
+ * Retry metadata that durable job providers can map to their own retry model.
99
+ */
19
100
  export interface JobRetryOptions {
20
101
  /**
21
- * Maximum number of retry attempts a durable job adapter should request.
22
- *
23
- * Providers may impose their own range limits. For example, the Inngest
24
- * adapter validates this as a function-level `retries` value.
102
+ * Retry strategy. Raw objects without a strategy default to exponential
103
+ * backoff so existing `{ attempts }` style definitions stay meaningful.
104
+ */
105
+ strategy?: JobRetryStrategy;
106
+ /**
107
+ * Maximum total attempts, including the first attempt.
25
108
  */
26
109
  attempts?: number;
110
+ /**
111
+ * Delay between attempts for fixed retry policies.
112
+ */
113
+ delay?: JobRetryDuration;
114
+ /**
115
+ * Initial delay for exponential retry policies.
116
+ */
117
+ initialDelay?: JobRetryDuration;
118
+ /**
119
+ * Maximum delay for exponential retry policies.
120
+ */
121
+ maxDelay?: JobRetryDuration;
122
+ /**
123
+ * Exponential multiplier. Defaults to `2`.
124
+ */
125
+ factor?: number;
126
+ /**
127
+ * Whether adapters that compute delays should add jitter.
128
+ */
129
+ jitter?: boolean;
130
+ /**
131
+ * Optional app-owned retry classifier.
132
+ */
133
+ retryIf?: JobRetryPredicate;
27
134
  }
135
+ /**
136
+ * Options for declaring a typed job.
137
+ */
28
138
  export interface DefineJobOptions<Name extends string, Payload extends StandardSchema, Ctx> {
139
+ /**
140
+ * Standard Schema payload validator.
141
+ */
29
142
  payload: Payload;
143
+ /**
144
+ * Optional human-readable description for docs and tooling.
145
+ */
30
146
  description?: string;
147
+ /**
148
+ * Retry metadata for durable job providers.
149
+ */
31
150
  retry?: JobRetryOptions;
151
+ /**
152
+ * Handle a parsed job payload.
153
+ */
32
154
  handle(args: JobHandleArgs<JobDef<Name, Payload, Ctx>, Ctx>): MaybePromise<void>;
33
155
  }
156
+ /**
157
+ * Options for a fixed job retry policy.
158
+ */
159
+ export interface FixedJobRetryOptions {
160
+ /**
161
+ * Maximum total attempts, including the first attempt.
162
+ */
163
+ attempts: number;
164
+ /**
165
+ * Delay between attempts.
166
+ */
167
+ delay: JobRetryDuration;
168
+ /**
169
+ * Optional app-owned retry classifier.
170
+ */
171
+ retryIf?: JobRetryPredicate;
172
+ }
173
+ /**
174
+ * Options for an exponential job retry policy.
175
+ */
176
+ export interface ExponentialJobRetryOptions {
177
+ /**
178
+ * Maximum total attempts, including the first attempt.
179
+ */
180
+ attempts: number;
181
+ /**
182
+ * Initial delay. Defaults to `1s`.
183
+ */
184
+ initialDelay?: JobRetryDuration;
185
+ /**
186
+ * Maximum delay. Defaults to `1m`.
187
+ */
188
+ maxDelay?: JobRetryDuration;
189
+ /**
190
+ * Exponential multiplier. Defaults to `2`.
191
+ */
192
+ factor?: number;
193
+ /**
194
+ * Whether computed delays should include jitter.
195
+ */
196
+ jitter?: boolean;
197
+ /**
198
+ * Optional app-owned retry classifier.
199
+ */
200
+ retryIf?: JobRetryPredicate;
201
+ }
202
+ /**
203
+ * Retry helper namespace for job definitions.
204
+ */
205
+ export declare const retry: {
206
+ /**
207
+ * Disable retries. The first failure is terminal.
208
+ */
209
+ readonly none: () => JobRetryOptions;
210
+ /**
211
+ * Retry with the same delay between attempts.
212
+ */
213
+ readonly fixed: (options: FixedJobRetryOptions) => JobRetryOptions;
214
+ /**
215
+ * Retry with exponential backoff.
216
+ */
217
+ readonly exponential: (options: ExponentialJobRetryOptions) => JobRetryOptions;
218
+ };
219
+ /**
220
+ * Options for the inline job dispatcher.
221
+ */
34
222
  export interface InlineJobDispatcherOptions<Ctx> {
223
+ /**
224
+ * Static job context or factory evaluated for each dispatched job.
225
+ */
35
226
  ctx?: Ctx | (() => MaybePromise<Ctx>);
227
+ /**
228
+ * Called when a dispatched inline job fails. When omitted, errors are
229
+ * rethrown to the caller.
230
+ */
36
231
  onError?: (error: unknown, job: JobDef<string, StandardSchema, Ctx>) => void;
37
232
  }
233
+ /**
234
+ * Local/test job dispatcher that executes job handlers inline.
235
+ */
38
236
  export interface InlineJobDispatcher<Ctx = unknown> {
237
+ /**
238
+ * Validate a payload and run the job handler immediately.
239
+ */
39
240
  dispatch<J extends JobDef<string, StandardSchema, Ctx>>(job: J, payload: InferJobPayload<J>): Promise<void>;
40
241
  }
242
+ /**
243
+ * Context-bound job helper factory.
244
+ */
41
245
  export interface JobHandlers<Ctx> {
246
+ /**
247
+ * Define a job with the bound context type.
248
+ */
42
249
  defineJob<Name extends string, Payload extends StandardSchema>(name: Name, options: DefineJobOptions<Name, Payload, Ctx>): JobDef<Name, Payload, Ctx>;
250
+ /**
251
+ * Create an inline dispatcher with the bound context type.
252
+ */
43
253
  createInlineJobDispatcher(options?: InlineJobDispatcherOptions<Ctx>): InlineJobDispatcher<Ctx>;
44
254
  }
255
+ /**
256
+ * Error thrown when job payload validation fails.
257
+ */
45
258
  export declare class JobValidationError extends Error {
259
+ /**
260
+ * Raw Standard Schema validation issues.
261
+ */
46
262
  readonly issues: readonly StandardSchemaV1.Issue[];
47
263
  constructor(args: {
48
264
  name: string;
49
265
  issues: readonly StandardSchemaV1.Issue[];
50
266
  });
51
267
  }
268
+ /**
269
+ * Return the maximum total attempts configured by a retry policy.
270
+ */
271
+ export declare function getJobRetryMaxAttempts(options: JobRetryOptions | undefined): number | undefined;
272
+ /**
273
+ * Return whether a failed job attempt should be retried.
274
+ */
275
+ export declare function shouldRetryJob(options: JobRetryOptions | undefined, args: JobRetryPredicateArgs): boolean;
276
+ /**
277
+ * Compute the next retry delay in milliseconds for a failed job attempt.
278
+ */
279
+ export declare function getJobRetryDelayMs(options: JobRetryOptions | undefined, args: Pick<JobRetryPredicateArgs, "attempt" | "error" | "jobName">): number;
280
+ /**
281
+ * Define a typed job.
282
+ *
283
+ * Retry options are provider hints. Inline dispatchers validate payloads and
284
+ * call `handle(...)` immediately; durable providers may enqueue or schedule the
285
+ * job according to their own runtime.
286
+ */
52
287
  export declare function defineJob<Name extends string, Payload extends StandardSchema, Ctx = unknown>(name: Name, options: DefineJobOptions<Name, Payload, Ctx>): JobDef<Name, Payload, Ctx>;
288
+ /**
289
+ * Validate and parse a job payload with the job's Standard Schema.
290
+ */
53
291
  export declare function parseJobPayload<J extends JobDef>(job: J, payload: unknown): Promise<InferJobPayload<J>>;
292
+ /**
293
+ * Create a local/test dispatcher that runs job handlers inline.
294
+ */
54
295
  export declare function createInlineJobDispatcher<Ctx>(options?: InlineJobDispatcherOptions<Ctx>): InlineJobDispatcher<Ctx>;
296
+ /**
297
+ * Create job helper methods bound to an application context type.
298
+ */
55
299
  export declare function createJobHandlers<Ctx>(): JobHandlers<Ctx>;
56
300
  //# sourceMappingURL=index.d.ts.map