@zintrust/queue-cloudflare 2.4.1

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 (36) hide show
  1. package/README.md +158 -0
  2. package/dist/CloudflareJobStore.d.ts +50 -0
  3. package/dist/CloudflareJobStore.js +435 -0
  4. package/dist/CloudflareQueueConsumer.d.ts +39 -0
  5. package/dist/CloudflareQueueConsumer.js +184 -0
  6. package/dist/CloudflareQueueCoordinator.d.ts +21 -0
  7. package/dist/CloudflareQueueCoordinator.js +57 -0
  8. package/dist/CloudflareQueueMigrator.d.ts +14 -0
  9. package/dist/CloudflareQueueMigrator.js +22 -0
  10. package/dist/CloudflareQueueScheduler.d.ts +43 -0
  11. package/dist/CloudflareQueueScheduler.js +99 -0
  12. package/dist/cli/MigrateCloudflareQueueCommand.d.ts +10 -0
  13. package/dist/cli/MigrateCloudflareQueueCommand.js +51 -0
  14. package/dist/cli-register.d.ts +9 -0
  15. package/dist/cli-register.js +21 -0
  16. package/dist/index.d.ts +50 -0
  17. package/dist/index.js +499 -0
  18. package/dist/migrationSql.d.ts +2 -0
  19. package/dist/migrationSql.js +104 -0
  20. package/dist/migrations/20260608000001_create_cloudflare_queue_jobs_table.d.ts +6 -0
  21. package/dist/migrations/20260608000001_create_cloudflare_queue_jobs_table.js +37 -0
  22. package/dist/migrations/20260608000002_create_cloudflare_queue_job_events_table.d.ts +6 -0
  23. package/dist/migrations/20260608000002_create_cloudflare_queue_job_events_table.js +21 -0
  24. package/dist/migrations/20260608000003_create_cloudflare_queue_job_logs_table.d.ts +6 -0
  25. package/dist/migrations/20260608000003_create_cloudflare_queue_job_logs_table.js +22 -0
  26. package/dist/migrations/20260608000004_create_cloudflare_queue_repeatables_table.d.ts +6 -0
  27. package/dist/migrations/20260608000004_create_cloudflare_queue_repeatables_table.js +28 -0
  28. package/dist/migrations/20260608000005_create_cloudflare_queue_flow_dependencies_table.d.ts +6 -0
  29. package/dist/migrations/20260608000005_create_cloudflare_queue_flow_dependencies_table.js +22 -0
  30. package/dist/migrations/index.d.ts +2 -0
  31. package/dist/migrations/index.js +12 -0
  32. package/dist/register.d.ts +5 -0
  33. package/dist/register.js +20 -0
  34. package/dist/types.d.ts +240 -0
  35. package/dist/types.js +1 -0
  36. package/package.json +52 -0
