better-cf 0.2.2 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +153 -77
- package/dist/cli/index.js +2883 -1014
- package/dist/cli/index.js.map +1 -1
- package/dist/durable-object/index.d.ts +7 -0
- package/dist/durable-object/index.js +244 -0
- package/dist/durable-object/index.js.map +1 -0
- package/dist/durable-object/internal.d.ts +96 -0
- package/dist/durable-object/internal.js +427 -0
- package/dist/durable-object/internal.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +194 -129
- package/dist/index.js.map +1 -1
- package/dist/queue/index.d.ts +3 -3
- package/dist/queue/index.js +194 -129
- package/dist/queue/index.js.map +1 -1
- package/dist/queue/internal.d.ts +1 -1
- package/dist/testing/index.d.ts +21 -1
- package/dist/testing/index.js +342 -1
- package/dist/testing/index.js.map +1 -1
- package/dist/types-C1mNTuC-.d.ts +239 -0
- package/dist/{types-D44i92Zf.d.ts → types-CcW1NyB-.d.ts} +96 -29
- package/package.json +24 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/queue/internal.ts","../../src/testing/index.ts"],"names":[],"mappings":";AAKO,IAAM,eAAA,mBAAkB,MAAA,CAAO,GAAA,CAAI,2BAA2B,CAAA;AAmB9D,SAAS,kBAAqB,KAAA,EAAqC;AACxE,EAAA,IAAI,CAAC,KAAA,IAAS,OAAO,KAAA,KAAU,QAAA,EAAU;AACvC,IAAA,MAAM,IAAI,MAAM,gCAAgC,CAAA;AAAA,EAClD;AAEA,EAAA,MAAM,SAAA,GAAa,MAAgC,eAAe,CAAA;AAClE,EAAA,IAAI,CAAC,SAAA,EAAW;AACd,IAAA,MAAM,IAAI,MAAM,yCAAyC,CAAA;AAAA,EAC3D;AAEA,EAAA,OAAO,SAAA;AACT;;;ACIA,eAAsB,SAAA,CACpB,QACA,OAAA,EACoC;AACpC,EAAA,MAAM,SAAA,GAAY,kBAAqB,MAAM,CAAA;AAE7C,EAAA,IAAI,SAAA,IAAa,OAAA,IAAW,UAAA,IAAc,OAAA,EAAS;AACjD,IAAA,MAAM,IAAI,MAAM,yDAAyD,CAAA;AAAA,EAC3E;AAEA,EAAA,MAAM,WAAA,GAAc,OAAA,CAAQ,QAAA,KAAa,OAAA,CAAQ,OAAA,KAAY,SAAY,CAAC,OAAA,CAAQ,OAAO,CAAA,GAAI,EAAC,CAAA;AAC9F,EAAA,IAAI,WAAA,CAAY,WAAW,CAAA,EAAG;AAC5B,IAAA,MAAM,IAAI,MAAM,yCAAyC,CAAA;AAAA,EAC3D;AAEA,EAAA,MAAM,MAAA,GAAoC;AAAA,IACxC,OAAO,EAAC;AAAA,IACR,SAAS;AAAC,GACZ;AAEA,EAAA,MAAM,KAAA,GAA+B;AAAA,IACnC,KAAA,EAAO,YAAA;AAAA,IACP,QAAA,EAAU,WAAA,CAAY,GAAA,CAAI,CAAC,MAAM,KAAA,MAAW;AAAA,MAC1C,EAAA,EAAI,OAAO,KAAK,CAAA,CAAA;AAAA,MAChB,SAAA,sBAAe,IAAA,EAAK;AAAA,MACpB,IAAA;AAAA,MACA,QAAA,EAAU,QAAQ,QAAA,IAAY,CAAA;AAAA,MAC9B,KAAK,MAAM;AACT,QAAA,MAAA,CAAO,KAAA,CAAM,KAAK,IAAI,CAAA;AAAA,MACxB,CAAA;AAAA,MACA,OAAO,MAAM;AACX,QAAA,MAAA,CAAO,OAAA,CAAQ,KAAK,IAAI,CAAA;AAAA,MAC1B;AAAA,KACF,CAAE,CAAA;AAAA,IACF,QAAQ,MAAM;AACZ,MAAA,MAAA,CAAO,KAAA,CAAM,IAAA,CAAK,GAAG,WAAW,CAAA;AAAA,IAClC,CAAA;AAAA,IACA,UAAU,MAAM;AACd,MAAA,MAAA,CAAO,OAAA,CAAQ,IAAA,CAAK,GAAG,WAAW,CAAA;AAAA,IACpC;AAAA,GACF;AAEA,EAAA,MAAM,YAAA,GAAe;AAAA,IACnB,SAAA,GAAY;AACV,MAAA;AAAA,IACF,CAAA;AAAA,IACA,sBAAA,GAAyB;AACvB,MAAA;AAAA,IACF,CAAA;AAAA,IACA,OAAO;AAAC,GACV;AAEA,EAAA,MAAM,SAAA,CAAU,OAAA,CAAQ,KAAA,EAAO,OAAA,CAAQ,KAAK,YAAY,CAAA;AAExD,EAAA,OAAO,MAAA;AACT","file":"index.js","sourcesContent":["import type { QueueDefinition } from './types.js';\n\n/**\n * Symbol used to store non-enumerable queue internals on queue handles.\n */\nexport const kQueueInternals = Symbol.for('better-cf.queue.internals');\n\n/**\n * Internal queue API used by runtime/testing/CLI internals.\n */\nexport interface QueueInternalApi<E> {\n setBinding(name: string): void;\n getBinding(): string | null;\n getDefinition(): QueueDefinition<E>;\n consume(batch: MessageBatch<unknown>, env: E, executionCtx: ExecutionContext): Promise<void>;\n}\n\nexport type QueueWithInternals<E> = {\n [kQueueInternals]: QueueInternalApi<E>;\n};\n\n/**\n * Reads internal queue metadata from a queue handle.\n */\nexport function getQueueInternals<E>(value: unknown): QueueInternalApi<E> {\n if (!value || typeof value !== 'object') {\n throw new Error('Queue handle is not an object.');\n }\n\n const internals = (value as QueueWithInternals<E>)[kQueueInternals];\n if (!internals) {\n throw new Error('Object is not a better-cf queue handle.');\n }\n\n return internals;\n}\n\n/**\n * Input module shape accepted when resolving worker handlers.\n */\nexport interface WorkerModuleLike {\n default?: unknown;\n fetch?: (request: Request, env: unknown, ctx: ExecutionContext) => Promise<Response>;\n scheduled?: (\n event: ScheduledEvent,\n env: unknown,\n ctx: ExecutionContext\n ) => Promise<void>;\n}\n\n/**\n * Normalized handler pair resolved from a worker module export.\n */\nexport interface ResolvedWorkerHandlers {\n fetch: (request: Request, env: unknown, ctx: ExecutionContext) => Promise<Response>;\n scheduled?: (event: ScheduledEvent, env: unknown, ctx: ExecutionContext) => Promise<void>;\n}\n\n/**\n * Resolves `fetch`/`scheduled` handlers from various worker export styles.\n */\nexport function resolveWorkerHandlers(moduleLike: WorkerModuleLike): ResolvedWorkerHandlers {\n const root = moduleLike.default ?? moduleLike;\n\n let fetchHandler: ResolvedWorkerHandlers['fetch'] | undefined;\n if (typeof root === 'function') {\n fetchHandler = root as ResolvedWorkerHandlers['fetch'];\n } else if (root && typeof root === 'object' && 'fetch' in root) {\n const maybeFetch = (root as { fetch?: unknown }).fetch;\n if (typeof maybeFetch === 'function') {\n fetchHandler = maybeFetch.bind(root) as ResolvedWorkerHandlers['fetch'];\n }\n }\n\n if (!fetchHandler && typeof moduleLike.fetch === 'function') {\n fetchHandler = moduleLike.fetch;\n }\n\n if (!fetchHandler) {\n throw new Error(\n 'Could not resolve worker fetch handler. Export default app/object/function or named fetch.'\n );\n }\n\n let scheduledHandler: ResolvedWorkerHandlers['scheduled'] | undefined;\n if (root && typeof root === 'object' && 'scheduled' in root) {\n const maybeScheduled = (root as { scheduled?: unknown }).scheduled;\n if (typeof maybeScheduled === 'function') {\n scheduledHandler = maybeScheduled.bind(root) as ResolvedWorkerHandlers['scheduled'];\n }\n }\n\n if (!scheduledHandler && typeof moduleLike.scheduled === 'function') {\n scheduledHandler = moduleLike.scheduled;\n }\n\n return {\n fetch: fetchHandler,\n scheduled: scheduledHandler\n };\n}\n","import { getQueueInternals } from '../queue/internal.js';\n\n/**\n * Options for queue consumer tests.\n */\ninterface TestQueueBaseOptions<E> {\n env: E;\n /** Overrides message attempts metadata. */\n attempts?: number;\n}\n\n/**\n * Options for queue consumer tests.\n */\nexport type TestQueueOptions<E, TMessage> =\n | (TestQueueBaseOptions<E> & {\n /** Test one message. */\n message: TMessage;\n messages?: never;\n })\n | (TestQueueBaseOptions<E> & {\n /** Test many messages in one batch. */\n messages: TMessage[];\n message?: never;\n });\n\n/**\n * Test execution result for queue consumers.\n */\nexport interface TestQueueResult<TMessage> {\n /** Messages acked by the consumer. */\n acked: TMessage[];\n /** Messages retried by the consumer. */\n retried: TMessage[];\n}\n\n/**\n * Runs a queue declaration's consumer logic in-memory for tests.\n */\nexport async function testQueue<E, TMessage>(\n handle: unknown,\n options: TestQueueOptions<E, TMessage>\n): Promise<TestQueueResult<TMessage>> {\n const internals = getQueueInternals<E>(handle);\n\n if ('message' in options && 'messages' in options) {\n throw new Error('testQueue accepts either message or messages, not both.');\n }\n\n const allMessages = options.messages ?? (options.message !== undefined ? [options.message] : []);\n if (allMessages.length === 0) {\n throw new Error('testQueue requires message or messages.');\n }\n\n const result: TestQueueResult<TMessage> = {\n acked: [],\n retried: []\n };\n\n const batch: MessageBatch<unknown> = {\n queue: 'test-queue',\n messages: allMessages.map((body, index) => ({\n id: `msg-${index}`,\n timestamp: new Date(),\n body,\n attempts: options.attempts ?? 1,\n ack: () => {\n result.acked.push(body);\n },\n retry: () => {\n result.retried.push(body);\n }\n })),\n ackAll: () => {\n result.acked.push(...allMessages);\n },\n retryAll: () => {\n result.retried.push(...allMessages);\n }\n };\n\n const executionCtx = {\n waitUntil() {\n return;\n },\n passThroughOnException() {\n return;\n },\n props: {}\n } as unknown as ExecutionContext;\n\n await internals.consume(batch, options.env, executionCtx);\n\n return result;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/queue/internal.ts","../../src/queue/utils.ts","../../src/durable-object/internal.ts","../../src/testing/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { QueueDefinition } from './types.js';\n\n/**\n * Symbol used to store non-enumerable queue internals on queue handles.\n */\nexport const kQueueInternals = Symbol.for('better-cf.queue.internals');\n\n/**\n * Internal queue API used by runtime/testing/CLI internals.\n */\nexport interface QueueInternalApi<E> {\n setBinding(name: string): void;\n getBinding(): string | null;\n getDefinition(): QueueDefinition<E>;\n consume(batch: MessageBatch<unknown>, env: E, executionCtx: ExecutionContext): Promise<void>;\n}\n\nexport type QueueWithInternals<E> = {\n [kQueueInternals]: QueueInternalApi<E>;\n};\n\n/**\n * Reads internal queue metadata from a queue handle.\n */\nexport function getQueueInternals<E>(value: unknown): QueueInternalApi<E> {\n if (!value || typeof value !== 'object') {\n throw new Error('Queue handle is not an object.');\n }\n\n const internals = (value as QueueWithInternals<E>)[kQueueInternals];\n if (!internals) {\n throw new Error('Object is not a better-cf queue handle.');\n }\n\n return internals;\n}\n\n/**\n * Input module shape accepted when resolving worker handlers.\n */\nexport interface WorkerModuleLike {\n default?: unknown;\n fetch?: (request: Request, env: unknown, ctx: ExecutionContext) => Promise<Response>;\n scheduled?: (\n event: ScheduledEvent,\n env: unknown,\n ctx: ExecutionContext\n ) => Promise<void>;\n}\n\n/**\n * Normalized handler pair resolved from a worker module export.\n */\nexport interface ResolvedWorkerHandlers {\n fetch: (request: Request, env: unknown, ctx: ExecutionContext) => Promise<Response>;\n scheduled?: (event: ScheduledEvent, env: unknown, ctx: ExecutionContext) => Promise<void>;\n}\n\n/**\n * Resolves `fetch`/`scheduled` handlers from various worker export styles.\n */\nexport function resolveWorkerHandlers(moduleLike: WorkerModuleLike): ResolvedWorkerHandlers {\n const root = moduleLike.default ?? moduleLike;\n\n let fetchHandler: ResolvedWorkerHandlers['fetch'] | undefined;\n if (typeof root === 'function') {\n fetchHandler = root as ResolvedWorkerHandlers['fetch'];\n } else if (root && typeof root === 'object' && 'fetch' in root) {\n const maybeFetch = (root as { fetch?: unknown }).fetch;\n if (typeof maybeFetch === 'function') {\n fetchHandler = maybeFetch.bind(root) as ResolvedWorkerHandlers['fetch'];\n }\n }\n\n if (!fetchHandler && typeof moduleLike.fetch === 'function') {\n fetchHandler = moduleLike.fetch;\n }\n\n if (!fetchHandler) {\n throw new Error(\n 'Could not resolve worker fetch handler. Export default app/object/function or named fetch.'\n );\n }\n\n let scheduledHandler: ResolvedWorkerHandlers['scheduled'] | undefined;\n if (root && typeof root === 'object' && 'scheduled' in root) {\n const maybeScheduled = (root as { scheduled?: unknown }).scheduled;\n if (typeof maybeScheduled === 'function') {\n scheduledHandler = maybeScheduled.bind(root) as ResolvedWorkerHandlers['scheduled'];\n }\n }\n\n if (!scheduledHandler && typeof moduleLike.scheduled === 'function') {\n scheduledHandler = moduleLike.scheduled;\n }\n\n return {\n fetch: fetchHandler,\n scheduled: scheduledHandler\n };\n}\n","import type { Duration, SendOptions } from './types.js';\n\nexport function parseDurationSeconds(value: Duration): number {\n if (typeof value === 'number') {\n if (!Number.isFinite(value) || value < 0) {\n throw new Error(`Invalid duration number: ${value}`);\n }\n return value;\n }\n\n const match = value.match(/^(\\d+)(s|m|h)$/);\n if (!match) {\n throw new Error(`Invalid duration string: ${value}`);\n }\n\n const numberValue = Number.parseInt(match[1], 10);\n const unit = match[2];\n\n if (unit === 's') {\n return numberValue;\n }\n\n if (unit === 'm') {\n return numberValue * 60;\n }\n\n return numberValue * 3600;\n}\n\nexport function mergeSendOptions(entry?: SendOptions, batch?: SendOptions): SendOptions | undefined {\n if (!entry && !batch) {\n return undefined;\n }\n\n return {\n delay: entry?.delay ?? batch?.delay,\n contentType: entry?.contentType ?? batch?.contentType\n };\n}\n\nexport function toCloudflareSendOptions(options: SendOptions | undefined): {\n delaySeconds?: number;\n contentType?: SendOptions['contentType'];\n} {\n if (!options) {\n return {};\n }\n\n const result: { delaySeconds?: number; contentType?: SendOptions['contentType'] } = {};\n\n if (options.delay !== undefined) {\n result.delaySeconds = parseDurationSeconds(options.delay);\n }\n\n if (options.contentType !== undefined) {\n result.contentType = options.contentType;\n }\n\n return result;\n}\n\nexport function isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n","import { parseDurationSeconds, toCloudflareSendOptions } from '../queue/utils.js';\nimport type {\n BetterCfGeneratedApi,\n BetterCfGeneratedBindings,\n BetterCfSDK,\n DurableAlarmConfig,\n DurableBaseContext,\n DurableFetchConfig,\n DurableFnConfig,\n DurableObjectConfig,\n DurableWebSocketConfig,\n MultiJobQueueConfig,\n PullConsumerConfig,\n QueueBatchConsumerConfig,\n QueueConfig,\n QueueJobConfig,\n QueueMessageConsumerConfig,\n RuntimeEnv,\n WorkerConfig,\n WorkerContext\n} from './types.js';\nimport type { z } from 'zod';\n\nexport const kDurableObjectInternals = Symbol.for('better-cf.durable-object.definition');\nexport const kDurableRegistrationInternals = Symbol.for('better-cf.durable-object.registration');\nexport const kQueueDefinitionInternals = Symbol.for('better-cf.durable-object.queue.definition');\nexport const kQueueConsumerInternals = Symbol.for('better-cf.durable-object.queue.consumer');\nexport const kWorkerInternals = Symbol.for('better-cf.durable-object.worker');\n\ntype ApiFactory = (env: unknown, executionCtx: ExecutionContext) => BetterCfGeneratedApi;\n\nlet apiFactory: ApiFactory | null = null;\n\nexport function setGeneratedApiFactory(factory: ApiFactory): void {\n apiFactory = factory;\n}\n\nexport function createRuntimeContext<E>(env: E, executionCtx: ExecutionContext): WorkerContext<E> {\n return {\n env: env as RuntimeEnv<E>,\n executionCtx,\n api: (apiFactory?.(env, executionCtx) ?? {}) as BetterCfGeneratedApi\n };\n}\n\nexport interface DurableObjectInternal<TKey> {\n config: DurableObjectConfig<z.ZodType<TKey>>;\n keySchema: z.ZodType<TKey>;\n serializeKey: (value: TKey) => string;\n}\n\nexport interface DurableFunctionInternal<E, TKey, TArgs, TReturn> {\n visibility: 'public' | 'internal';\n config: DurableFnConfig<E, z.ZodType<TArgs>, TReturn>;\n}\n\nexport interface DurableFetchInternal<E> {\n config: DurableFetchConfig<E>;\n}\n\nexport interface DurableAlarmInternal<E> {\n config: DurableAlarmConfig<E>;\n}\n\nexport interface DurableInitInternal<E> {\n config: { description?: string; handler: (ctx: DurableBaseContext<E>) => Promise<void> | void };\n}\n\nexport interface DurableWebSocketInternal<E, TAttachment> {\n config: DurableWebSocketConfig<E, TAttachment>;\n}\n\ntype PushQueueConsumerType = 'message' | 'batch' | 'job-message';\n\nexport interface QueueDefinitionInternal {\n kind: 'single' | 'multi';\n config: QueueConfig<z.ZodTypeAny> | MultiJobQueueConfig<Record<string, unknown>>;\n bindingName: string | null;\n setBinding: (bindingName: string) => void;\n getBinding: () => string | null;\n}\n\nexport interface QueueConsumerInternal<E> {\n type: PushQueueConsumerType;\n queue: unknown;\n jobName?: string;\n config: QueueMessageConsumerConfig<E, unknown> | QueueBatchConsumerConfig<E, unknown>;\n}\n\nexport interface WorkerInternal<E> {\n config: WorkerConfig<E>;\n}\n\nexport function normalizeKey(value: unknown): string {\n if (typeof value === 'string') {\n return value;\n }\n\n if (typeof value === 'number' || typeof value === 'boolean' || value === null) {\n return String(value);\n }\n\n return JSON.stringify(value);\n}\n\nexport function makeDurableBaseContext<E>(\n env: E,\n executionCtx: ExecutionContext,\n state: DurableObjectState\n): DurableBaseContext<E> {\n const runtime = createRuntimeContext(env, executionCtx);\n return {\n ...runtime,\n state,\n storage: state.storage,\n sql: state.storage.sql\n };\n}\n\nexport function getDurableObjectInternals<TKey>(value: unknown): DurableObjectInternal<TKey> {\n if (!value || typeof value !== 'object') {\n throw new Error('Value is not a durable object definition.');\n }\n\n const internals = (value as Record<PropertyKey, unknown>)[kDurableObjectInternals];\n if (!internals) {\n throw new Error('Object is not a better-cf durable object handle.');\n }\n\n return internals as DurableObjectInternal<TKey>;\n}\n\nexport function getDurableRegistrationInternals(value: unknown):\n | DurableFunctionInternal<unknown, unknown, unknown, unknown>\n | DurableFetchInternal<unknown>\n | DurableAlarmInternal<unknown>\n | DurableInitInternal<unknown>\n | DurableWebSocketInternal<unknown, unknown> {\n if (!value || typeof value !== 'object') {\n throw new Error('Value is not a durable object registration.');\n }\n\n const internals = (value as Record<PropertyKey, unknown>)[kDurableRegistrationInternals];\n if (!internals) {\n throw new Error('Object is not a better-cf durable object registration.');\n }\n\n return internals as\n | DurableFunctionInternal<unknown, unknown, unknown, unknown>\n | DurableFetchInternal<unknown>\n | DurableAlarmInternal<unknown>\n | DurableInitInternal<unknown>\n | DurableWebSocketInternal<unknown, unknown>;\n}\n\nexport function getQueueDefinitionInternals(value: unknown): QueueDefinitionInternal {\n if (!value || typeof value !== 'object') {\n throw new Error('Value is not a queue definition.');\n }\n\n const internals = (value as Record<PropertyKey, unknown>)[kQueueDefinitionInternals];\n if (!internals) {\n throw new Error('Object is not a better-cf durable-object queue handle.');\n }\n\n return internals as QueueDefinitionInternal;\n}\n\nexport function getQueueConsumerInternals<E>(value: unknown): QueueConsumerInternal<E> {\n if (!value || typeof value !== 'object') {\n throw new Error('Value is not a queue consumer registration.');\n }\n\n const internals = (value as Record<PropertyKey, unknown>)[kQueueConsumerInternals];\n if (!internals) {\n throw new Error('Object is not a better-cf durable-object queue consumer registration.');\n }\n\n return internals as QueueConsumerInternal<E>;\n}\n\nexport function getWorkerInternals<E>(value: unknown): WorkerInternal<E> | undefined {\n if (!value || typeof value !== 'object') {\n return undefined;\n }\n\n const internals = (value as Record<PropertyKey, unknown>)[kWorkerInternals];\n return internals as WorkerInternal<E> | undefined;\n}\n\nexport function createQueueProducerApi(\n binding: unknown,\n payload: unknown,\n options?: { delay?: number; contentType?: string }\n): Promise<void> {\n const queueBinding = binding as\n | {\n send: (value: unknown, opts?: { delaySeconds?: number; contentType?: string }) => Promise<void>;\n }\n | undefined;\n\n if (!queueBinding || typeof queueBinding.send !== 'function') {\n throw new Error('Queue binding is not available in env.');\n }\n\n return queueBinding.send(payload, options);\n}\n\nexport function createQueueProducerBatchApi(\n binding: unknown,\n payload: Array<{ body: unknown; delaySeconds?: number; contentType?: string }>\n): Promise<void> {\n const queueBinding = binding as\n | {\n sendBatch: (entries: Array<{ body: unknown; delaySeconds?: number; contentType?: string }>) => Promise<void>;\n }\n | undefined;\n\n if (!queueBinding || typeof queueBinding.sendBatch !== 'function') {\n throw new Error('Queue binding is not available in env.');\n }\n\n return queueBinding.sendBatch(payload);\n}\n\nexport async function consumeQueueRegistration<E>(\n definitionHandle: unknown,\n consumerRegistration: unknown,\n batch: MessageBatch<unknown>,\n env: E,\n executionCtx: ExecutionContext\n): Promise<void> {\n const definition = getQueueDefinitionInternals(definitionHandle);\n const consumer = getQueueConsumerInternals<E>(consumerRegistration);\n const runtime = createRuntimeContext(env, executionCtx);\n\n if (definition.config.consumer && (definition.config.consumer as PullConsumerConfig).type === 'http_pull') {\n batch.ackAll();\n return;\n }\n\n if (consumer.type === 'batch') {\n let ackOrRetryHandled = false;\n const batchCtx = {\n ...runtime,\n batch: {\n queue: batch.queue,\n receivedAt: new Date(),\n firstMessageTimestamp: batch.messages[0]?.timestamp,\n ackAll: () => {\n ackOrRetryHandled = true;\n batch.ackAll();\n },\n retryAll: (options?: { delaySeconds?: number }) => {\n ackOrRetryHandled = true;\n batch.retryAll(options);\n }\n }\n };\n\n try {\n const schema = (definition.config as QueueConfig<z.ZodTypeAny>).args;\n const entries = batch.messages.map((message) => {\n const parsed = schema.safeParse(message.body);\n if (!parsed.success) {\n throw new Error(`Queue batch validation failed for ${message.id}: ${parsed.error.message}`);\n }\n\n return {\n data: parsed.data,\n id: message.id,\n timestamp: message.timestamp,\n attempts: message.attempts\n };\n });\n\n await (consumer.config as QueueBatchConsumerConfig<E, unknown>).handler(batchCtx, entries);\n if (!ackOrRetryHandled) {\n batch.ackAll();\n }\n } catch (error) {\n const failure = (consumer.config as QueueBatchConsumerConfig<E, unknown>).failure;\n if (failure) {\n await failure(batchCtx, null, toError(error));\n }\n if (!ackOrRetryHandled) {\n batch.retryAll(withRetryDelay(definition.config.retryDelay));\n }\n }\n return;\n }\n\n if (consumer.type === 'job-message') {\n const jobConfig = (definition.config as MultiJobQueueConfig<Record<string, unknown>>)[\n consumer.jobName as string\n ] as QueueJobConfig<z.ZodTypeAny>;\n\n for (const message of batch.messages) {\n const envelope = message.body as { _job?: string; data?: unknown };\n if (envelope?._job !== consumer.jobName) {\n if (!envelope?._job) {\n message.ack();\n }\n continue;\n }\n\n const messageCtx = {\n ...runtime,\n message: {\n id: message.id,\n timestamp: message.timestamp,\n attempts: message.attempts,\n queue: batch.queue\n }\n };\n\n try {\n const parsed = jobConfig.args.safeParse(envelope.data);\n if (!parsed.success) {\n throw new Error(`Queue job validation failed for ${consumer.jobName}: ${parsed.error.message}`);\n }\n\n await (consumer.config as QueueMessageConsumerConfig<E, unknown>).handler(messageCtx, parsed.data);\n message.ack();\n } catch (error) {\n const failure = (consumer.config as QueueMessageConsumerConfig<E, unknown>).failure;\n if (failure) {\n await failure(messageCtx, envelope.data ?? null, toError(error));\n }\n message.retry(withRetryDelay(definition.config.retryDelay));\n }\n }\n return;\n }\n\n for (const message of batch.messages) {\n const messageCtx = {\n ...runtime,\n message: {\n id: message.id,\n timestamp: message.timestamp,\n attempts: message.attempts,\n queue: batch.queue\n }\n };\n\n try {\n const schema = (definition.config as QueueConfig<z.ZodTypeAny>).args;\n const parsed = schema.safeParse(message.body);\n if (!parsed.success) {\n throw new Error(`Queue args validation failed: ${parsed.error.message}`);\n }\n\n await (consumer.config as QueueMessageConsumerConfig<E, unknown>).handler(messageCtx, parsed.data);\n message.ack();\n } catch (error) {\n const failure = (consumer.config as QueueMessageConsumerConfig<E, unknown>).failure;\n if (failure) {\n await failure(messageCtx, message.body as unknown, toError(error));\n }\n message.retry(withRetryDelay(definition.config.retryDelay));\n }\n }\n}\n\nexport async function invokeDurableFunction<E, TArgs, TReturn>(\n env: E,\n state: DurableObjectState,\n executionCtx: ExecutionContext,\n registration: unknown,\n args: TArgs\n): Promise<TReturn> {\n const internals = getDurableRegistrationInternals(registration) as DurableFunctionInternal<E, unknown, TArgs, TReturn>;\n const parsed = internals.config.args.safeParse(args);\n if (!parsed.success) {\n throw new Error(parsed.error.message);\n }\n\n const ctx = makeDurableBaseContext(env, executionCtx, state);\n const result = await internals.config.handler(ctx, parsed.data);\n if (internals.config.returns) {\n return internals.config.returns.parse(result);\n }\n return result;\n}\n\nexport async function invokeDurableFetch<E>(\n env: E,\n state: DurableObjectState,\n executionCtx: ExecutionContext,\n registration: unknown,\n request: Request\n): Promise<Response> {\n const internals = getDurableRegistrationInternals(registration) as DurableFetchInternal<E>;\n const ctx = makeDurableBaseContext(env, executionCtx, state);\n return internals.config.handler({\n ...ctx,\n request\n });\n}\n\nexport async function invokeDurableAlarm<E>(\n env: E,\n state: DurableObjectState,\n executionCtx: ExecutionContext,\n registration: unknown,\n alarmInfo: AlarmInvocationInfo\n): Promise<void> {\n const internals = getDurableRegistrationInternals(registration) as DurableAlarmInternal<E>;\n const ctx = makeDurableBaseContext(env, executionCtx, state);\n await internals.config.handler({\n ...ctx,\n alarmInfo\n });\n}\n\nexport async function invokeDurableInit<E>(\n env: E,\n state: DurableObjectState,\n executionCtx: ExecutionContext,\n registration: unknown\n): Promise<void> {\n const internals = getDurableRegistrationInternals(registration) as DurableInitInternal<E>;\n const ctx = makeDurableBaseContext(env, executionCtx, state);\n await internals.config.handler(ctx);\n}\n\nexport async function invokeDurableWebSocketConnect<E, TAttachment>(\n env: E,\n state: DurableObjectState,\n executionCtx: ExecutionContext,\n registration: unknown,\n request: Request\n): Promise<Response> {\n const internals = getDurableRegistrationInternals(registration) as DurableWebSocketInternal<E, TAttachment>;\n const pair = new WebSocketPair();\n const client = pair[0];\n const server = pair[1];\n let accepted = false;\n\n const ctx = makeDurableBaseContext(env, executionCtx, state);\n const response = await internals.config.connect?.({\n ...ctx,\n request,\n client,\n server,\n accept(options) {\n accepted = true;\n state.acceptWebSocket(server, options?.tags);\n if (options?.attachment !== undefined) {\n const attachment = internals.config.serializeAttachment\n ? internals.config.serializeAttachment(options.attachment)\n : options.attachment;\n server.serializeAttachment(attachment);\n }\n }\n });\n\n if (response) {\n return response;\n }\n\n if (!accepted) {\n state.acceptWebSocket(server);\n }\n\n return new Response(null, {\n status: 101,\n webSocket: client\n });\n}\n\nexport async function invokeDurableWebSocketMessage<E, TAttachment>(\n env: E,\n state: DurableObjectState,\n executionCtx: ExecutionContext,\n registration: unknown,\n socket: WebSocket,\n message: string | ArrayBuffer\n): Promise<void> {\n const internals = getDurableRegistrationInternals(registration) as DurableWebSocketInternal<E, TAttachment>;\n if (!internals.config.message) {\n return;\n }\n\n const ctx = makeDurableBaseContext(env, executionCtx, state);\n await internals.config.message({\n ...ctx,\n socket,\n attachment: hydrateAttachment(socket, internals)\n }, message);\n}\n\nexport async function invokeDurableWebSocketClose<E, TAttachment>(\n env: E,\n state: DurableObjectState,\n executionCtx: ExecutionContext,\n registration: unknown,\n socket: WebSocket,\n code: number,\n reason: string,\n wasClean: boolean\n): Promise<void> {\n const internals = getDurableRegistrationInternals(registration) as DurableWebSocketInternal<E, TAttachment>;\n if (!internals.config.close) {\n return;\n }\n\n const ctx = makeDurableBaseContext(env, executionCtx, state);\n await internals.config.close({\n ...ctx,\n socket,\n attachment: hydrateAttachment(socket, internals)\n }, code, reason, wasClean);\n}\n\nexport async function invokeDurableWebSocketError<E, TAttachment>(\n env: E,\n state: DurableObjectState,\n executionCtx: ExecutionContext,\n registration: unknown,\n socket: WebSocket,\n error: unknown\n): Promise<void> {\n const internals = getDurableRegistrationInternals(registration) as DurableWebSocketInternal<E, TAttachment>;\n if (!internals.config.error) {\n return;\n }\n\n const ctx = makeDurableBaseContext(env, executionCtx, state);\n await internals.config.error({\n ...ctx,\n socket,\n attachment: hydrateAttachment(socket, internals)\n }, error);\n}\n\nfunction hydrateAttachment<E, TAttachment>(\n socket: WebSocket,\n internals: DurableWebSocketInternal<E, TAttachment>\n): TAttachment | undefined {\n const value = socket.deserializeAttachment();\n if (value === undefined) {\n return undefined;\n }\n return internals.config.hydrateAttachment ? internals.config.hydrateAttachment(value) : (value as TAttachment);\n}\n\nfunction toError(error: unknown): Error {\n return error instanceof Error ? error : new Error(String(error));\n}\n\nfunction withRetryDelay(value: unknown): { delaySeconds?: number } | undefined {\n if (value === undefined) {\n return undefined;\n }\n\n return { delaySeconds: parseDurationSeconds(value as never) };\n}\n\nexport function createGeneratedQueueApi(binding: unknown, payload: unknown, options?: { delay?: unknown; contentType?: unknown }) {\n return createQueueProducerApi(binding, payload, toCloudflareSendOptions(options as never));\n}\n\nexport function createGeneratedQueueBatchApi(\n binding: unknown,\n messages: Array<{ data: unknown; delay?: unknown; contentType?: unknown }>\n) {\n return createQueueProducerBatchApi(\n binding,\n messages.map((message) => ({\n body: message.data,\n ...toCloudflareSendOptions(message as never)\n }))\n );\n}\n\nexport function resolveWorkerHandlers(moduleLike: {\n default?: unknown;\n fetch?: (request: Request, env: unknown, ctx: ExecutionContext) => Promise<Response>;\n scheduled?: (event: ScheduledEvent, env: unknown, ctx: ExecutionContext) => Promise<void>;\n}) {\n const root = moduleLike.default ?? moduleLike;\n const worker = getWorkerInternals(root);\n if (worker) {\n return {\n async fetch(request: Request, env: unknown, ctx: ExecutionContext): Promise<Response> {\n return worker.config.fetch(request, createRuntimeContext(env, ctx));\n },\n ...(worker.config.scheduled\n ? {\n async scheduled(event: ScheduledEvent, env: unknown, ctx: ExecutionContext): Promise<void> {\n await worker.config.scheduled?.(event, createRuntimeContext(env, ctx));\n }\n }\n : {})\n };\n }\n\n let fetchHandler: ((request: Request, env: unknown, ctx: ExecutionContext) => Promise<Response>) | undefined;\n if (root && typeof root === 'object' && 'fetch' in root) {\n const maybeFetch = (root as { fetch?: unknown }).fetch;\n if (typeof maybeFetch === 'function') {\n fetchHandler = maybeFetch.bind(root) as (request: Request, env: unknown, ctx: ExecutionContext) => Promise<Response>;\n }\n }\n\n if (!fetchHandler && typeof moduleLike.fetch === 'function') {\n fetchHandler = moduleLike.fetch;\n }\n\n if (!fetchHandler) {\n throw new Error('Could not resolve worker fetch handler.');\n }\n\n let scheduledHandler: ((event: ScheduledEvent, env: unknown, ctx: ExecutionContext) => Promise<void>) | undefined;\n if (root && typeof root === 'object' && 'scheduled' in root) {\n const maybeScheduled = (root as { scheduled?: unknown }).scheduled;\n if (typeof maybeScheduled === 'function') {\n scheduledHandler = maybeScheduled.bind(root) as (\n event: ScheduledEvent,\n env: unknown,\n ctx: ExecutionContext\n ) => Promise<void>;\n }\n }\n\n if (!scheduledHandler && typeof moduleLike.scheduled === 'function') {\n scheduledHandler = moduleLike.scheduled;\n }\n\n return {\n fetch: fetchHandler,\n scheduled: scheduledHandler\n };\n}\n","import { getQueueInternals } from '../queue/internal.js';\nimport { consumeQueueRegistration, invokeDurableFunction, setGeneratedApiFactory } from '../durable-object/internal.js';\nimport type { DurableFnArgs, DurableFnReturn } from '../durable-object/index.js';\n\n/**\n * Options for queue consumer tests.\n */\ninterface TestQueueBaseOptions<E> {\n /** Worker env object passed into queue consume simulation. */\n env: E;\n /** Overrides message attempts metadata. */\n attempts?: number;\n}\n\n/**\n * Options for queue consumer tests.\n */\nexport type TestQueueOptions<E, TMessage> =\n | (TestQueueBaseOptions<E> & {\n /** Test one message. */\n message: TMessage;\n messages?: never;\n })\n | (TestQueueBaseOptions<E> & {\n /** Test many messages in one batch. */\n messages: TMessage[];\n message?: never;\n });\n\n/**\n * Test execution result for queue consumers.\n */\nexport interface TestQueueResult<TMessage> {\n /** Messages acked by the consumer. */\n acked: TMessage[];\n /** Messages retried by the consumer. */\n retried: TMessage[];\n}\n\nexport type TestQueueConsumerOptions<E, TMessage> = TestQueueOptions<E, TMessage> & {\n /** Optional generated API object to inject into `ctx.api` for tests. */\n api?: Record<string, unknown>;\n};\n\nexport interface TestDurableFunctionOptions<E, TArgs> {\n env: E;\n args: TArgs;\n storage?: Map<string, unknown>;\n api?: Record<string, unknown>;\n}\n\n/**\n * Runs a queue declaration's consumer logic in-memory for tests.\n *\n * @param handle Queue handle returned by `defineQueue(...)` or `defineQueues(...)`.\n * @param options Test input payloads and env.\n * @returns Acked/retried payload collections captured from the simulated consume flow.\n */\nexport async function testQueue<E, TMessage>(\n handle: unknown,\n options: TestQueueOptions<E, TMessage>\n): Promise<TestQueueResult<TMessage>> {\n const internals = getQueueInternals<E>(handle);\n\n if ('message' in options && 'messages' in options) {\n throw new Error('testQueue accepts either message or messages, not both.');\n }\n\n const allMessages = options.messages ?? (options.message !== undefined ? [options.message] : []);\n if (allMessages.length === 0) {\n throw new Error('testQueue requires message or messages.');\n }\n\n const result: TestQueueResult<TMessage> = {\n acked: [],\n retried: []\n };\n\n const batch: MessageBatch<unknown> = {\n queue: 'test-queue',\n messages: allMessages.map((body, index) => ({\n id: `msg-${index}`,\n timestamp: new Date(),\n body,\n attempts: options.attempts ?? 1,\n ack: () => {\n result.acked.push(body);\n },\n retry: () => {\n result.retried.push(body);\n }\n })),\n ackAll: () => {\n result.acked.push(...allMessages);\n },\n retryAll: () => {\n result.retried.push(...allMessages);\n }\n };\n\n const executionCtx = {\n waitUntil() {\n return;\n },\n passThroughOnException() {\n return;\n },\n props: {}\n } as unknown as ExecutionContext;\n\n await internals.consume(batch, options.env, executionCtx);\n\n return result;\n}\n\nexport async function testQueueConsumer<E, TMessage>(\n queue: unknown,\n consumer: unknown,\n options: TestQueueConsumerOptions<E, TMessage>\n): Promise<TestQueueResult<TMessage>> {\n if (options.api) {\n setGeneratedApiFactory(() => options.api as never);\n }\n\n const result = createQueueBatch<E, TMessage>(options);\n const executionCtx = createExecutionContext();\n await consumeQueueRegistration(queue, consumer, result.batch, options.env, executionCtx);\n return result.result;\n}\n\nexport async function testDurableFunction<E, TFunction>(\n fn: TFunction,\n options: TestDurableFunctionOptions<E, DurableFnArgs<TFunction>>\n): Promise<DurableFnReturn<TFunction>> {\n if (options.api) {\n setGeneratedApiFactory(() => options.api as never);\n }\n\n const state = createDurableState(options.storage);\n const executionCtx = createExecutionContext();\n return invokeDurableFunction(options.env, state, executionCtx, fn, options.args as never) as Promise<\n DurableFnReturn<TFunction>\n >;\n}\n\nfunction createQueueBatch<E, TMessage>(options: TestQueueOptions<E, TMessage>) {\n if ('message' in options && 'messages' in options) {\n throw new Error('testQueueConsumer accepts either message or messages, not both.');\n }\n\n const allMessages = options.messages ?? (options.message !== undefined ? [options.message] : []);\n if (allMessages.length === 0) {\n throw new Error('testQueueConsumer requires message or messages.');\n }\n\n const result: TestQueueResult<TMessage> = {\n acked: [],\n retried: []\n };\n\n return {\n result,\n batch: {\n queue: 'test-queue',\n messages: allMessages.map((body, index) => ({\n id: `msg-${index}`,\n timestamp: new Date(),\n body,\n attempts: options.attempts ?? 1,\n ack: () => {\n result.acked.push(body);\n },\n retry: () => {\n result.retried.push(body);\n }\n })),\n ackAll: () => {\n result.acked.push(...allMessages);\n },\n retryAll: () => {\n result.retried.push(...allMessages);\n }\n } as MessageBatch<unknown>\n };\n}\n\nfunction createExecutionContext(): ExecutionContext {\n return {\n waitUntil() {\n return;\n },\n passThroughOnException() {\n return;\n },\n props: {}\n } as unknown as ExecutionContext;\n}\n\nfunction createDurableState(storageMap = new Map<string, unknown>()): DurableObjectState {\n const storage = {\n sql: {\n exec() {\n return {\n one() {\n return undefined;\n },\n toArray() {\n return [];\n },\n raw() {\n return [];\n }\n };\n }\n },\n async get(key: string) {\n return storageMap.get(key);\n },\n async put(key: string, value: unknown) {\n storageMap.set(key, value);\n },\n async delete(key: string) {\n return storageMap.delete(key);\n },\n async deleteAll() {\n storageMap.clear();\n },\n async list() {\n return new Map(storageMap);\n },\n async getAlarm() {\n return null;\n },\n async setAlarm() {\n return;\n },\n async deleteAlarm() {\n return;\n }\n } as unknown as DurableObjectStorage;\n\n return {\n storage,\n blockConcurrencyWhile<T>(callback: () => Promise<T>): Promise<T> {\n return callback();\n },\n waitUntil() {\n return;\n },\n acceptWebSocket() {\n return;\n },\n getWebSockets() {\n return [];\n }\n } as unknown as DurableObjectState;\n}\n"]}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
interface BetterCfGeneratedBindings {
|
|
4
|
+
}
|
|
5
|
+
interface BetterCfGeneratedApi {
|
|
6
|
+
}
|
|
7
|
+
interface BetterCfAutoEnv extends BetterCfGeneratedBindings {
|
|
8
|
+
[binding: string]: unknown;
|
|
9
|
+
}
|
|
10
|
+
type RuntimeEnv<E> = E & BetterCfGeneratedBindings;
|
|
11
|
+
type RuntimeApi = BetterCfGeneratedApi;
|
|
12
|
+
type Duration = number | `${number}s` | `${number}m` | `${number}h`;
|
|
13
|
+
type ContentType = 'json' | 'text' | 'bytes' | 'v8';
|
|
14
|
+
interface SendOptions {
|
|
15
|
+
delay?: Duration;
|
|
16
|
+
contentType?: ContentType;
|
|
17
|
+
}
|
|
18
|
+
interface SendBatchEntry<T> {
|
|
19
|
+
data: T;
|
|
20
|
+
delay?: Duration;
|
|
21
|
+
contentType?: ContentType;
|
|
22
|
+
}
|
|
23
|
+
interface BaseExecutionContext<E> {
|
|
24
|
+
env: RuntimeEnv<E>;
|
|
25
|
+
executionCtx: ExecutionContext;
|
|
26
|
+
api: RuntimeApi;
|
|
27
|
+
}
|
|
28
|
+
interface WorkerContext<E> extends BaseExecutionContext<E> {
|
|
29
|
+
}
|
|
30
|
+
interface QueueMessageContext<E> extends BaseExecutionContext<E> {
|
|
31
|
+
message: {
|
|
32
|
+
id: string;
|
|
33
|
+
timestamp: Date;
|
|
34
|
+
attempts: number;
|
|
35
|
+
queue: string;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
interface QueueBatchContext<E> extends BaseExecutionContext<E> {
|
|
39
|
+
batch: {
|
|
40
|
+
queue: string;
|
|
41
|
+
receivedAt: Date;
|
|
42
|
+
firstMessageTimestamp?: Date;
|
|
43
|
+
ackAll: () => void;
|
|
44
|
+
retryAll: (options?: {
|
|
45
|
+
delaySeconds?: number;
|
|
46
|
+
}) => void;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
interface DurableBaseContext<E> extends BaseExecutionContext<E> {
|
|
50
|
+
state: DurableObjectState;
|
|
51
|
+
storage: DurableObjectStorage;
|
|
52
|
+
sql: DurableObjectStorage['sql'];
|
|
53
|
+
}
|
|
54
|
+
interface DurableFetchContext<E> extends DurableBaseContext<E> {
|
|
55
|
+
request: Request;
|
|
56
|
+
}
|
|
57
|
+
interface DurableAlarmContext<E> extends DurableBaseContext<E> {
|
|
58
|
+
alarmInfo: AlarmInvocationInfo;
|
|
59
|
+
}
|
|
60
|
+
interface DurableWebSocketConnectContext<E, TAttachment> extends DurableBaseContext<E> {
|
|
61
|
+
request: Request;
|
|
62
|
+
client: WebSocket;
|
|
63
|
+
server: WebSocket;
|
|
64
|
+
accept: (options?: {
|
|
65
|
+
tags?: string[];
|
|
66
|
+
attachment?: TAttachment;
|
|
67
|
+
}) => void;
|
|
68
|
+
}
|
|
69
|
+
interface DurableWebSocketEventContext<E, TAttachment> extends DurableBaseContext<E> {
|
|
70
|
+
socket: WebSocket;
|
|
71
|
+
attachment: TAttachment | undefined;
|
|
72
|
+
}
|
|
73
|
+
interface QueueCommonConfig {
|
|
74
|
+
retry?: number;
|
|
75
|
+
retryDelay?: Duration;
|
|
76
|
+
deadLetter?: string;
|
|
77
|
+
deliveryDelay?: Duration;
|
|
78
|
+
visibilityTimeout?: Duration;
|
|
79
|
+
batch?: {
|
|
80
|
+
maxSize?: number;
|
|
81
|
+
timeout?: Duration;
|
|
82
|
+
maxConcurrency?: number;
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
interface PullConsumerConfig {
|
|
86
|
+
type: 'http_pull';
|
|
87
|
+
visibilityTimeout?: Duration;
|
|
88
|
+
}
|
|
89
|
+
interface QueueConfig<TSchema extends z.ZodTypeAny> extends QueueCommonConfig {
|
|
90
|
+
args: TSchema;
|
|
91
|
+
description?: string;
|
|
92
|
+
consumer?: {
|
|
93
|
+
type?: 'worker';
|
|
94
|
+
} | PullConsumerConfig;
|
|
95
|
+
}
|
|
96
|
+
interface QueueJobConfig<TSchema extends z.ZodTypeAny> {
|
|
97
|
+
args: TSchema;
|
|
98
|
+
description?: string;
|
|
99
|
+
}
|
|
100
|
+
type MultiJobQueueConfig<TConfig extends Record<string, unknown>> = QueueCommonConfig & {
|
|
101
|
+
description?: string;
|
|
102
|
+
consumer?: never;
|
|
103
|
+
args?: never;
|
|
104
|
+
} & TConfig;
|
|
105
|
+
interface QueueMessageConsumerConfig<E, TMessage> {
|
|
106
|
+
description?: string;
|
|
107
|
+
handler: (ctx: QueueMessageContext<E>, args: TMessage) => Promise<void> | void;
|
|
108
|
+
failure?: (ctx: QueueMessageContext<E>, args: TMessage | null, error: Error) => Promise<void> | void;
|
|
109
|
+
}
|
|
110
|
+
interface QueueBatchConsumerConfig<E, TMessage> {
|
|
111
|
+
description?: string;
|
|
112
|
+
handler: (ctx: QueueBatchContext<E>, args: ConsumerBatchEntry<TMessage>[]) => Promise<void> | void;
|
|
113
|
+
failure?: (ctx: QueueBatchContext<E>, args: ConsumerBatchEntry<TMessage>[] | null, error: Error) => Promise<void> | void;
|
|
114
|
+
}
|
|
115
|
+
interface ConsumerBatchEntry<T> {
|
|
116
|
+
data: T;
|
|
117
|
+
id: string;
|
|
118
|
+
timestamp: Date;
|
|
119
|
+
attempts: number;
|
|
120
|
+
}
|
|
121
|
+
interface DurableObjectConfig<TKeySchema extends z.ZodTypeAny> {
|
|
122
|
+
name: string;
|
|
123
|
+
key: TKeySchema;
|
|
124
|
+
version?: number;
|
|
125
|
+
description?: string;
|
|
126
|
+
}
|
|
127
|
+
interface DurableFnConfig<E, TArgsSchema extends z.ZodTypeAny, TReturn> {
|
|
128
|
+
args: TArgsSchema;
|
|
129
|
+
returns?: z.ZodType<TReturn>;
|
|
130
|
+
description?: string;
|
|
131
|
+
handler: (ctx: DurableBaseContext<E>, args: z.infer<TArgsSchema>) => Promise<TReturn> | TReturn;
|
|
132
|
+
}
|
|
133
|
+
interface DurableFetchConfig<E> {
|
|
134
|
+
description?: string;
|
|
135
|
+
handler: (ctx: DurableFetchContext<E>) => Promise<Response> | Response;
|
|
136
|
+
}
|
|
137
|
+
interface DurableAlarmConfig<E> {
|
|
138
|
+
description?: string;
|
|
139
|
+
handler: (ctx: DurableAlarmContext<E>) => Promise<void> | void;
|
|
140
|
+
}
|
|
141
|
+
interface DurableInitConfig<E> {
|
|
142
|
+
description?: string;
|
|
143
|
+
handler: (ctx: DurableBaseContext<E>) => Promise<void> | void;
|
|
144
|
+
}
|
|
145
|
+
interface DurableWebSocketConfig<E, TAttachment = unknown> {
|
|
146
|
+
description?: string;
|
|
147
|
+
connect?: (ctx: DurableWebSocketConnectContext<E, TAttachment>) => Promise<Response | void> | Response | void;
|
|
148
|
+
message?: (ctx: DurableWebSocketEventContext<E, TAttachment>, message: string | ArrayBuffer) => Promise<void> | void;
|
|
149
|
+
close?: (ctx: DurableWebSocketEventContext<E, TAttachment>, code: number, reason: string, wasClean: boolean) => Promise<void> | void;
|
|
150
|
+
error?: (ctx: DurableWebSocketEventContext<E, TAttachment>, error: unknown) => Promise<void> | void;
|
|
151
|
+
serializeAttachment?: (attachment: TAttachment) => unknown;
|
|
152
|
+
hydrateAttachment?: (attachment: unknown) => TAttachment;
|
|
153
|
+
}
|
|
154
|
+
interface WorkerConfig<E> {
|
|
155
|
+
fetch: (request: Request, ctx: WorkerContext<E>) => Promise<Response>;
|
|
156
|
+
scheduled?: (event: ScheduledEvent, ctx: WorkerContext<E>) => Promise<void>;
|
|
157
|
+
}
|
|
158
|
+
interface WorkerEntrypoint<E> {
|
|
159
|
+
fetch(request: Request, env: E, executionCtx: ExecutionContext): Promise<Response>;
|
|
160
|
+
scheduled?: (event: ScheduledEvent, env: E, executionCtx: ExecutionContext) => Promise<void>;
|
|
161
|
+
}
|
|
162
|
+
interface QueueHandle<E, TMessage> {
|
|
163
|
+
message(config: QueueMessageConsumerConfig<E, TMessage>): QueueConsumerRef<TMessage>;
|
|
164
|
+
batch(config: QueueBatchConsumerConfig<E, TMessage>): QueueBatchConsumerRef<TMessage>;
|
|
165
|
+
}
|
|
166
|
+
interface QueueJobHandle<E, TMessage> {
|
|
167
|
+
message(config: QueueMessageConsumerConfig<E, TMessage>): QueueJobConsumerRef<TMessage>;
|
|
168
|
+
}
|
|
169
|
+
type MultiJobQueueHandle<E, TJobs extends Record<string, QueueJobConfig<z.ZodTypeAny>>> = {
|
|
170
|
+
[K in keyof TJobs]: QueueJobHandle<E, z.infer<TJobs[K]['args']>>;
|
|
171
|
+
};
|
|
172
|
+
interface DurableObjectHandle<E, TKey> {
|
|
173
|
+
fn<TArgsSchema extends z.ZodTypeAny, TReturn>(config: DurableFnConfig<E, TArgsSchema, TReturn>): DurableFnRef<TKey, z.infer<TArgsSchema>, TReturn>;
|
|
174
|
+
internal<TArgsSchema extends z.ZodTypeAny, TReturn>(config: DurableFnConfig<E, TArgsSchema, TReturn>): DurableFnRef<TKey, z.infer<TArgsSchema>, TReturn>;
|
|
175
|
+
fetch(config: DurableFetchConfig<E>): DurableFetchRef;
|
|
176
|
+
alarm(config: DurableAlarmConfig<E>): DurableAlarmRef;
|
|
177
|
+
init(config: DurableInitConfig<E>): DurableInitRef;
|
|
178
|
+
websocket<TAttachment = unknown>(config: DurableWebSocketConfig<E, TAttachment>): DurableWebSocketRef<TAttachment>;
|
|
179
|
+
}
|
|
180
|
+
interface QueueConsumerRef<TMessage> {
|
|
181
|
+
readonly __type?: 'queue-message';
|
|
182
|
+
readonly __message?: TMessage;
|
|
183
|
+
}
|
|
184
|
+
interface QueueBatchConsumerRef<TMessage> {
|
|
185
|
+
readonly __type?: 'queue-batch';
|
|
186
|
+
readonly __message?: TMessage;
|
|
187
|
+
}
|
|
188
|
+
interface QueueJobConsumerRef<TMessage> {
|
|
189
|
+
readonly __type?: 'queue-job-message';
|
|
190
|
+
readonly __message?: TMessage;
|
|
191
|
+
}
|
|
192
|
+
interface DurableFnRef<TKey, TArgs, TReturn> {
|
|
193
|
+
readonly __type?: 'durable-fn';
|
|
194
|
+
readonly __key?: TKey;
|
|
195
|
+
readonly __args?: TArgs;
|
|
196
|
+
readonly __return?: TReturn;
|
|
197
|
+
}
|
|
198
|
+
interface DurableFetchRef {
|
|
199
|
+
readonly __type?: 'durable-fetch';
|
|
200
|
+
}
|
|
201
|
+
interface DurableAlarmRef {
|
|
202
|
+
readonly __type?: 'durable-alarm';
|
|
203
|
+
}
|
|
204
|
+
interface DurableInitRef {
|
|
205
|
+
readonly __type?: 'durable-init';
|
|
206
|
+
}
|
|
207
|
+
interface DurableWebSocketRef<TAttachment> {
|
|
208
|
+
readonly __type?: 'durable-websocket';
|
|
209
|
+
readonly __attachment?: TAttachment;
|
|
210
|
+
}
|
|
211
|
+
type QueuePayload<TQueue> = TQueue extends QueueHandle<any, infer TMessage> ? TMessage : never;
|
|
212
|
+
type QueueJobPayload<TJob> = TJob extends QueueJobHandle<any, infer TMessage> ? TMessage : never;
|
|
213
|
+
type DurableObjectKey<TObject> = TObject extends DurableObjectHandle<any, infer TKey> ? TKey : never;
|
|
214
|
+
type DurableFnKey<TFn> = TFn extends DurableFnRef<infer TKey, any, any> ? TKey : never;
|
|
215
|
+
type DurableFnArgs<TFn> = TFn extends DurableFnRef<any, infer TArgs, any> ? TArgs : never;
|
|
216
|
+
type DurableFnReturn<TFn> = TFn extends DurableFnRef<any, any, infer TReturn> ? TReturn : never;
|
|
217
|
+
interface DefineDurableObject<E> {
|
|
218
|
+
<TKeySchema extends z.ZodTypeAny>(config: DurableObjectConfig<TKeySchema>): DurableObjectHandle<E, z.infer<TKeySchema>>;
|
|
219
|
+
}
|
|
220
|
+
interface DefineQueue<E> {
|
|
221
|
+
<TSchema extends z.ZodTypeAny>(config: QueueConfig<TSchema>): QueueHandle<E, z.infer<TSchema>>;
|
|
222
|
+
}
|
|
223
|
+
interface DefineQueues<E> {
|
|
224
|
+
<const TConfig extends Record<string, unknown>>(config: MultiJobQueueConfig<TConfig>): MultiJobQueueHandle<E, ExtractQueueJobs<TConfig>>;
|
|
225
|
+
}
|
|
226
|
+
type ExtractQueueJobs<TConfig extends Record<string, unknown>> = {
|
|
227
|
+
[K in keyof TConfig as TConfig[K] extends QueueJobConfig<z.ZodTypeAny> ? K : never]: TConfig[K] extends QueueJobConfig<z.ZodTypeAny> ? TConfig[K] : never;
|
|
228
|
+
};
|
|
229
|
+
interface DefineWorker<E> {
|
|
230
|
+
(config: WorkerConfig<E>): WorkerEntrypoint<E>;
|
|
231
|
+
}
|
|
232
|
+
interface BetterCfSDK<E> {
|
|
233
|
+
defineDurableObject: DefineDurableObject<E>;
|
|
234
|
+
defineQueue: DefineQueue<E>;
|
|
235
|
+
defineQueues: DefineQueues<E>;
|
|
236
|
+
defineWorker: DefineWorker<E>;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
export type { MultiJobQueueHandle as A, BetterCfAutoEnv as B, ConsumerBatchEntry as C, DefineDurableObject as D, QueueBatchConsumerRef as E, QueueBatchContext as F, QueueCommonConfig as G, QueueConfig as H, QueueConsumerRef as I, QueueHandle as J, QueueJobConfig as K, QueueJobConsumerRef as L, MultiJobQueueConfig as M, QueueJobHandle as N, QueueJobPayload as O, PullConsumerConfig as P, QueueBatchConsumerConfig as Q, QueueMessageConsumerConfig as R, QueueMessageContext as S, QueuePayload as T, RuntimeApi as U, RuntimeEnv as V, SendBatchEntry as W, SendOptions as X, WorkerConfig as Y, WorkerContext as Z, WorkerEntrypoint as _, BetterCfSDK as a, BetterCfGeneratedApi as b, BetterCfGeneratedBindings as c, ContentType as d, DefineQueue as e, DefineQueues as f, DefineWorker as g, DurableAlarmConfig as h, DurableBaseContext as i, DurableFetchConfig as j, DurableFetchRef as k, DurableFnArgs as l, DurableFnConfig as m, DurableFnKey as n, DurableFnRef as o, DurableFnReturn as p, DurableInitConfig as q, DurableInitRef as r, DurableObjectConfig as s, DurableObjectHandle as t, DurableObjectKey as u, DurableWebSocketConfig as v, DurableWebSocketConnectContext as w, DurableWebSocketEventContext as x, DurableWebSocketRef as y, Duration as z };
|
|
@@ -40,20 +40,30 @@ type SendBatchOptions = SendOptions;
|
|
|
40
40
|
* Per-message input for `sendBatch`.
|
|
41
41
|
*/
|
|
42
42
|
interface SendBatchEntry<T> {
|
|
43
|
+
/** Payload to enqueue. */
|
|
43
44
|
data: T;
|
|
45
|
+
/** Per-message delay override (takes precedence over batch-level `options.delay`). */
|
|
44
46
|
delay?: Duration;
|
|
47
|
+
/** Per-message content type override (takes precedence over batch-level `options.contentType`). */
|
|
45
48
|
contentType?: ContentType;
|
|
46
49
|
}
|
|
47
50
|
/**
|
|
48
51
|
* Context passed to per-message queue consumers.
|
|
49
52
|
*/
|
|
50
53
|
interface QueueContext<E> {
|
|
54
|
+
/** Queue-aware runtime environment (`env` + generated bindings). */
|
|
51
55
|
env: QueueEnv<E>;
|
|
56
|
+
/** Cloudflare execution context. */
|
|
52
57
|
executionCtx: ExecutionContext;
|
|
58
|
+
/** Metadata for the currently processed message. */
|
|
53
59
|
message: {
|
|
60
|
+
/** Unique Cloudflare queue message id. */
|
|
54
61
|
id: string;
|
|
62
|
+
/** Message enqueue timestamp. */
|
|
55
63
|
timestamp: Date;
|
|
64
|
+
/** Delivery attempt count for this message. */
|
|
56
65
|
attempts: number;
|
|
66
|
+
/** Queue name currently being consumed. */
|
|
57
67
|
queue: string;
|
|
58
68
|
};
|
|
59
69
|
}
|
|
@@ -61,13 +71,21 @@ interface QueueContext<E> {
|
|
|
61
71
|
* Context passed to batch queue consumers.
|
|
62
72
|
*/
|
|
63
73
|
interface BatchContext<E> {
|
|
74
|
+
/** Queue-aware runtime environment (`env` + generated bindings). */
|
|
64
75
|
env: QueueEnv<E>;
|
|
76
|
+
/** Cloudflare execution context. */
|
|
65
77
|
executionCtx: ExecutionContext;
|
|
78
|
+
/** Batch metadata + helpers for explicit ack/retry control. */
|
|
66
79
|
batch: {
|
|
80
|
+
/** Queue name currently being consumed. */
|
|
67
81
|
queue: string;
|
|
82
|
+
/** When the batch was received by this worker invocation. */
|
|
68
83
|
receivedAt: Date;
|
|
84
|
+
/** Timestamp of first message in this batch (if present). */
|
|
69
85
|
firstMessageTimestamp?: Date;
|
|
86
|
+
/** Ack every message in the current batch. */
|
|
70
87
|
ackAll: () => void;
|
|
88
|
+
/** Retry every message in the current batch. */
|
|
71
89
|
retryAll: (options?: {
|
|
72
90
|
delaySeconds?: number;
|
|
73
91
|
}) => void;
|
|
@@ -77,16 +95,22 @@ interface BatchContext<E> {
|
|
|
77
95
|
* Context passed to worker handlers.
|
|
78
96
|
*/
|
|
79
97
|
interface WorkerContext<E> {
|
|
98
|
+
/** Queue-aware runtime environment (`env` + generated bindings). */
|
|
80
99
|
env: QueueEnv<E>;
|
|
100
|
+
/** Cloudflare execution context. */
|
|
81
101
|
executionCtx: ExecutionContext;
|
|
82
102
|
}
|
|
83
103
|
/**
|
|
84
104
|
* Message shape received by batch consumers.
|
|
85
105
|
*/
|
|
86
106
|
interface ConsumerBatchEntry<T> {
|
|
107
|
+
/** Validated payload data. */
|
|
87
108
|
data: T;
|
|
109
|
+
/** Unique Cloudflare queue message id. */
|
|
88
110
|
id: string;
|
|
111
|
+
/** Message enqueue timestamp. */
|
|
89
112
|
timestamp: Date;
|
|
113
|
+
/** Delivery attempt count for this message. */
|
|
90
114
|
attempts: number;
|
|
91
115
|
}
|
|
92
116
|
/**
|
|
@@ -105,8 +129,11 @@ interface QueueCommonConfig {
|
|
|
105
129
|
visibilityTimeout?: Duration;
|
|
106
130
|
/** Batch processing tuning (worker consumer mode only). */
|
|
107
131
|
batch?: {
|
|
132
|
+
/** Maximum number of messages per delivered batch. */
|
|
108
133
|
maxSize?: number;
|
|
134
|
+
/** Maximum time to wait before delivering a partial batch. */
|
|
109
135
|
timeout?: Duration;
|
|
136
|
+
/** Maximum concurrent batch invocations. */
|
|
110
137
|
maxConcurrency?: number;
|
|
111
138
|
};
|
|
112
139
|
}
|
|
@@ -116,55 +143,72 @@ interface QueueCommonConfig {
|
|
|
116
143
|
interface PullConsumerConfig {
|
|
117
144
|
/** Pull mode marker. */
|
|
118
145
|
type: 'http_pull';
|
|
119
|
-
/** Pull visibility timeout
|
|
146
|
+
/** Pull visibility timeout (seconds or duration shorthand). */
|
|
120
147
|
visibilityTimeout?: Duration;
|
|
121
148
|
}
|
|
122
149
|
/**
|
|
123
150
|
* Per-message queue handler.
|
|
124
151
|
*/
|
|
125
|
-
type
|
|
152
|
+
type QueueHandler<E, TSchema extends z.ZodTypeAny> = (ctx: QueueContext<E>, args: z.infer<TSchema>) => Promise<void>;
|
|
126
153
|
/**
|
|
127
154
|
* Batch queue handler.
|
|
128
155
|
*/
|
|
129
|
-
type
|
|
156
|
+
type QueueBatchHandler<E, TSchema extends z.ZodTypeAny> = (ctx: BatchContext<E>, args: ConsumerBatchEntry<z.infer<TSchema>>[]) => Promise<void>;
|
|
130
157
|
/**
|
|
131
158
|
* Optional failure handler for queue processing.
|
|
132
159
|
*/
|
|
133
|
-
type QueueFailureHandler<E, TSchema extends z.ZodTypeAny> = (ctx: QueueContext<E> | BatchContext<E>,
|
|
160
|
+
type QueueFailureHandler<E, TSchema extends z.ZodTypeAny> = (ctx: QueueContext<E> | BatchContext<E>, args: z.infer<TSchema> | null, error: Error) => Promise<void>;
|
|
134
161
|
/**
|
|
135
162
|
* Worker-consumer queue with per-message processing.
|
|
136
163
|
*/
|
|
137
164
|
type QueueProcessConfig<E, TSchema extends z.ZodTypeAny> = QueueCommonConfig & {
|
|
138
|
-
|
|
165
|
+
/** Zod schema used to validate each incoming payload. */
|
|
166
|
+
args: TSchema;
|
|
167
|
+
/** Optional explicit worker consumer marker. */
|
|
139
168
|
consumer?: {
|
|
140
169
|
type?: 'worker';
|
|
141
170
|
};
|
|
142
|
-
|
|
143
|
-
|
|
171
|
+
/** Per-message push handler. */
|
|
172
|
+
handler: QueueHandler<E, TSchema>;
|
|
173
|
+
/** Not allowed in single-message mode. */
|
|
174
|
+
batchHandler?: never;
|
|
175
|
+
/** Optional failure hook when `handler` throws or payload validation fails. */
|
|
144
176
|
onFailure?: QueueFailureHandler<E, TSchema>;
|
|
145
177
|
};
|
|
146
178
|
/**
|
|
147
179
|
* Worker-consumer queue with batch processing.
|
|
148
180
|
*/
|
|
149
181
|
type QueueBatchConfig<E, TSchema extends z.ZodTypeAny> = QueueCommonConfig & {
|
|
150
|
-
|
|
182
|
+
/** Zod schema used to validate each payload before `batchHandler` runs. */
|
|
183
|
+
args: TSchema;
|
|
184
|
+
/** Optional explicit worker consumer marker. */
|
|
151
185
|
consumer?: {
|
|
152
186
|
type?: 'worker';
|
|
153
187
|
};
|
|
154
|
-
|
|
155
|
-
|
|
188
|
+
/** Not allowed in batch mode. */
|
|
189
|
+
handler?: never;
|
|
190
|
+
/** Batch push handler. */
|
|
191
|
+
batchHandler: QueueBatchHandler<E, TSchema>;
|
|
192
|
+
/** Optional failure hook when `batchHandler` throws or batch validation fails. */
|
|
156
193
|
onFailure?: QueueFailureHandler<E, TSchema>;
|
|
157
194
|
};
|
|
158
195
|
/**
|
|
159
196
|
* HTTP pull consumer queue (producer-only declaration).
|
|
160
197
|
*/
|
|
161
198
|
type QueuePullConfig<E, TSchema extends z.ZodTypeAny> = Omit<QueueCommonConfig, 'visibilityTimeout' | 'batch'> & {
|
|
162
|
-
|
|
199
|
+
/** Zod schema for producer payload typing in pull mode. */
|
|
200
|
+
args: TSchema;
|
|
201
|
+
/** Required pull consumer configuration. */
|
|
163
202
|
consumer: PullConsumerConfig;
|
|
203
|
+
/** Not allowed in pull mode. */
|
|
164
204
|
batch?: never;
|
|
205
|
+
/** Not allowed in pull mode. */
|
|
165
206
|
visibilityTimeout?: never;
|
|
166
|
-
|
|
167
|
-
|
|
207
|
+
/** Not allowed in pull mode. */
|
|
208
|
+
handler?: never;
|
|
209
|
+
/** Not allowed in pull mode. */
|
|
210
|
+
batchHandler?: never;
|
|
211
|
+
/** Not allowed in pull mode. */
|
|
168
212
|
onFailure?: never;
|
|
169
213
|
};
|
|
170
214
|
/**
|
|
@@ -175,9 +219,12 @@ type QueueConfig<E, TSchema extends z.ZodTypeAny> = QueueProcessConfig<E, TSchem
|
|
|
175
219
|
* Per-job declaration inside a multi-job queue.
|
|
176
220
|
*/
|
|
177
221
|
interface JobConfig<E, TSchema extends z.ZodTypeAny> {
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
222
|
+
/** Zod schema used to validate this job's payload. */
|
|
223
|
+
args: TSchema;
|
|
224
|
+
/** Job handler for this job key. */
|
|
225
|
+
handler: (ctx: QueueContext<E>, args: z.infer<TSchema>) => Promise<void>;
|
|
226
|
+
/** Optional failure hook for this job handler. */
|
|
227
|
+
onFailure?: (ctx: QueueContext<E>, args: z.infer<TSchema>, error: Error) => Promise<void>;
|
|
181
228
|
}
|
|
182
229
|
/**
|
|
183
230
|
* Internal helper alias for any job config.
|
|
@@ -193,10 +240,15 @@ type ExtractJobMap<E, TConfig extends Record<string, unknown>> = {
|
|
|
193
240
|
* Multi-job queue declaration object.
|
|
194
241
|
*/
|
|
195
242
|
type MultiJobQueueConfig<E, TConfig extends Record<string, unknown>> = QueueCommonConfig & {
|
|
243
|
+
/** Not allowed at top level in multi-job mode; define `args` per job key. */
|
|
196
244
|
consumer?: never;
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
245
|
+
/** Not allowed at top level in multi-job mode; define `args` per job key. */
|
|
246
|
+
args?: never;
|
|
247
|
+
/** Not allowed at top level in multi-job mode; define `handler` per job key. */
|
|
248
|
+
handler?: never;
|
|
249
|
+
/** Not allowed in multi-job mode. */
|
|
250
|
+
batchHandler?: never;
|
|
251
|
+
/** Not allowed at top level in multi-job mode; define `onFailure` per job key. */
|
|
200
252
|
onFailure?: never;
|
|
201
253
|
} & TConfig;
|
|
202
254
|
/**
|
|
@@ -220,11 +272,11 @@ type MultiJobQueueHandle<E, TJobs extends Record<string, AnyJobConfig<E>>> = {
|
|
|
220
272
|
/** Sends one message to a named job. */
|
|
221
273
|
send(ctx: {
|
|
222
274
|
env: QueueEnv<E>;
|
|
223
|
-
}, data: z.infer<TJobs[K]['
|
|
275
|
+
}, data: z.infer<TJobs[K]['args']>, options?: SendOptions): Promise<void>;
|
|
224
276
|
/** Sends many messages to a named job. */
|
|
225
277
|
sendBatch(ctx: {
|
|
226
278
|
env: QueueEnv<E>;
|
|
227
|
-
}, messages: SendBatchEntry<z.infer<TJobs[K]['
|
|
279
|
+
}, messages: SendBatchEntry<z.infer<TJobs[K]['args']>>[], options?: SendBatchOptions): Promise<void>;
|
|
228
280
|
};
|
|
229
281
|
};
|
|
230
282
|
/**
|
|
@@ -240,7 +292,9 @@ interface WorkerConfig<E> {
|
|
|
240
292
|
* Worker module shape returned by `defineWorker`.
|
|
241
293
|
*/
|
|
242
294
|
interface WorkerEntrypoint<E> {
|
|
295
|
+
/** Cloudflare module `fetch` entrypoint. */
|
|
243
296
|
fetch(request: Request, env: E, executionCtx: ExecutionContext): Promise<Response>;
|
|
297
|
+
/** Optional Cloudflare module `scheduled` entrypoint. */
|
|
244
298
|
scheduled?: (event: ScheduledEvent, env: E, executionCtx: ExecutionContext) => Promise<void>;
|
|
245
299
|
}
|
|
246
300
|
/**
|
|
@@ -248,7 +302,7 @@ interface WorkerEntrypoint<E> {
|
|
|
248
302
|
*/
|
|
249
303
|
type DefineWorker<E> = (config: WorkerConfig<E>) => WorkerEntrypoint<E>;
|
|
250
304
|
/**
|
|
251
|
-
* Defines queue
|
|
305
|
+
* Defines a single queue contract and returns a typed producer handle.
|
|
252
306
|
*/
|
|
253
307
|
interface DefineQueue<E> {
|
|
254
308
|
/**
|
|
@@ -256,19 +310,30 @@ interface DefineQueue<E> {
|
|
|
256
310
|
*
|
|
257
311
|
* @example
|
|
258
312
|
* defineQueue({
|
|
259
|
-
*
|
|
260
|
-
*
|
|
313
|
+
* args: z.object({ id: z.string() }),
|
|
314
|
+
* handler: async (ctx, args) => {}
|
|
261
315
|
* })
|
|
316
|
+
*
|
|
317
|
+
* @remarks
|
|
318
|
+
* Use exactly one of `handler` or `batchHandler` for worker-consumer queues.
|
|
262
319
|
*/
|
|
263
320
|
<TSchema extends z.ZodTypeAny>(config: QueueConfig<E, TSchema>): QueueHandle<E, z.infer<TSchema>>;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Defines a multi-job queue contract and returns job-keyed producer handles.
|
|
324
|
+
*/
|
|
325
|
+
interface DefineQueues<E> {
|
|
264
326
|
/**
|
|
265
327
|
* Declare a multi-job queue where each top-level key is a job definition.
|
|
266
328
|
*
|
|
267
329
|
* @example
|
|
268
|
-
*
|
|
269
|
-
* email: {
|
|
270
|
-
* audit: {
|
|
330
|
+
* defineQueues({
|
|
331
|
+
* email: { args: z.object({ to: z.string() }), handler: async () => {} },
|
|
332
|
+
* audit: { args: z.object({ id: z.string() }), handler: async () => {} }
|
|
271
333
|
* })
|
|
334
|
+
*
|
|
335
|
+
* @remarks
|
|
336
|
+
* Shared queue settings (for example `retry`, `retryDelay`, `batch`) stay at the top level.
|
|
272
337
|
*/
|
|
273
338
|
<const TConfig extends Record<string, unknown>>(config: MultiJobQueueConfig<E, TConfig>): MultiJobQueueHandle<E, ExtractJobMap<E, TConfig>>;
|
|
274
339
|
}
|
|
@@ -276,8 +341,10 @@ interface DefineQueue<E> {
|
|
|
276
341
|
* SDK helpers returned by `createSDK`.
|
|
277
342
|
*/
|
|
278
343
|
interface BetterCfSDK<E> {
|
|
279
|
-
/**
|
|
344
|
+
/** Single-queue helper. */
|
|
280
345
|
defineQueue: DefineQueue<E>;
|
|
346
|
+
/** Multi-job helper where each top-level key is a job declaration. */
|
|
347
|
+
defineQueues: DefineQueues<E>;
|
|
281
348
|
/** Worker declaration helper that maps to Cloudflare module handlers. */
|
|
282
349
|
defineWorker: DefineWorker<E>;
|
|
283
350
|
}
|
|
@@ -306,4 +373,4 @@ type QueueDefinition<E> = {
|
|
|
306
373
|
shared: QueueCommonConfig;
|
|
307
374
|
};
|
|
308
375
|
|
|
309
|
-
export type { BetterCfAutoEnv as B, ConsumerBatchEntry as C, DefineQueue as D, JobConfig as J, MultiJobQueueConfig as M, PullConsumerConfig as P, QueueDefinition as Q, SendBatchEntry as S, WorkerConfig as W, BetterCfSDK as a, BatchContext as b, BetterCfGeneratedBindings as c, ContentType as d,
|
|
376
|
+
export type { BetterCfAutoEnv as B, ConsumerBatchEntry as C, DefineQueue as D, JobConfig as J, MultiJobQueueConfig as M, PullConsumerConfig as P, QueueDefinition as Q, SendBatchEntry as S, WorkerConfig as W, BetterCfSDK as a, BatchContext as b, BetterCfGeneratedBindings as c, ContentType as d, DefineQueues as e, DefineWorker as f, Duration as g, MultiJobQueueHandle as h, QueueCommonConfig as i, QueueConfig as j, QueueContext as k, QueueEnv as l, QueueHandle as m, SendBatchOptions as n, SendOptions as o, WorkerContext as p, WorkerEntrypoint as q };
|