delaykit 0.1.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.
Files changed (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +264 -0
  3. package/dist/delaykit.d.ts +77 -0
  4. package/dist/delaykit.d.ts.map +1 -0
  5. package/dist/delaykit.js +525 -0
  6. package/dist/delaykit.js.map +1 -0
  7. package/dist/duration.d.ts +7 -0
  8. package/dist/duration.d.ts.map +1 -0
  9. package/dist/duration.js +38 -0
  10. package/dist/duration.js.map +1 -0
  11. package/dist/emitter.d.ts +9 -0
  12. package/dist/emitter.d.ts.map +1 -0
  13. package/dist/emitter.js +41 -0
  14. package/dist/emitter.js.map +1 -0
  15. package/dist/executor.d.ts +41 -0
  16. package/dist/executor.d.ts.map +1 -0
  17. package/dist/executor.js +98 -0
  18. package/dist/executor.js.map +1 -0
  19. package/dist/index.d.ts +10 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +6 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/result-handler.d.ts +23 -0
  24. package/dist/result-handler.d.ts.map +1 -0
  25. package/dist/result-handler.js +155 -0
  26. package/dist/result-handler.js.map +1 -0
  27. package/dist/schedulers/polling.d.ts +46 -0
  28. package/dist/schedulers/polling.d.ts.map +1 -0
  29. package/dist/schedulers/polling.js +148 -0
  30. package/dist/schedulers/polling.js.map +1 -0
  31. package/dist/schedulers/posthook.d.ts +29 -0
  32. package/dist/schedulers/posthook.d.ts.map +1 -0
  33. package/dist/schedulers/posthook.js +49 -0
  34. package/dist/schedulers/posthook.js.map +1 -0
  35. package/dist/stores/memory.d.ts +28 -0
  36. package/dist/stores/memory.d.ts.map +1 -0
  37. package/dist/stores/memory.js +282 -0
  38. package/dist/stores/memory.js.map +1 -0
  39. package/dist/stores/postgres-migrations.d.ts +6 -0
  40. package/dist/stores/postgres-migrations.d.ts.map +1 -0
  41. package/dist/stores/postgres-migrations.js +65 -0
  42. package/dist/stores/postgres-migrations.js.map +1 -0
  43. package/dist/stores/postgres.d.ts +32 -0
  44. package/dist/stores/postgres.d.ts.map +1 -0
  45. package/dist/stores/postgres.js +382 -0
  46. package/dist/stores/postgres.js.map +1 -0
  47. package/dist/types.d.ts +192 -0
  48. package/dist/types.d.ts.map +1 -0
  49. package/dist/types.js +4 -0
  50. package/dist/types.js.map +1 -0
  51. package/package.json +80 -0
@@ -0,0 +1,29 @@
1
+ import type { Scheduler, ScheduleRequest } from "../types.js";
2
+ export interface PosthookSchedulerOptions {
3
+ /** Posthook API key. */
4
+ apiKey: string;
5
+ /** Posthook signing key for webhook verification. */
6
+ signingKey: string;
7
+ /** Base path where createHandler() is mounted (e.g., '/api/delaykit').
8
+ * Handler name is appended automatically: '/api/delaykit/send-reminder'. */
9
+ basePath: string;
10
+ /** Override the Posthook API base URL (for development). */
11
+ baseURL?: string;
12
+ }
13
+ export declare class PosthookScheduler implements Scheduler {
14
+ private client;
15
+ private basePath;
16
+ readonly signingKey: string;
17
+ constructor(options: PosthookSchedulerOptions);
18
+ /** Maximum total attempts Posthook supports (1 initial + 15 retries). */
19
+ readonly maxAttempts = 16;
20
+ schedule(req: ScheduleRequest): Promise<string | null>;
21
+ cancel(schedulerRef: string): Promise<void>;
22
+ start(): Promise<void>;
23
+ stop(): Promise<void>;
24
+ verifyDelivery<T = Record<string, unknown>>(body: string, headers: Headers | Record<string, string | string[] | undefined>): {
25
+ hookId: string;
26
+ data: T;
27
+ };
28
+ }
29
+ //# sourceMappingURL=posthook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"posthook.d.ts","sourceRoot":"","sources":["../../src/schedulers/posthook.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAwB,MAAM,aAAa,CAAC;AAEpF,MAAM,WAAW,wBAAwB;IACvC,wBAAwB;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,qDAAqD;IACrD,UAAU,EAAE,MAAM,CAAC;IACnB;iFAC6E;IAC7E,QAAQ,EAAE,MAAM,CAAC;IACjB,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,iBAAkB,YAAW,SAAS;IACjD,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,QAAQ,CAAS;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;gBAEhB,OAAO,EAAE,wBAAwB;IAS7C,yEAAyE;IACzE,QAAQ,CAAC,WAAW,MAAM;IAEpB,QAAQ,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAUtD,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IACtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAE3B,cAAc,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACxC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,GAC/D;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,CAAC,CAAA;KAAE;CAI/B"}
@@ -0,0 +1,49 @@
1
+ import Posthook from "@posthook/node";
2
+ export class PosthookScheduler {
3
+ client;
4
+ basePath;
5
+ signingKey;
6
+ constructor(options) {
7
+ this.client = new Posthook(options.apiKey, {
8
+ signingKey: options.signingKey,
9
+ ...(options.baseURL ? { baseURL: options.baseURL } : {}),
10
+ });
11
+ this.basePath = options.basePath.replace(/\/+$/, ""); // strip trailing slash
12
+ this.signingKey = options.signingKey;
13
+ }
14
+ /** Maximum total attempts Posthook supports (1 initial + 15 retries). */
15
+ maxAttempts = 16;
16
+ async schedule(req) {
17
+ const hook = await this.client.hooks.schedule({
18
+ path: `${this.basePath}/${encodeURIComponent(req.handler)}`,
19
+ postAt: req.at.toISOString(),
20
+ data: { jobId: req.id, ...(req.key ? { key: req.key } : {}) },
21
+ ...(req.retry && req.retry.attempts > 1 ? { retryOverride: toPosthookRetry(req.retry) } : {}),
22
+ });
23
+ return hook.id;
24
+ }
25
+ async cancel(schedulerRef) {
26
+ await this.client.hooks.delete(schedulerRef);
27
+ }
28
+ async start() { }
29
+ async stop() { }
30
+ verifyDelivery(body, headers) {
31
+ const delivery = this.client.signatures.parseDelivery(body, headers);
32
+ return { hookId: delivery.hookId, data: delivery.data };
33
+ }
34
+ }
35
+ function toPosthookRetry(retry) {
36
+ const strategy = retry.backoff === "exponential" ? "exponential" : "fixed";
37
+ const delaySecs = Math.min(Math.max(5, Math.ceil(retry.initialDelayMs / 1000)), 60);
38
+ const minRetries = Math.min(retry.attempts - 1, 15);
39
+ return {
40
+ minRetries,
41
+ delaySecs,
42
+ strategy,
43
+ jitter: retry.jitter,
44
+ ...(strategy === "exponential" ? {
45
+ maxDelaySecs: Math.max(60, Math.min(Math.ceil(retry.maxDelayMs / 1000), 3600)),
46
+ } : {}),
47
+ };
48
+ }
49
+ //# sourceMappingURL=posthook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"posthook.js","sourceRoot":"","sources":["../../src/schedulers/posthook.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { Job, Store } from "../types.js";
2
+ export declare class MemoryStore implements Store {
3
+ private jobs;
4
+ private keyIndex;
5
+ private evictionTimer;
6
+ constructor();
7
+ createJob(job: Omit<Job, "createdAt">): Promise<Job>;
8
+ getJob(id: string): Promise<Job | null>;
9
+ getActiveJobByKey(handler: string, key: string): Promise<Job | null>;
10
+ cancelJob(id: string): Promise<boolean>;
11
+ updateScheduledFor(id: string, scheduledFor: Date): Promise<void>;
12
+ deleteJob(id: string): Promise<void>;
13
+ updatePatternEvent(key: string, handler: string, kind: "debounce" | "throttle", now: Date, waitMs: number, maxWaitMs: number | null): Promise<Job | null>;
14
+ markRunning(id: string, version: number): Promise<boolean>;
15
+ markCompleted(id: string, version: number): Promise<boolean>;
16
+ markFailed(id: string, version: number, error: Error): Promise<boolean>;
17
+ retryJob(id: string, version: number, nextAttempt: number, scheduledFor: Date, lastError: string): Promise<boolean>;
18
+ rescheduleDueAt(id: string, version: number): Promise<Job | null>;
19
+ requeueForNextWindow(id: string): Promise<Job | null>;
20
+ replaceJob(id: string, scheduledFor: Date, maxAttempts: number): Promise<Job | null>;
21
+ updateSchedulerRef(id: string, version: number, ref: string): Promise<boolean>;
22
+ reclaimStalled(id: string, leaseMs: number): Promise<Job | null>;
23
+ reclaimStalledJobs(handlerTimeouts: Map<string, number>): Promise<Job[]>;
24
+ getDueJobs(limit: number): Promise<Job[]>;
25
+ close(): Promise<void>;
26
+ private evictTerminal;
27
+ }
28
+ //# sourceMappingURL=memory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/stores/memory.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAU9C,qBAAa,WAAY,YAAW,KAAK;IACvC,OAAO,CAAC,IAAI,CAA0B;IACtC,OAAO,CAAC,QAAQ,CAA6B;IAC7C,OAAO,CAAC,aAAa,CAA+C;;IAM9D,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC;IAgBpD,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IAKvC,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IAYpE,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IASvC,kBAAkB,CAAC,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAKjE,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMpC,kBAAkB,CACtB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,UAAU,GAAG,UAAU,EAC7B,GAAG,EAAE,IAAI,EACT,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAAG,IAAI,GACvB,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IA2ChB,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAS1D,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAS5D,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC;IAUvE,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAanH,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IAUjE,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IAerD,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IAYpF,kBAAkB,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAO9E,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IAwBhE,kBAAkB,CAAC,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAgCxE,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAczC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAS5B,OAAO,CAAC,aAAa;CAYtB"}
@@ -0,0 +1,282 @@
1
+ import { ACTIVE_STATUSES, DEFAULT_TIMEOUT_MS, STALLED_GRACE_MS } from "../types.js";
2
+ const EVICTION_INTERVAL = 60_000;
3
+ const EVICTION_AGE = 5 * 60_000;
4
+ function indexKey(handler, key) {
5
+ return `${handler}\0${key}`;
6
+ }
7
+ export class MemoryStore {
8
+ jobs = new Map();
9
+ keyIndex = new Map(); // indexKey(handler, key) → jobId
10
+ evictionTimer = null;
11
+ constructor() {
12
+ this.evictionTimer = setInterval(() => this.evictTerminal(), EVICTION_INTERVAL);
13
+ }
14
+ async createJob(job) {
15
+ const ik = indexKey(job.handler, job.key);
16
+ const existingId = this.keyIndex.get(ik);
17
+ if (existingId) {
18
+ const existing = this.jobs.get(existingId);
19
+ if (existing && ACTIVE_STATUSES.has(existing.status)) {
20
+ throw new Error(`Job with active key "${job.key}" already exists (concurrent insert)`);
21
+ }
22
+ }
23
+ const full = { ...job, createdAt: new Date() };
24
+ this.jobs.set(full.id, full);
25
+ this.keyIndex.set(ik, full.id);
26
+ return full;
27
+ }
28
+ async getJob(id) {
29
+ const job = this.jobs.get(id);
30
+ return job ? { ...job } : null;
31
+ }
32
+ async getActiveJobByKey(handler, key) {
33
+ const ik = indexKey(handler, key);
34
+ const id = this.keyIndex.get(ik);
35
+ if (!id)
36
+ return null;
37
+ const job = this.jobs.get(id);
38
+ if (!job || !ACTIVE_STATUSES.has(job.status)) {
39
+ this.keyIndex.delete(ik);
40
+ return null;
41
+ }
42
+ return { ...job };
43
+ }
44
+ async cancelJob(id) {
45
+ const job = this.jobs.get(id);
46
+ if (!job || job.status !== "pending")
47
+ return false;
48
+ job.status = "cancelled";
49
+ job.completedAt = new Date();
50
+ this.keyIndex.delete(indexKey(job.handler, job.key));
51
+ return true;
52
+ }
53
+ async updateScheduledFor(id, scheduledFor) {
54
+ const job = this.jobs.get(id);
55
+ if (job)
56
+ job.scheduledFor = scheduledFor;
57
+ }
58
+ async deleteJob(id) {
59
+ const job = this.jobs.get(id);
60
+ if (job)
61
+ this.keyIndex.delete(job.key);
62
+ this.jobs.delete(id);
63
+ }
64
+ async updatePatternEvent(key, handler, kind, now, waitMs, maxWaitMs) {
65
+ const id = this.keyIndex.get(indexKey(handler, key));
66
+ if (!id)
67
+ return null;
68
+ const job = this.jobs.get(id);
69
+ if (!job || !ACTIVE_STATUSES.has(job.status))
70
+ return null;
71
+ // Validate frozen config
72
+ if (job.kind !== kind) {
73
+ throw new Error(`Cannot use ${kind} for key "${key}": an active ${job.kind} job exists for this key.`);
74
+ }
75
+ if (job.handler !== handler) {
76
+ throw new Error(`Config mismatch for key "${key}": active job uses handler "${job.handler}" but "${handler}" was requested.`);
77
+ }
78
+ if (job.waitMs !== waitMs) {
79
+ throw new Error(`Config mismatch for key "${key}": active job uses wait=${job.waitMs}ms but ${waitMs}ms was requested.`);
80
+ }
81
+ if (job.maxWaitMs !== maxWaitMs) {
82
+ throw new Error(`Config mismatch for key "${key}": active job uses maxWait=${job.maxWaitMs}ms but ${maxWaitMs}ms was requested.`);
83
+ }
84
+ job.version += 1;
85
+ job.lastAt = now;
86
+ if (job.status === "running") {
87
+ // Only reset firstAt on the FIRST event after execution started.
88
+ // Subsequent events during the same execution just update lastAt.
89
+ // This keeps throttle windows anchored and debounce maxWait stable.
90
+ if (!job.startedAt || job.firstAt.getTime() <= job.startedAt.getTime()) {
91
+ job.firstAt = now;
92
+ }
93
+ }
94
+ return { ...job };
95
+ }
96
+ async markRunning(id, version) {
97
+ const job = this.jobs.get(id);
98
+ if (!job || job.status !== "pending" || job.version !== version)
99
+ return false;
100
+ job.status = "running";
101
+ job.claimedVersion = version;
102
+ job.startedAt = new Date();
103
+ return true;
104
+ }
105
+ async markCompleted(id, version) {
106
+ const job = this.jobs.get(id);
107
+ if (!job || job.status !== "running" || job.version !== version)
108
+ return false;
109
+ job.status = "completed";
110
+ job.completedAt = new Date();
111
+ this.keyIndex.delete(indexKey(job.handler, job.key));
112
+ return true;
113
+ }
114
+ async markFailed(id, version, error) {
115
+ const job = this.jobs.get(id);
116
+ if (!job || job.status !== "running" || job.version !== version)
117
+ return false;
118
+ job.status = "failed";
119
+ job.lastError = error.message;
120
+ job.completedAt = new Date();
121
+ this.keyIndex.delete(indexKey(job.handler, job.key));
122
+ return true;
123
+ }
124
+ async retryJob(id, version, nextAttempt, scheduledFor, lastError) {
125
+ const job = this.jobs.get(id);
126
+ if (!job || job.status !== "running" || job.version !== version)
127
+ return false;
128
+ job.status = "pending";
129
+ job.attempt = nextAttempt;
130
+ job.scheduledFor = scheduledFor;
131
+ job.startedAt = null;
132
+ job.completedAt = null;
133
+ job.claimedVersion = null;
134
+ job.lastError = lastError;
135
+ return true;
136
+ }
137
+ async rescheduleDueAt(id, version) {
138
+ const job = this.jobs.get(id);
139
+ if (!job || job.status !== "pending" || job.version !== version)
140
+ return null;
141
+ if (!job.lastAt || !job.waitMs)
142
+ return null;
143
+ job.scheduledFor = computePatternDueAt(job);
144
+ job.version += 1;
145
+ return { ...job };
146
+ }
147
+ async requeueForNextWindow(id) {
148
+ const job = this.jobs.get(id);
149
+ if (!job || job.status !== "running")
150
+ return null;
151
+ if (!job.lastAt || !job.waitMs)
152
+ return null;
153
+ job.status = "pending";
154
+ job.scheduledFor = computePatternDueAt(job);
155
+ job.startedAt = null;
156
+ job.completedAt = null;
157
+ job.claimedVersion = null;
158
+ job.attempt = 0;
159
+ job.version += 1;
160
+ return { ...job };
161
+ }
162
+ async replaceJob(id, scheduledFor, maxAttempts) {
163
+ const job = this.jobs.get(id);
164
+ if (!job || job.status !== "pending")
165
+ return null;
166
+ job.version += 1;
167
+ job.scheduledFor = scheduledFor;
168
+ job.attempt = 0;
169
+ job.maxAttempts = maxAttempts;
170
+ job.schedulerRef = null;
171
+ job.lastError = null;
172
+ return { ...job };
173
+ }
174
+ async updateSchedulerRef(id, version, ref) {
175
+ const job = this.jobs.get(id);
176
+ if (!job || job.version !== version)
177
+ return false;
178
+ job.schedulerRef = ref;
179
+ return true;
180
+ }
181
+ async reclaimStalled(id, leaseMs) {
182
+ const job = this.jobs.get(id);
183
+ if (!job || job.status !== "running" || !job.startedAt)
184
+ return null;
185
+ if (Date.now() - job.startedAt.getTime() <= leaseMs)
186
+ return null;
187
+ if (job.kind !== "once" && job.claimedVersion != null && job.version > job.claimedVersion) {
188
+ // Pattern with version advance: requeue fresh window
189
+ job.status = "pending";
190
+ job.scheduledFor = computePatternDueAt(job);
191
+ job.startedAt = null;
192
+ job.completedAt = null;
193
+ job.claimedVersion = null;
194
+ job.attempt = 0;
195
+ job.version += 1;
196
+ }
197
+ else {
198
+ // Reclaim: increment attempt, set pending. Caller decides if exhausted.
199
+ job.status = "pending";
200
+ job.attempt += 1;
201
+ job.startedAt = null;
202
+ job.claimedVersion = null;
203
+ }
204
+ return { ...job };
205
+ }
206
+ async reclaimStalledJobs(handlerTimeouts) {
207
+ const reclaimed = [];
208
+ const now = Date.now();
209
+ for (const job of this.jobs.values()) {
210
+ if (job.status !== "running" || !job.startedAt)
211
+ continue;
212
+ const timeout = handlerTimeouts.get(job.handler) ?? DEFAULT_TIMEOUT_MS;
213
+ if (now - job.startedAt.getTime() > timeout + STALLED_GRACE_MS) {
214
+ if (job.kind !== "once" && job.claimedVersion != null && job.version > job.claimedVersion) {
215
+ // Pattern with version advance: requeue fresh window
216
+ job.status = "pending";
217
+ job.scheduledFor = computePatternDueAt(job);
218
+ job.startedAt = null;
219
+ job.completedAt = null;
220
+ job.claimedVersion = null;
221
+ job.attempt = 0;
222
+ job.version += 1;
223
+ reclaimed.push({ ...job });
224
+ }
225
+ else {
226
+ // Reclaim: increment attempt, set pending. Caller handles exhaustion + onFailure.
227
+ job.status = "pending";
228
+ job.attempt += 1;
229
+ job.startedAt = null;
230
+ job.claimedVersion = null;
231
+ reclaimed.push({ ...job });
232
+ }
233
+ }
234
+ }
235
+ return reclaimed;
236
+ }
237
+ async getDueJobs(limit) {
238
+ const now = new Date();
239
+ const due = [];
240
+ for (const job of this.jobs.values()) {
241
+ if (job.status === "pending" && job.scheduledFor <= now) {
242
+ due.push(job);
243
+ }
244
+ }
245
+ due.sort((a, b) => a.scheduledFor.getTime() - b.scheduledFor.getTime());
246
+ return due.slice(0, limit);
247
+ }
248
+ async close() {
249
+ if (this.evictionTimer) {
250
+ clearInterval(this.evictionTimer);
251
+ this.evictionTimer = null;
252
+ }
253
+ this.jobs.clear();
254
+ this.keyIndex.clear();
255
+ }
256
+ evictTerminal() {
257
+ const cutoff = Date.now() - EVICTION_AGE;
258
+ for (const [id, job] of this.jobs) {
259
+ if (!ACTIVE_STATUSES.has(job.status) &&
260
+ job.completedAt &&
261
+ job.completedAt.getTime() < cutoff) {
262
+ this.jobs.delete(id);
263
+ }
264
+ }
265
+ }
266
+ }
267
+ function computePatternDueAt(job) {
268
+ if (job.kind === "throttle") {
269
+ // Throttle: fixed window from first event of the burst
270
+ return new Date(job.firstAt.getTime() + job.waitMs);
271
+ }
272
+ // Debounce: sliding window from last event, capped by maxWait
273
+ let nextAt = new Date(job.lastAt.getTime() + job.waitMs);
274
+ if (job.maxWaitMs != null && job.firstAt) {
275
+ const deadline = new Date(job.firstAt.getTime() + job.maxWaitMs);
276
+ if (nextAt.getTime() > deadline.getTime()) {
277
+ nextAt = deadline;
278
+ }
279
+ }
280
+ return nextAt;
281
+ }
282
+ //# sourceMappingURL=memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/stores/memory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export declare const SCHEMA = "delaykit";
2
+ export declare const MIGRATIONS: {
3
+ version: number;
4
+ sql: string;
5
+ }[];
6
+ //# sourceMappingURL=postgres-migrations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres-migrations.d.ts","sourceRoot":"","sources":["../../src/stores/postgres-migrations.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,MAAM,aAAa,CAAC;AAEjC,eAAO,MAAM,UAAU;;;GA8DtB,CAAC"}
@@ -0,0 +1,65 @@
1
+ export const SCHEMA = "delaykit";
2
+ export const MIGRATIONS = [
3
+ {
4
+ version: 1,
5
+ sql: `
6
+ CREATE SCHEMA IF NOT EXISTS delaykit;
7
+
8
+ CREATE TABLE IF NOT EXISTS delaykit.jobs (
9
+ id UUID PRIMARY KEY,
10
+ kind TEXT NOT NULL DEFAULT 'once',
11
+ handler TEXT NOT NULL,
12
+ key TEXT NOT NULL,
13
+ version INT NOT NULL DEFAULT 1,
14
+ claimed_version INT,
15
+ status TEXT NOT NULL DEFAULT 'pending',
16
+ scheduled_for TIMESTAMPTZ NOT NULL,
17
+ started_at TIMESTAMPTZ,
18
+ completed_at TIMESTAMPTZ,
19
+ attempt INT NOT NULL DEFAULT 0,
20
+ max_attempts INT NOT NULL DEFAULT 1,
21
+ scheduler_ref TEXT,
22
+ last_error TEXT,
23
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
24
+ first_at TIMESTAMPTZ,
25
+ last_at TIMESTAMPTZ,
26
+ wait_ms INT,
27
+ max_wait_ms INT
28
+ );
29
+
30
+ CREATE INDEX IF NOT EXISTS idx_jobs_status_scheduled
31
+ ON delaykit.jobs (scheduled_for)
32
+ WHERE status = 'pending';
33
+
34
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_jobs_key_active
35
+ ON delaykit.jobs (handler, key)
36
+ WHERE status IN ('pending', 'running');
37
+
38
+ CREATE INDEX IF NOT EXISTS idx_jobs_status_running
39
+ ON delaykit.jobs (started_at)
40
+ WHERE status = 'running';
41
+
42
+ CREATE TABLE IF NOT EXISTS delaykit.migrations (
43
+ version INT PRIMARY KEY,
44
+ applied_at TIMESTAMPTZ NOT NULL DEFAULT now()
45
+ );
46
+
47
+ INSERT INTO delaykit.migrations (version) VALUES (1) ON CONFLICT DO NOTHING;
48
+ `,
49
+ },
50
+ {
51
+ version: 2,
52
+ sql: `
53
+ -- Scope active-job uniqueness to (handler, key) instead of just (key).
54
+ -- This allows different handlers to use the same key concurrently.
55
+ DROP INDEX IF EXISTS delaykit.idx_jobs_key_active;
56
+
57
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_jobs_key_active
58
+ ON delaykit.jobs (handler, key)
59
+ WHERE status IN ('pending', 'running');
60
+
61
+ INSERT INTO delaykit.migrations (version) VALUES (2) ON CONFLICT DO NOTHING;
62
+ `,
63
+ },
64
+ ];
65
+ //# sourceMappingURL=postgres-migrations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres-migrations.js","sourceRoot":"","sources":["../../src/stores/postgres-migrations.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,MAAM,GAAG,UAAU,CAAC;AAEjC,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB;QACE,OAAO,EAAE,CAAC;QACV,GAAG,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA2CJ;KACF;IACD;QACE,OAAO,EAAE,CAAC;QACV,GAAG,EAAE;;;;;;;;;;KAUJ;KACF;CACF,CAAC"}
@@ -0,0 +1,32 @@
1
+ import postgres from "postgres";
2
+ import type { Job, Store } from "../types.js";
3
+ export interface PostgresStoreOptions {
4
+ runMigrations?: boolean;
5
+ }
6
+ export declare class PostgresStore implements Store {
7
+ private sql;
8
+ private constructor();
9
+ static connect(connectionStringOrClient?: string | postgres.Sql, options?: PostgresStoreOptions): Promise<PostgresStore>;
10
+ private migrate;
11
+ createJob(job: Omit<Job, "createdAt">): Promise<Job>;
12
+ getJob(id: string): Promise<Job | null>;
13
+ getActiveJobByKey(handler: string, key: string): Promise<Job | null>;
14
+ cancelJob(id: string): Promise<boolean>;
15
+ updateScheduledFor(id: string, scheduledFor: Date): Promise<void>;
16
+ deleteJob(id: string): Promise<void>;
17
+ updatePatternEvent(key: string, handler: string, kind: "debounce" | "throttle", now: Date, waitMs: number, maxWaitMs: number | null): Promise<Job | null>;
18
+ markRunning(id: string, version: number): Promise<boolean>;
19
+ markCompleted(id: string, version: number): Promise<boolean>;
20
+ markFailed(id: string, version: number, error: Error): Promise<boolean>;
21
+ retryJob(id: string, version: number, nextAttempt: number, scheduledFor: Date, lastError: string): Promise<boolean>;
22
+ rescheduleDueAt(id: string, version: number): Promise<Job | null>;
23
+ requeueForNextWindow(id: string): Promise<Job | null>;
24
+ replaceJob(id: string, scheduledFor: Date, maxAttempts: number): Promise<Job | null>;
25
+ updateSchedulerRef(id: string, version: number, ref: string): Promise<boolean>;
26
+ reclaimStalled(id: string, leaseMs: number): Promise<Job | null>;
27
+ reclaimStalledJobs(handlerTimeouts: Map<string, number>): Promise<Job[]>;
28
+ getDueJobs(limit: number): Promise<Job[]>;
29
+ close(): Promise<void>;
30
+ private rowToJob;
31
+ }
32
+ //# sourceMappingURL=postgres.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../../src/stores/postgres.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,UAAU,CAAC;AAEhC,OAAO,KAAK,EAAE,GAAG,EAAa,KAAK,EAAE,MAAM,aAAa,CAAC;AAQzD,MAAM,WAAW,oBAAoB;IACnC,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,qBAAa,aAAc,YAAW,KAAK;IACzC,OAAO,CAAC,GAAG,CAAe;IAE1B,OAAO;WAIM,OAAO,CAClB,wBAAwB,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC,GAAG,EAChD,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,aAAa,CAAC;YAsBX,OAAO;IAqBf,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC;IA2BpD,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IAavC,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IASpE,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IASvC,kBAAkB,CAAC,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAQjE,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpC,kBAAkB,CACtB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,UAAU,GAAG,UAAU,EAC7B,GAAG,EAAE,IAAI,EACT,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAAG,IAAI,GACvB,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IAqChB,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAU1D,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAU5D,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC;IAUvE,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAYnH,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IAqBjE,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IAyBrD,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IAYpF,kBAAkB,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAS9E,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IAyChE,kBAAkB,CAAC,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAwDxE,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAUzC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B,OAAO,CAAC,QAAQ;CAuBjB"}