@@ -0,0 +1,184 @@
1
+ const isEnvelope = (value) => {
2
+ return (value !== null &&
3
+ typeof value === 'object' &&
4
+ value.protocol === 'zintrust.cf.queue.v1' &&
5
+ typeof value.jobId === 'string');
6
+ };
7
+ const resolveCoordinator = (config, queueName) => {
8
+ const direct = config?.coordinator;
9
+ if (direct?.getByName !== undefined)
10
+ return direct.getByName(queueName ?? 'default');
11
+ if (direct?.idFromName !== undefined && direct.get !== undefined) {
12
+ return direct.get(direct.idFromName(queueName ?? 'default'));
13
+ }
14
+ const env = globalThis.env;
15
+ const bindingName = config?.coordinatorBindingName ?? 'QUEUE_COORDINATOR';
16
+ const binding = env?.[bindingName];
17
+ if (binding?.getByName !== undefined)
18
+ return binding.getByName(queueName ?? 'default');
19
+ if (binding?.idFromName !== undefined && binding.get !== undefined) {
20
+ return binding.get(binding.idFromName(queueName ?? 'default'));
21
+ }
22
+ return null;
23
+ };
24
+ const resolveWorkerId = (config) => {
25
+ return config?.workerId ?? 'queue-cloudflare-worker';
26
+ };
27
+ const resolveRetryDelay = (job, attempts, baseDelaySeconds) => {
28
+ const backoff = job.opts.backoff;
29
+ const baseMs = backoff?.delay ?? baseDelaySeconds * 1000;
30
+ const delayMs = backoff?.type === 'fixed' ? baseMs : baseMs * 2 ** Math.max(0, attempts);
31
+ return Math.min(Math.max(0, Math.ceil(delayMs / 1000)), 43200);
32
+ };
33
+ const toEnvelope = (job) => ({
34
+ protocol: 'zintrust.cf.queue.v1',
35
+ jobId: job.id,
36
+ queueName: job.queueName,
37
+ name: job.name,
38
+ attempt: job.attemptsMade,
39
+ availableAt: job.availableAt,
40
+ });
41
+ const serializeError = (error) => {
42
+ if (error instanceof Error)
43
+ return { name: error.name, message: error.message, stack: error.stack };
44
+ return error;
45
+ };
46
+ const createConsumer = (config) => {
47
+ return {
48
+ async processMessage(message, batchQueueName) {
49
+ const envelope = isEnvelope(message.body)
50
+ ? message.body
51
+ : {
52
+ protocol: 'zintrust.cf.queue.v1',
53
+ jobId: message.id,
54
+ queueName: config.queueName ?? batchQueueName ?? 'default',
55
+ name: 'default',
56
+ attempt: message.attempts,
57
+ availableAt: new Date().toISOString(),
58
+ };
59
+ const queueName = config.queueName ?? envelope.queueName;
60
+ const coordinator = resolveCoordinator(config.state, queueName);
61
+ if ((await coordinator?.isPaused?.()) === true) {
62
+ message.retry({ delaySeconds: config.retryDelaySeconds ?? 30 });
63
+ return;
64
+ }
65
+ const job = await config.store.getJob(queueName, envelope.jobId);
66
+ if (job === null || job.state === 'canceled') {
67
+ message.ack();
68
+ return;
69
+ }
70
+ const lease = await coordinator?.acquireLease?.({
71
+ queueName,
72
+ jobId: job.id,
73
+ workerId: resolveWorkerId(config.state),
74
+ ttlMs: config.state?.heartbeatTtlMs ?? 60_000,
75
+ });
76
+ if (lease !== undefined && !lease.acquired) {
77
+ message.retry({ delaySeconds: config.retryDelaySeconds ?? 30 });
78
+ return;
79
+ }
80
+ await config.store.updateState({
81
+ queueName,
82
+ jobId: job.id,
83
+ state: 'active',
84
+ incrementAttempts: true,
85
+ });
86
+ try {
87
+ const result = await config.processor(job.data, {
88
+ job,
89
+ attempt: message.attempts,
90
+ updateProgress: async (progress) => {
91
+ await config.store.updateProgress(queueName, job.id, progress);
92
+ },
93
+ log: async (logMessage, data) => {
94
+ await config.store.recordLog(queueName, job.id, 'info', logMessage, data);
95
+ },
96
+ heartbeat: async () => {
97
+ await coordinator?.heartbeat?.({
98
+ queueName,
99
+ jobId: job.id,
100
+ workerId: resolveWorkerId(config.state),
101
+ ttlMs: config.state?.heartbeatTtlMs ?? 60_000,
102
+ });
103
+ await config.store.updateState({
104
+ queueName,
105
+ jobId: job.id,
106
+ state: 'active',
107
+ });
108
+ },
109
+ });
110
+ await config.store.updateState({
111
+ queueName,
112
+ jobId: job.id,
113
+ state: 'completed',
114
+ result,
115
+ });
116
+ const releasedParents = await config.store.markFlowChildCompleted(queueName, job.id);
117
+ for (const parent of releasedParents) {
118
+ await config.queue?.enqueue(parent.queueName, toEnvelope(parent));
119
+ await config.store.markDispatched(parent.queueName, parent.id);
120
+ }
121
+ await config.store.applyRetention(queueName, job.id, 'completed');
122
+ await coordinator?.releaseLease?.({
123
+ queueName,
124
+ jobId: job.id,
125
+ workerId: resolveWorkerId(config.state),
126
+ ttlMs: config.state?.heartbeatTtlMs ?? 60_000,
127
+ });
128
+ message.ack();
129
+ }
130
+ catch (error) {
131
+ const exhausted = job.attemptsMade + 1 >= job.maxAttempts;
132
+ await config.store.updateState({
133
+ queueName,
134
+ jobId: job.id,
135
+ state: exhausted ? 'failed' : 'retrying',
136
+ error: serializeError(error),
137
+ });
138
+ if (exhausted) {
139
+ await config.store.applyRetention(queueName, job.id, 'failed');
140
+ await coordinator?.releaseLease?.({
141
+ queueName,
142
+ jobId: job.id,
143
+ workerId: resolveWorkerId(config.state),
144
+ ttlMs: config.state?.heartbeatTtlMs ?? 60_000,
145
+ });
146
+ message.ack();
147
+ return;
148
+ }
149
+ message.retry({
150
+ delaySeconds: resolveRetryDelay(job, message.attempts, config.retryDelaySeconds ?? 30),
151
+ });
152
+ }
153
+ },
154
+ async processBatch(batch) {
155
+ for (const message of batch.messages) {
156
+ await this.processMessage(message, batch.queue);
157
+ }
158
+ },
159
+ };
160
+ };
161
+ export const CloudflareQueueConsumer = Object.freeze({
162
+ create: createConsumer,
163
+ createDeadLetter(input) {
164
+ return {
165
+ async processMessage(message, batchQueueName) {
166
+ const envelope = isEnvelope(message.body) ? message.body : null;
167
+ const queueName = input.queueName ?? envelope?.queueName ?? batchQueueName ?? 'default';
168
+ const jobId = envelope?.jobId ?? message.id;
169
+ await input.store.updateState({
170
+ queueName,
171
+ jobId,
172
+ state: 'dead_lettered',
173
+ error: { messageId: message.id, body: message.body, attempts: message.attempts },
174
+ });
175
+ message.ack();
176
+ },
177
+ async processBatch(batch) {
178
+ for (const message of batch.messages) {
179
+ await this.processMessage(message, batch.queue);
180
+ }
181
+ },
182
+ };
183
+ },
184
+ });
@@ -0,0 +1,21 @@
1
+ import type { LeaseInput, LeaseResult, RateLimitInput, RateLimitResult } from './types.js';
2
+ type DurableObjectStorageLike = {
3
+ get: <T = unknown>(key: string) => Promise<T | undefined>;
4
+ put: (key: string, value: unknown) => Promise<void>;
5
+ delete: (key: string) => Promise<void>;
6
+ };
7
+ type DurableObjectStateLike = {
8
+ storage: DurableObjectStorageLike;
9
+ };
10
+ export declare class CloudflareQueueCoordinator {
11
+ readonly state: DurableObjectStateLike;
12
+ constructor(state: DurableObjectStateLike);
13
+ acquireLease(input: LeaseInput): Promise<LeaseResult>;
14
+ heartbeat(input: LeaseInput): Promise<LeaseResult>;
15
+ releaseLease(input: LeaseInput): Promise<void>;
16
+ pause(queueName?: string): Promise<void>;
17
+ resume(queueName?: string): Promise<void>;
18
+ isPaused(queueName?: string): Promise<boolean>;
19
+ rateLimit(input: RateLimitInput): Promise<RateLimitResult>;
20
+ }
21
+ export {};
@@ -0,0 +1,57 @@
1
+ const leaseKey = (queueName, jobId) => `lease:${queueName}:${jobId}`;
2
+ const pausedKey = (queueName) => `paused:${queueName}`;
3
+ const rateLimitKey = (key) => `rate:${key}`;
4
+ export class CloudflareQueueCoordinator {
5
+ state;
6
+ constructor(state) {
7
+ this.state = state;
8
+ }
9
+ async acquireLease(input) {
10
+ const key = leaseKey(input.queueName, input.jobId);
11
+ const existing = await this.state.storage.get(key);
12
+ const now = Date.now();
13
+ if (existing !== undefined && existing.expiresAt > now && existing.owner !== input.workerId) {
14
+ return { acquired: false, owner: existing.owner, expiresAt: existing.expiresAt };
15
+ }
16
+ const expiresAt = now + Math.max(1000, input.ttlMs);
17
+ await this.state.storage.put(key, { owner: input.workerId, expiresAt });
18
+ return { acquired: true, owner: input.workerId, expiresAt };
19
+ }
20
+ async heartbeat(input) {
21
+ return await this.acquireLease(input);
22
+ }
23
+ async releaseLease(input) {
24
+ const key = leaseKey(input.queueName, input.jobId);
25
+ const existing = await this.state.storage.get(key);
26
+ if (existing === undefined || existing.owner === input.workerId) {
27
+ await this.state.storage.delete(key);
28
+ }
29
+ }
30
+ async pause(queueName = 'default') {
31
+ await this.state.storage.put(pausedKey(queueName), true);
32
+ }
33
+ async resume(queueName = 'default') {
34
+ await this.state.storage.delete(pausedKey(queueName));
35
+ }
36
+ async isPaused(queueName = 'default') {
37
+ return (await this.state.storage.get(pausedKey(queueName))) === true;
38
+ }
39
+ async rateLimit(input) {
40
+ const now = Date.now();
41
+ const max = Math.max(1, Math.floor(input.max));
42
+ const durationMs = Math.max(1000, Math.floor(input.durationMs));
43
+ const key = rateLimitKey(input.key);
44
+ const existing = await this.state.storage.get(key);
45
+ if (existing === undefined || existing.resetAt <= now) {
46
+ const record = { remaining: max - 1, resetAt: now + durationMs };
47
+ await this.state.storage.put(key, record);
48
+ return { allowed: true, ...record };
49
+ }
50
+ if (existing.remaining <= 0) {
51
+ return { allowed: false, remaining: 0, resetAt: existing.resetAt };
52
+ }
53
+ const record = { remaining: existing.remaining - 1, resetAt: existing.resetAt };
54
+ await this.state.storage.put(key, record);
55
+ return { allowed: true, ...record };
56
+ }
57
+ }
@@ -0,0 +1,14 @@
1
+ import type { D1DatabaseLike, ZinTrustDatabaseLike } from './types.js';
2
+ export type CloudflareQueueMigrationTarget = {
3
+ d1: D1DatabaseLike;
4
+ db?: never;
5
+ } | {
6
+ db: ZinTrustDatabaseLike;
7
+ d1?: never;
8
+ };
9
+ export declare const CloudflareQueueMigrator: Readonly<{
10
+ statements: readonly string[];
11
+ rollbackStatements: readonly string[];
12
+ up(target: CloudflareQueueMigrationTarget): Promise<void>;
13
+ down(target: CloudflareQueueMigrationTarget): Promise<void>;
14
+ }>;
@@ -0,0 +1,22 @@
1
+ import { cloudflareQueueMigrationStatements, cloudflareQueueRollbackStatements, } from './migrationSql.js';
2
+ const runStatement = async (target, statement) => {
3
+ if ('d1' in target && target.d1 !== undefined) {
4
+ await target.d1.prepare(statement).run();
5
+ return;
6
+ }
7
+ await target.db.execute(statement);
8
+ };
9
+ export const CloudflareQueueMigrator = Object.freeze({
10
+ statements: cloudflareQueueMigrationStatements,
11
+ rollbackStatements: cloudflareQueueRollbackStatements,
12
+ async up(target) {
13
+ for (const statement of cloudflareQueueMigrationStatements) {
14
+ await runStatement(target, statement);
15
+ }
16
+ },
17
+ async down(target) {
18
+ for (const statement of cloudflareQueueRollbackStatements) {
19
+ await runStatement(target, statement);
20
+ }
21
+ },
22
+ });
@@ -0,0 +1,43 @@
1
+ import type { CloudflareJobStore } from './CloudflareJobStore.js';
2
+ import type { CloudflareQueueConfig } from './types.js';
3
+ type SchedulerQueueApi = {
4
+ enqueue<T = unknown>(queue: string, payload: T): Promise<string>;
5
+ };
6
+ export type CloudflareQueueSchedulerConfig = {
7
+ queueName: string;
8
+ store: CloudflareJobStore;
9
+ queue: SchedulerQueueApi;
10
+ batchSize?: number;
11
+ stalledAfterMs?: number;
12
+ };
13
+ export declare const CloudflareQueueScheduler: Readonly<{
14
+ create: (config: CloudflareQueueSchedulerConfig) => {
15
+ dispatchDueJobs(): Promise<number>;
16
+ dispatchRepeatables(): Promise<number>;
17
+ reconcileStalled(): Promise<number>;
18
+ run(): Promise<{
19
+ jobs: number;
20
+ repeatables: number;
21
+ }>;
22
+ };
23
+ createFromQueueConfig(input: {
24
+ queueName: string;
25
+ config: CloudflareQueueConfig;
26
+ store: CloudflareJobStore;
27
+ queue: SchedulerQueueApi;
28
+ batchSize?: number;
29
+ }): {
30
+ dispatchDueJobs(): Promise<number>;
31
+ dispatchRepeatables(): Promise<number>;
32
+ reconcileStalled(): Promise<number>;
33
+ run(): Promise<{
34
+ jobs: number;
35
+ repeatables: number;
36
+ }>;
37
+ };
38
+ createScheduledHandler(config: CloudflareQueueSchedulerConfig): () => Promise<{
39
+ jobs: number;
40
+ repeatables: number;
41
+ }>;
42
+ }>;
43
+ export {};
@@ -0,0 +1,99 @@
1
+ const toEnvelope = (input) => ({
2
+ protocol: 'zintrust.cf.queue.v1',
3
+ jobId: input.jobId,
4
+ queueName: input.queueName,
5
+ name: input.name,
6
+ attempt: input.attempt,
7
+ availableAt: input.availableAt,
8
+ });
9
+ const createScheduler = (config) => {
10
+ return {
11
+ async dispatchDueJobs() {
12
+ const jobs = await config.store.getDueJobs(config.queueName, config.batchSize);
13
+ let dispatched = 0;
14
+ for (const job of jobs) {
15
+ await config.queue.enqueue(config.queueName, toEnvelope({
16
+ queueName: job.queueName,
17
+ jobId: job.id,
18
+ name: job.name,
19
+ attempt: job.attemptsMade,
20
+ availableAt: job.availableAt,
21
+ }));
22
+ await config.store.markDispatched(job.queueName, job.id);
23
+ dispatched += 1;
24
+ }
25
+ return dispatched;
26
+ },
27
+ async dispatchRepeatables() {
28
+ const rows = await config.store.getDueRepeatables(config.batchSize);
29
+ let dispatched = 0;
30
+ for (const row of rows) {
31
+ const payload = JSON.parse(row.payload);
32
+ const job = await config.store.createJob({
33
+ queueName: row.queue_name,
34
+ name: row.name,
35
+ data: payload,
36
+ });
37
+ await config.queue.enqueue(row.queue_name, toEnvelope({
38
+ queueName: row.queue_name,
39
+ jobId: job.id,
40
+ name: row.name,
41
+ attempt: 0,
42
+ availableAt: job.availableAt,
43
+ }));
44
+ await config.store.markDispatched(job.queueName, job.id);
45
+ await config.store.updateRepeatableAfterRun(row);
46
+ dispatched += 1;
47
+ }
48
+ return dispatched;
49
+ },
50
+ async reconcileStalled() {
51
+ const stalled = await config.store.getStalledJobs(config.queueName, config.stalledAfterMs ?? 60_000, config.batchSize);
52
+ let retried = 0;
53
+ for (const job of stalled) {
54
+ await config.store.updateState({
55
+ queueName: job.queueName,
56
+ jobId: job.id,
57
+ state: 'stalled',
58
+ });
59
+ await config.store.updateState({
60
+ queueName: job.queueName,
61
+ jobId: job.id,
62
+ state: 'retrying',
63
+ availableAt: new Date().toISOString(),
64
+ });
65
+ await config.queue.enqueue(job.queueName, toEnvelope({
66
+ queueName: job.queueName,
67
+ jobId: job.id,
68
+ name: job.name,
69
+ attempt: job.attemptsMade,
70
+ availableAt: job.availableAt,
71
+ }));
72
+ await config.store.markDispatched(job.queueName, job.id);
73
+ retried += 1;
74
+ }
75
+ return retried;
76
+ },
77
+ async run() {
78
+ await this.reconcileStalled();
79
+ const repeatables = await this.dispatchRepeatables();
80
+ const jobs = await this.dispatchDueJobs();
81
+ return { jobs, repeatables };
82
+ },
83
+ };
84
+ };
85
+ export const CloudflareQueueScheduler = Object.freeze({
86
+ create: createScheduler,
87
+ createFromQueueConfig(input) {
88
+ return createScheduler({
89
+ queueName: input.queueName,
90
+ store: input.store,
91
+ queue: input.queue,
92
+ batchSize: input.batchSize,
93
+ });
94
+ },
95
+ createScheduledHandler(config) {
96
+ const scheduler = createScheduler(config);
97
+ return async () => await scheduler.run();
98
+ },
99
+ });
@@ -0,0 +1,10 @@
1
+ import type { Command } from 'commander';
2
+ type CommandProvider = {
3
+ getCommand: () => Command;
4
+ info(message: string): void;
5
+ success(message: string): void;
6
+ };
7
+ export declare const MigrateCloudflareQueueCommand: Readonly<{
8
+ create(): CommandProvider;
9
+ }>;
10
+ export {};
@@ -0,0 +1,51 @@
1
+ import { BaseCommand } from '@zintrust/core/cli';
2
+ import { execFileSync } from 'node:child_process';
3
+ import { cloudflareQueueMigrationStatements, cloudflareQueueRollbackStatements, } from '../migrationSql.js';
4
+ const addOptions = (command) => {
5
+ command
6
+ .option('--database <name>', 'Wrangler D1 database binding/name', 'zintrust_db')
7
+ .option('--local', 'Run against local D1 database', true)
8
+ .option('--remote', 'Run against remote D1 database')
9
+ .option('--rollback', 'Drop Cloudflare queue state tables')
10
+ .option('--dry-run', 'Print generated SQL without applying it');
11
+ };
12
+ const joinStatements = (statements) => `${statements.join(';\n')};`;
13
+ const runWranglerD1 = (dbName, sql, remote) => {
14
+ const args = ['d1', 'execute', dbName, remote ? '--remote' : '--local', '--command', sql];
15
+ return execFileSync('wrangler', args, { encoding: 'utf-8' });
16
+ };
17
+ const execute = async (options, cmd) => {
18
+ const dbName = typeof options['database'] === 'string' && options['database'].trim() !== ''
19
+ ? options['database'].trim()
20
+ : 'zintrust_db';
21
+ const rollback = options['rollback'] === true;
22
+ const remote = options['remote'] === true;
23
+ const statements = rollback
24
+ ? cloudflareQueueRollbackStatements
25
+ : cloudflareQueueMigrationStatements;
26
+ const sql = joinStatements(statements);
27
+ if (options['dryRun'] === true) {
28
+ cmd.info(sql);
29
+ return;
30
+ }
31
+ const output = runWranglerD1(dbName, sql, remote);
32
+ if (output.trim() !== '')
33
+ cmd.info(output.trim());
34
+ cmd.success(rollback
35
+ ? 'Cloudflare queue state tables rolled back.'
36
+ : 'Cloudflare queue state tables migrated.');
37
+ };
38
+ export const MigrateCloudflareQueueCommand = Object.freeze({
39
+ create() {
40
+ return BaseCommand.create({
41
+ name: 'migrate:queue-cloudflare',
42
+ description: 'Run @zintrust/queue-cloudflare D1 state migrations',
43
+ aliases: ['queue-cloudflare:migrate'],
44
+ addOptions,
45
+ execute: async (options) => {
46
+ const command = MigrateCloudflareQueueCommand.create();
47
+ await execute(options, command);
48
+ },
49
+ });
50
+ },
51
+ });
@@ -0,0 +1,9 @@
1
+ type Registry = {
2
+ register: (id: string, provider: CliCommandProvider) => void;
3
+ };
4
+ type CliCommandProvider = {
5
+ getCommand: () => unknown;
6
+ name?: string;
7
+ };
8
+ export declare function registerCloudflareQueueCliCommands(registry: Registry): void;
9
+ export {};
@@ -0,0 +1,21 @@
1
+ const commandModule = (await import('./cli/MigrateCloudflareQueueCommand.js'));
2
+ export function registerCloudflareQueueCliCommands(registry) {
3
+ registry.register('migrate:queue-cloudflare', commandModule.MigrateCloudflareQueueCommand.create());
4
+ }
5
+ const globalWithRegistry = globalThis;
6
+ const globalRegistry = globalWithRegistry.__zintrust_cli_command_registry__ ??
7
+ (globalWithRegistry.__zintrust_cli_command_registry__ = new Map());
8
+ registerCloudflareQueueCliCommands({
9
+ register: (id, provider) => {
10
+ globalRegistry.set(id, provider);
11
+ },
12
+ });
13
+ try {
14
+ const coreCli = (await import('@zintrust/core/cli'));
15
+ if (coreCli.OptionalCliCommandRegistry !== undefined) {
16
+ registerCloudflareQueueCliCommands(coreCli.OptionalCliCommandRegistry);
17
+ }
18
+ }
19
+ catch {
20
+ // no-op
21
+ }
@@ -0,0 +1,50 @@
1
+ import { CloudflareQueueConsumer } from './CloudflareQueueConsumer.js';
2
+ import type { CloudflareJobOptions, CloudflareFlowInput, CloudflareFlowResult, CloudflareQueueConfig, CloudflareQueueJob, CloudflareQueueMetrics, CloudflareQueueProcessor, CloudflareQueueState, QueueMessage } from './types.js';
3
+ export type { CloudflareJobOptions, CloudflareFlowInput, CloudflareFlowResult, CloudflareQueueBackoff, CloudflareQueueBinding, CloudflareQueueConfig, CloudflareQueueContentType, CloudflareQueueEnvelope, CloudflareQueueJob, CloudflareQueueMetrics, CloudflareQueueProcessor, CloudflareQueueProcessorContext, CloudflareQueueState, CloudflareQueueStateConfig, CloudflareQueueRetention, CloudflareRepeatOptions, QueueMessage, } from './types.js';
4
+ export { CloudflareJobStore } from './CloudflareJobStore.js';
5
+ export { CloudflareQueueConsumer } from './CloudflareQueueConsumer.js';
6
+ export { CloudflareQueueCoordinator } from './CloudflareQueueCoordinator.js';
7
+ export { CloudflareQueueMigrator } from './CloudflareQueueMigrator.js';
8
+ export { CloudflareQueueScheduler } from './CloudflareQueueScheduler.js';
9
+ type CloudflareQueueDriver = {
10
+ enqueue<T = unknown>(queue: string, payload: T): Promise<string>;
11
+ dequeue<T = unknown>(queue: string): Promise<QueueMessage<T> | undefined>;
12
+ ack(queue: string, id: string): Promise<void>;
13
+ length(queue: string): Promise<number>;
14
+ drain(queue: string): Promise<void>;
15
+ add<T = unknown>(queue: string, name: string, data: T, options?: CloudflareJobOptions): Promise<CloudflareQueueJob<T>>;
16
+ addBulk<T = unknown>(queue: string, jobs: Array<{
17
+ name: string;
18
+ data: T;
19
+ options?: CloudflareJobOptions;
20
+ }>): Promise<Array<CloudflareQueueJob<T>>>;
21
+ getJob<T = unknown>(queue: string, id: string): Promise<CloudflareQueueJob<T> | null>;
22
+ getJobs<T = unknown>(queue: string, states?: CloudflareQueueState[], limit?: number): Promise<Array<CloudflareQueueJob<T>>>;
23
+ getJobCounts(queue: string, ...states: CloudflareQueueState[]): Promise<Record<string, number>>;
24
+ getMetrics(queue: string): Promise<CloudflareQueueMetrics>;
25
+ updateProgress(queue: string, id: string, progress: unknown): Promise<void>;
26
+ log(queue: string, id: string, message: string, data?: unknown): Promise<void>;
27
+ remove(queue: string, id: string): Promise<void>;
28
+ retry(queue: string, id: string): Promise<void>;
29
+ promote(queue: string, id: string): Promise<void>;
30
+ clean(queue: string, states: CloudflareQueueState[], olderThanMs: number): Promise<void>;
31
+ upsertJobScheduler<T = unknown>(queue: string, name: string, data: T, repeat: NonNullable<CloudflareJobOptions['repeat']>, id?: string): Promise<unknown>;
32
+ removeJobScheduler(id: string): Promise<void>;
33
+ runScheduler(queue: string, limit?: number): Promise<{
34
+ jobs: number;
35
+ repeatables: number;
36
+ }>;
37
+ reconcileStalled(queue: string, olderThanMs?: number, limit?: number): Promise<number>;
38
+ createFlow<TParent = unknown, TChild = unknown>(input: CloudflareFlowInput<TParent, TChild>): Promise<CloudflareFlowResult<TParent, TChild>>;
39
+ getFlowChildren<T = unknown>(queue: string, parentJobId: string): Promise<Array<CloudflareQueueJob<T>>>;
40
+ markFlowChildCompleted(queue: string, childJobId: string): Promise<Array<CloudflareQueueJob>>;
41
+ createConsumer<T = unknown, TResult = unknown>(processor: CloudflareQueueProcessor<T, TResult>, queueName?: string): ReturnType<typeof CloudflareQueueConsumer.create<T, TResult>>;
42
+ migrateState(): Promise<void>;
43
+ };
44
+ export declare const CloudflareQueues: Readonly<{
45
+ create(config?: CloudflareQueueConfig): CloudflareQueueDriver;
46
+ }>;
47
+ export declare const CloudflareQueue: Readonly<{
48
+ create(config?: CloudflareQueueConfig): CloudflareQueueDriver;
49
+ }>;
50
+ export default CloudflareQueues;