alchemy 0.12.6 → 0.12.8
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/lib/cloudflare/ai-gateway.d.ts.map +1 -1
- package/lib/cloudflare/ai-gateway.js +1 -2
- package/lib/cloudflare/ai-gateway.js.map +1 -1
- package/lib/cloudflare/bindings.d.ts +2 -1
- package/lib/cloudflare/bindings.d.ts.map +1 -1
- package/lib/cloudflare/bound.d.ts +2 -1
- package/lib/cloudflare/bound.d.ts.map +1 -1
- package/lib/cloudflare/bucket.d.ts +8 -2
- package/lib/cloudflare/bucket.d.ts.map +1 -1
- package/lib/cloudflare/bucket.js +1 -1
- package/lib/cloudflare/bucket.js.map +1 -1
- package/lib/cloudflare/d1-database.d.ts +8 -2
- package/lib/cloudflare/d1-database.d.ts.map +1 -1
- package/lib/cloudflare/d1-database.js +2 -2
- package/lib/cloudflare/d1-database.js.map +1 -1
- package/lib/cloudflare/event-source.d.ts +26 -0
- package/lib/cloudflare/event-source.d.ts.map +1 -0
- package/lib/cloudflare/event-source.js +9 -0
- package/lib/cloudflare/event-source.js.map +1 -0
- package/lib/cloudflare/hyperdrive.d.ts +216 -0
- package/lib/cloudflare/hyperdrive.d.ts.map +1 -0
- package/lib/cloudflare/hyperdrive.js +184 -0
- package/lib/cloudflare/hyperdrive.js.map +1 -0
- package/lib/cloudflare/index.d.ts +2 -0
- package/lib/cloudflare/index.d.ts.map +1 -1
- package/lib/cloudflare/index.js +2 -0
- package/lib/cloudflare/index.js.map +1 -1
- package/lib/cloudflare/queue-consumer.d.ts +162 -0
- package/lib/cloudflare/queue-consumer.d.ts.map +1 -0
- package/lib/cloudflare/queue-consumer.js +197 -0
- package/lib/cloudflare/queue-consumer.js.map +1 -0
- package/lib/cloudflare/queue.d.ts +15 -3
- package/lib/cloudflare/queue.d.ts.map +1 -1
- package/lib/cloudflare/queue.js +8 -2
- package/lib/cloudflare/queue.js.map +1 -1
- package/lib/cloudflare/website.d.ts.map +1 -1
- package/lib/cloudflare/website.js +8 -10
- package/lib/cloudflare/website.js.map +1 -1
- package/lib/cloudflare/worker.d.ts +13 -2
- package/lib/cloudflare/worker.d.ts.map +1 -1
- package/lib/cloudflare/worker.js +75 -3
- package/lib/cloudflare/worker.js.map +1 -1
- package/lib/cloudflare/wrangler.json.d.ts +13 -3
- package/lib/cloudflare/wrangler.json.d.ts.map +1 -1
- package/lib/cloudflare/wrangler.json.js +27 -5
- package/lib/cloudflare/wrangler.json.js.map +1 -1
- package/lib/neon/api-error.d.ts +31 -0
- package/lib/neon/api-error.d.ts.map +1 -0
- package/lib/neon/api-error.js +73 -0
- package/lib/neon/api-error.js.map +1 -0
- package/lib/neon/api.d.ts +70 -0
- package/lib/neon/api.d.ts.map +1 -0
- package/lib/neon/api.js +128 -0
- package/lib/neon/api.js.map +1 -0
- package/lib/neon/index.d.ts +4 -0
- package/lib/neon/index.d.ts.map +1 -0
- package/lib/neon/index.js +4 -0
- package/lib/neon/index.js.map +1 -0
- package/lib/neon/project.d.ts +345 -0
- package/lib/neon/project.d.ts.map +1 -0
- package/lib/neon/project.js +305 -0
- package/lib/neon/project.js.map +1 -0
- package/package.json +2 -1
- package/src/cloudflare/ai-gateway.ts +0 -1
- package/src/cloudflare/bindings.ts +4 -2
- package/src/cloudflare/bound.ts +20 -17
- package/src/cloudflare/bucket.ts +9 -2
- package/src/cloudflare/d1-database.ts +10 -3
- package/src/cloudflare/event-source.ts +33 -0
- package/src/cloudflare/hyperdrive.ts +375 -0
- package/src/cloudflare/index.ts +2 -0
- package/src/cloudflare/queue-consumer.ts +433 -0
- package/src/cloudflare/queue.ts +83 -63
- package/src/cloudflare/website.ts +9 -13
- package/src/cloudflare/worker.ts +109 -5
- package/src/cloudflare/wrangler.json.ts +52 -8
- package/src/neon/api-error.ts +81 -0
- package/src/neon/api.ts +178 -0
- package/src/neon/index.ts +3 -0
- package/src/neon/project.ts +870 -0
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
import type { Context } from "../context.js";
|
|
2
|
+
import { Resource } from "../resource.js";
|
|
3
|
+
import { CloudflareApiError, handleApiError } from "./api-error.js";
|
|
4
|
+
import {
|
|
5
|
+
CloudflareApi,
|
|
6
|
+
createCloudflareApi,
|
|
7
|
+
type CloudflareApiOptions,
|
|
8
|
+
} from "./api.js";
|
|
9
|
+
import type { Queue } from "./queue.js";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Settings for configuring a Queue Consumer
|
|
13
|
+
*/
|
|
14
|
+
export interface QueueConsumerSettings {
|
|
15
|
+
/**
|
|
16
|
+
* Number of messages to deliver in a batch
|
|
17
|
+
* @default 10
|
|
18
|
+
*/
|
|
19
|
+
batchSize?: number;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Maximum number of concurrent consumer worker invocations
|
|
23
|
+
* @default 2
|
|
24
|
+
*/
|
|
25
|
+
maxConcurrency?: number;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Maximum number of retries for each message
|
|
29
|
+
* @default 3
|
|
30
|
+
*/
|
|
31
|
+
maxRetries?: number;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Maximum time in milliseconds to wait for batch to fill
|
|
35
|
+
* @default 500
|
|
36
|
+
*/
|
|
37
|
+
maxWaitTimeMs?: number;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Time in seconds to delay retry after a failure
|
|
41
|
+
* @default 30
|
|
42
|
+
*/
|
|
43
|
+
retryDelay?: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Properties for creating or updating a Queue Consumer
|
|
48
|
+
*/
|
|
49
|
+
export interface QueueConsumerProps extends CloudflareApiOptions {
|
|
50
|
+
/**
|
|
51
|
+
* The queue to consume
|
|
52
|
+
* Either queue or queueId must be provided
|
|
53
|
+
*/
|
|
54
|
+
queue?: Queue;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* The queue ID to consume (alternative to providing a queue)
|
|
58
|
+
* Either queue or queueId must be provided
|
|
59
|
+
*/
|
|
60
|
+
queueId?: string;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Name of the worker script that will consume the queue
|
|
64
|
+
*/
|
|
65
|
+
scriptName: string;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Settings for the consumer
|
|
69
|
+
*/
|
|
70
|
+
settings?: QueueConsumerSettings;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Whether to delete the consumer.
|
|
74
|
+
* If set to false, the consumer will remain but the resource will be removed from state
|
|
75
|
+
* @default true
|
|
76
|
+
*/
|
|
77
|
+
delete?: boolean;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Output returned after Queue Consumer creation/update
|
|
82
|
+
*/
|
|
83
|
+
export interface QueueConsumer
|
|
84
|
+
extends Resource<"cloudflare::QueueConsumer">,
|
|
85
|
+
QueueConsumerProps {
|
|
86
|
+
/**
|
|
87
|
+
* Unique ID for the consumer
|
|
88
|
+
*/
|
|
89
|
+
id: string;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Type identifier for Cloudflare Queue Consumer
|
|
93
|
+
*/
|
|
94
|
+
type: "worker";
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* ID of the queue being consumed
|
|
98
|
+
*/
|
|
99
|
+
queueId: string;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Time when the consumer was created
|
|
103
|
+
*/
|
|
104
|
+
createdOn?: string;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Creates a consumer for a Cloudflare Queue that processes messages using a Worker.
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* // Create a queue consumer with default settings
|
|
112
|
+
* const queue = await Queue("notifications", {
|
|
113
|
+
* name: "notifications"
|
|
114
|
+
* });
|
|
115
|
+
*
|
|
116
|
+
* const consumer = await QueueConsumer("notification-processor", {
|
|
117
|
+
* queue,
|
|
118
|
+
* scriptName: "notification-worker"
|
|
119
|
+
* });
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* // Create a consumer with custom settings
|
|
123
|
+
* const batchConsumer = await QueueConsumer("batch-processor", {
|
|
124
|
+
* queue,
|
|
125
|
+
* scriptName: "batch-worker",
|
|
126
|
+
* settings: {
|
|
127
|
+
* batchSize: 50, // Process 50 messages at once
|
|
128
|
+
* maxConcurrency: 10, // Allow 10 concurrent invocations
|
|
129
|
+
* maxRetries: 5, // Retry failed messages up to 5 times
|
|
130
|
+
* maxWaitTimeMs: 2000, // Wait up to 2 seconds to fill a batch
|
|
131
|
+
* retryDelay: 60 // Wait 60 seconds before retrying failed messages
|
|
132
|
+
* }
|
|
133
|
+
* });
|
|
134
|
+
*
|
|
135
|
+
* @see https://developers.cloudflare.com/queues/platform/consumers/
|
|
136
|
+
*/
|
|
137
|
+
export const QueueConsumer = Resource(
|
|
138
|
+
"cloudflare::QueueConsumer",
|
|
139
|
+
async function (
|
|
140
|
+
this: Context<QueueConsumer>,
|
|
141
|
+
id: string,
|
|
142
|
+
props: QueueConsumerProps
|
|
143
|
+
): Promise<QueueConsumer> {
|
|
144
|
+
const api = await createCloudflareApi(props);
|
|
145
|
+
|
|
146
|
+
// Get queueId from either props.queue or props.queueId
|
|
147
|
+
const queueId = props.queue?.id || props.queueId;
|
|
148
|
+
|
|
149
|
+
if (!queueId) {
|
|
150
|
+
throw new Error("Either queue or queueId must be provided");
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (this.phase === "delete") {
|
|
154
|
+
console.log(`Deleting Queue Consumer for queue ${queueId}`);
|
|
155
|
+
if (props.delete !== false && this.output?.id) {
|
|
156
|
+
// Delete the consumer
|
|
157
|
+
await deleteQueueConsumer(api, queueId, this.output.id);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Return void (a deleted consumer has no content)
|
|
161
|
+
return this.destroy();
|
|
162
|
+
} else {
|
|
163
|
+
let consumerData: CloudflareQueueConsumerResponse;
|
|
164
|
+
|
|
165
|
+
if (this.phase === "create") {
|
|
166
|
+
console.log(`Creating Queue Consumer for queue ${queueId}`);
|
|
167
|
+
consumerData = await createQueueConsumer(api, queueId, props);
|
|
168
|
+
} else if (this.output?.id) {
|
|
169
|
+
console.log(`Updating Queue Consumer ${this.output.id}`);
|
|
170
|
+
consumerData = await updateQueueConsumer(
|
|
171
|
+
api,
|
|
172
|
+
queueId,
|
|
173
|
+
this.output.id,
|
|
174
|
+
props
|
|
175
|
+
);
|
|
176
|
+
} else {
|
|
177
|
+
// If no ID exists, fall back to creating a new consumer
|
|
178
|
+
console.log(
|
|
179
|
+
`No existing Consumer ID found, creating new Queue Consumer for queue ${queueId}`
|
|
180
|
+
);
|
|
181
|
+
consumerData = await createQueueConsumer(api, queueId, props);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return this({
|
|
185
|
+
id: consumerData.result.consumer_id,
|
|
186
|
+
queueId,
|
|
187
|
+
queue: props.queue,
|
|
188
|
+
type: "worker",
|
|
189
|
+
scriptName: props.scriptName,
|
|
190
|
+
settings: consumerData.result.settings
|
|
191
|
+
? {
|
|
192
|
+
batchSize: consumerData.result.settings.batch_size,
|
|
193
|
+
maxConcurrency: consumerData.result.settings.max_concurrency,
|
|
194
|
+
maxRetries: consumerData.result.settings.max_retries,
|
|
195
|
+
maxWaitTimeMs: consumerData.result.settings.max_wait_time_ms,
|
|
196
|
+
retryDelay: consumerData.result.settings.retry_delay,
|
|
197
|
+
}
|
|
198
|
+
: undefined,
|
|
199
|
+
createdOn: consumerData.result.created_on,
|
|
200
|
+
accountId: api.accountId,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Response from Cloudflare API for Queue Consumer operations
|
|
208
|
+
*/
|
|
209
|
+
interface CloudflareQueueConsumerResponse {
|
|
210
|
+
result: {
|
|
211
|
+
consumer_id: string;
|
|
212
|
+
script_name: string;
|
|
213
|
+
settings?: {
|
|
214
|
+
batch_size?: number;
|
|
215
|
+
max_concurrency?: number;
|
|
216
|
+
max_retries?: number;
|
|
217
|
+
max_wait_time_ms?: number;
|
|
218
|
+
retry_delay?: number;
|
|
219
|
+
};
|
|
220
|
+
type: "worker";
|
|
221
|
+
queue_id?: string;
|
|
222
|
+
created_on?: string;
|
|
223
|
+
};
|
|
224
|
+
success: boolean;
|
|
225
|
+
errors: Array<{ code: number; message: string }>;
|
|
226
|
+
messages: string[];
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Create a new Queue Consumer
|
|
231
|
+
*/
|
|
232
|
+
export async function createQueueConsumer(
|
|
233
|
+
api: CloudflareApi,
|
|
234
|
+
queueId: string,
|
|
235
|
+
props: QueueConsumerProps
|
|
236
|
+
): Promise<CloudflareQueueConsumerResponse> {
|
|
237
|
+
// Prepare the create payload
|
|
238
|
+
const createPayload: any = {
|
|
239
|
+
script_name: props.scriptName,
|
|
240
|
+
type: "worker",
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
// Add settings if provided
|
|
244
|
+
if (props.settings) {
|
|
245
|
+
createPayload.settings = {};
|
|
246
|
+
|
|
247
|
+
if (props.settings.batchSize !== undefined) {
|
|
248
|
+
createPayload.settings.batch_size = props.settings.batchSize;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (props.settings.maxConcurrency !== undefined) {
|
|
252
|
+
createPayload.settings.max_concurrency = props.settings.maxConcurrency;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (props.settings.maxRetries !== undefined) {
|
|
256
|
+
createPayload.settings.max_retries = props.settings.maxRetries;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if (props.settings.maxWaitTimeMs !== undefined) {
|
|
260
|
+
createPayload.settings.max_wait_time_ms = props.settings.maxWaitTimeMs;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (props.settings.retryDelay !== undefined) {
|
|
264
|
+
createPayload.settings.retry_delay = props.settings.retryDelay;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const createResponse = await api.post(
|
|
269
|
+
`/accounts/${api.accountId}/queues/${queueId}/consumers`,
|
|
270
|
+
createPayload
|
|
271
|
+
);
|
|
272
|
+
|
|
273
|
+
if (!createResponse.ok) {
|
|
274
|
+
return await handleApiError(
|
|
275
|
+
createResponse,
|
|
276
|
+
"creating",
|
|
277
|
+
"Queue Consumer",
|
|
278
|
+
`for queue ${queueId}`
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return (await createResponse.json()) as CloudflareQueueConsumerResponse;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Delete a Queue Consumer
|
|
287
|
+
*/
|
|
288
|
+
export async function deleteQueueConsumer(
|
|
289
|
+
api: CloudflareApi,
|
|
290
|
+
queueId: string,
|
|
291
|
+
consumerId: string
|
|
292
|
+
): Promise<void> {
|
|
293
|
+
const deleteResponse = await api.delete(
|
|
294
|
+
`/accounts/${api.accountId}/queues/${queueId}/consumers/${consumerId}`
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
if (!deleteResponse.ok && deleteResponse.status !== 404) {
|
|
298
|
+
const errorData: any = await deleteResponse.json().catch(() => ({
|
|
299
|
+
errors: [{ message: deleteResponse.statusText }],
|
|
300
|
+
}));
|
|
301
|
+
throw new CloudflareApiError(
|
|
302
|
+
`Error deleting Queue Consumer '${consumerId}': ${errorData.errors?.[0]?.message || deleteResponse.statusText}`,
|
|
303
|
+
deleteResponse
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Update a Queue Consumer
|
|
310
|
+
*/
|
|
311
|
+
async function updateQueueConsumer(
|
|
312
|
+
api: CloudflareApi,
|
|
313
|
+
queueId: string,
|
|
314
|
+
consumerId: string,
|
|
315
|
+
props: QueueConsumerProps
|
|
316
|
+
): Promise<CloudflareQueueConsumerResponse> {
|
|
317
|
+
// Prepare the update payload
|
|
318
|
+
const updatePayload: any = {
|
|
319
|
+
script_name: props.scriptName,
|
|
320
|
+
type: "worker",
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
// Add settings if provided
|
|
324
|
+
if (props.settings) {
|
|
325
|
+
updatePayload.settings = {};
|
|
326
|
+
|
|
327
|
+
if (props.settings.batchSize !== undefined) {
|
|
328
|
+
updatePayload.settings.batch_size = props.settings.batchSize;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
if (props.settings.maxConcurrency !== undefined) {
|
|
332
|
+
updatePayload.settings.max_concurrency = props.settings.maxConcurrency;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (props.settings.maxRetries !== undefined) {
|
|
336
|
+
updatePayload.settings.max_retries = props.settings.maxRetries;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (props.settings.maxWaitTimeMs !== undefined) {
|
|
340
|
+
updatePayload.settings.max_wait_time_ms = props.settings.maxWaitTimeMs;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
if (props.settings.retryDelay !== undefined) {
|
|
344
|
+
updatePayload.settings.retry_delay = props.settings.retryDelay;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Use PUT to update the consumer
|
|
349
|
+
const updateResponse = await api.put(
|
|
350
|
+
`/accounts/${api.accountId}/queues/${queueId}/consumers/${consumerId}`,
|
|
351
|
+
updatePayload
|
|
352
|
+
);
|
|
353
|
+
|
|
354
|
+
if (!updateResponse.ok) {
|
|
355
|
+
return await handleApiError(
|
|
356
|
+
updateResponse,
|
|
357
|
+
"updating",
|
|
358
|
+
"Queue Consumer",
|
|
359
|
+
consumerId
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
return (await updateResponse.json()) as CloudflareQueueConsumerResponse;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
export interface ListQueueConsumersResponse {
|
|
367
|
+
id: string;
|
|
368
|
+
scriptName: string;
|
|
369
|
+
queueId: string;
|
|
370
|
+
queueName: string;
|
|
371
|
+
createdOn: string;
|
|
372
|
+
settings?: QueueConsumerSettings;
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* List all consumers for a queue
|
|
376
|
+
*/
|
|
377
|
+
export async function listQueueConsumers(
|
|
378
|
+
api: CloudflareApi,
|
|
379
|
+
queueId: string
|
|
380
|
+
): Promise<ListQueueConsumersResponse[]> {
|
|
381
|
+
const response = await api.get(
|
|
382
|
+
`/accounts/${api.accountId}/queues/${queueId}/consumers`
|
|
383
|
+
);
|
|
384
|
+
|
|
385
|
+
if (!response.ok) {
|
|
386
|
+
throw new CloudflareApiError(
|
|
387
|
+
`Failed to list queue consumers: ${response.statusText}`,
|
|
388
|
+
response
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const data = (await response.json()) as {
|
|
393
|
+
success: boolean;
|
|
394
|
+
errors?: Array<{ code: number; message: string }>;
|
|
395
|
+
result?: Array<{
|
|
396
|
+
consumer_id: string;
|
|
397
|
+
script: string;
|
|
398
|
+
queue_id: string;
|
|
399
|
+
queue_name: string;
|
|
400
|
+
created_on: string;
|
|
401
|
+
settings?: {
|
|
402
|
+
batch_size?: number;
|
|
403
|
+
max_concurrency?: number;
|
|
404
|
+
max_retries?: number;
|
|
405
|
+
max_wait_time_ms?: number;
|
|
406
|
+
retry_delay?: number;
|
|
407
|
+
};
|
|
408
|
+
}>;
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
if (!data.success) {
|
|
412
|
+
const errorMessage = data.errors?.[0]?.message || "Unknown error";
|
|
413
|
+
throw new Error(`Failed to list queue consumers: ${errorMessage}`);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// Transform API response
|
|
417
|
+
return (data.result || []).map((consumer) => ({
|
|
418
|
+
id: consumer.consumer_id,
|
|
419
|
+
scriptName: consumer.script,
|
|
420
|
+
queueId: consumer.queue_id,
|
|
421
|
+
queueName: consumer.queue_name,
|
|
422
|
+
createdOn: consumer.created_on,
|
|
423
|
+
settings: consumer.settings
|
|
424
|
+
? {
|
|
425
|
+
batchSize: consumer.settings.batch_size,
|
|
426
|
+
maxConcurrency: consumer.settings.max_concurrency,
|
|
427
|
+
maxRetries: consumer.settings.max_retries,
|
|
428
|
+
maxWaitTimeMs: consumer.settings.max_wait_time_ms,
|
|
429
|
+
retryDelay: consumer.settings.retry_delay,
|
|
430
|
+
}
|
|
431
|
+
: undefined,
|
|
432
|
+
}));
|
|
433
|
+
}
|
package/src/cloudflare/queue.ts
CHANGED
|
@@ -38,8 +38,10 @@ export interface QueueProps extends CloudflareApiOptions {
|
|
|
38
38
|
* Name of the queue
|
|
39
39
|
* Required during creation
|
|
40
40
|
* Cannot be changed after creation
|
|
41
|
+
*
|
|
42
|
+
* @default id
|
|
41
43
|
*/
|
|
42
|
-
name
|
|
44
|
+
name?: string;
|
|
43
45
|
|
|
44
46
|
/**
|
|
45
47
|
* Settings for the queue
|
|
@@ -56,10 +58,16 @@ export interface QueueProps extends CloudflareApiOptions {
|
|
|
56
58
|
delete?: boolean;
|
|
57
59
|
}
|
|
58
60
|
|
|
61
|
+
export function isQueue(eventSource: any): eventSource is Queue {
|
|
62
|
+
return "Kind" in eventSource && eventSource.Kind === "cloudflare::Queue";
|
|
63
|
+
}
|
|
64
|
+
|
|
59
65
|
/**
|
|
60
66
|
* Output returned after Cloudflare Queue creation/update
|
|
61
67
|
*/
|
|
62
|
-
export interface Queue
|
|
68
|
+
export interface Queue<Body = unknown>
|
|
69
|
+
extends Resource<"cloudflare::Queue">,
|
|
70
|
+
QueueProps {
|
|
63
71
|
/**
|
|
64
72
|
* Type identifier for Cloudflare Queue
|
|
65
73
|
*/
|
|
@@ -70,6 +78,11 @@ export interface Queue extends Resource<"cloudflare::Queue">, QueueProps {
|
|
|
70
78
|
*/
|
|
71
79
|
id: string;
|
|
72
80
|
|
|
81
|
+
/**
|
|
82
|
+
* The name of the queue
|
|
83
|
+
*/
|
|
84
|
+
name: string;
|
|
85
|
+
|
|
73
86
|
/**
|
|
74
87
|
* Time when the queue was created
|
|
75
88
|
*/
|
|
@@ -79,6 +92,13 @@ export interface Queue extends Resource<"cloudflare::Queue">, QueueProps {
|
|
|
79
92
|
* Modified timestamp
|
|
80
93
|
*/
|
|
81
94
|
modifiedOn: string;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Phantom property to allow type inference
|
|
98
|
+
*/
|
|
99
|
+
Body: Body;
|
|
100
|
+
|
|
101
|
+
Batch: MessageBatch<Body>;
|
|
82
102
|
}
|
|
83
103
|
|
|
84
104
|
interface CloudflareQueueResponse {
|
|
@@ -131,74 +151,74 @@ interface CloudflareQueueResponse {
|
|
|
131
151
|
*
|
|
132
152
|
* @see https://developers.cloudflare.com/queues/
|
|
133
153
|
*/
|
|
134
|
-
export const Queue = Resource(
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
if (
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
await deleteQueue(api, this.output?.id);
|
|
149
|
-
}
|
|
154
|
+
export const Queue = Resource("cloudflare::Queue", async function <
|
|
155
|
+
T = unknown,
|
|
156
|
+
>(this: Context<Queue<T>>, id: string, props: QueueProps = {}): Promise<
|
|
157
|
+
Queue<T>
|
|
158
|
+
> {
|
|
159
|
+
const api = await createCloudflareApi(props);
|
|
160
|
+
const queueName = props.name ?? id;
|
|
161
|
+
|
|
162
|
+
if (this.phase === "delete") {
|
|
163
|
+
console.log("Deleting Cloudflare Queue:", queueName);
|
|
164
|
+
if (props.delete !== false) {
|
|
165
|
+
// Delete Queue
|
|
166
|
+
await deleteQueue(api, this.output?.id);
|
|
167
|
+
}
|
|
150
168
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
169
|
+
// Return void (a deleted queue has no content)
|
|
170
|
+
return this.destroy();
|
|
171
|
+
} else {
|
|
172
|
+
let queueData: CloudflareQueueResponse;
|
|
155
173
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// Update the queue with new settings
|
|
172
|
-
queueData = await updateQueue(api, this.output.id, props);
|
|
173
|
-
} else {
|
|
174
|
-
// If no ID exists, fall back to creating a new queue
|
|
175
|
-
console.log(
|
|
176
|
-
"No existing Queue ID found, creating new Cloudflare Queue:",
|
|
177
|
-
queueName
|
|
174
|
+
if (this.phase === "create") {
|
|
175
|
+
console.log("Creating Cloudflare Queue:", queueName);
|
|
176
|
+
queueData = await createQueue(api, queueName, props);
|
|
177
|
+
} else {
|
|
178
|
+
// Update operation
|
|
179
|
+
if (this.output?.id) {
|
|
180
|
+
console.log("Updating Cloudflare Queue:", queueName);
|
|
181
|
+
|
|
182
|
+
// Check if name is being changed, which is not allowed
|
|
183
|
+
if (props.name !== this.output.name) {
|
|
184
|
+
throw new Error(
|
|
185
|
+
"Cannot update Queue name after creation. Queue name is immutable."
|
|
178
186
|
);
|
|
179
|
-
queueData = await createQueue(api, queueName, props);
|
|
180
187
|
}
|
|
181
|
-
}
|
|
182
188
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
}
|
|
194
|
-
: undefined,
|
|
195
|
-
createdOn: queueData.result.created_on || new Date().toISOString(),
|
|
196
|
-
modifiedOn: queueData.result.modified_on || new Date().toISOString(),
|
|
197
|
-
accountId: api.accountId,
|
|
198
|
-
});
|
|
189
|
+
// Update the queue with new settings
|
|
190
|
+
queueData = await updateQueue(api, this.output.id, props);
|
|
191
|
+
} else {
|
|
192
|
+
// If no ID exists, fall back to creating a new queue
|
|
193
|
+
console.log(
|
|
194
|
+
"No existing Queue ID found, creating new Cloudflare Queue:",
|
|
195
|
+
queueName
|
|
196
|
+
);
|
|
197
|
+
queueData = await createQueue(api, queueName, props);
|
|
198
|
+
}
|
|
199
199
|
}
|
|
200
|
+
|
|
201
|
+
return this({
|
|
202
|
+
type: "queue",
|
|
203
|
+
id: queueData.result.queue_id || "",
|
|
204
|
+
name: queueName,
|
|
205
|
+
settings: queueData.result.settings
|
|
206
|
+
? {
|
|
207
|
+
deliveryDelay: queueData.result.settings.delivery_delay,
|
|
208
|
+
deliveryPaused: queueData.result.settings.delivery_paused,
|
|
209
|
+
messageRetentionPeriod:
|
|
210
|
+
queueData.result.settings.message_retention_period,
|
|
211
|
+
}
|
|
212
|
+
: undefined,
|
|
213
|
+
createdOn: queueData.result.created_on || new Date().toISOString(),
|
|
214
|
+
modifiedOn: queueData.result.modified_on || new Date().toISOString(),
|
|
215
|
+
accountId: api.accountId,
|
|
216
|
+
// phantom properties
|
|
217
|
+
Body: undefined as T,
|
|
218
|
+
Batch: undefined! as MessageBatch<T>,
|
|
219
|
+
});
|
|
200
220
|
}
|
|
201
|
-
);
|
|
221
|
+
});
|
|
202
222
|
|
|
203
223
|
/**
|
|
204
224
|
* Create a new Cloudflare Queue
|
|
@@ -93,15 +93,6 @@ export async function Website<B extends Bindings>(
|
|
|
93
93
|
command: props.command,
|
|
94
94
|
});
|
|
95
95
|
|
|
96
|
-
const dist =
|
|
97
|
-
typeof props.assets === "string"
|
|
98
|
-
? props.assets
|
|
99
|
-
: (props.assets?.dist ?? "dist");
|
|
100
|
-
|
|
101
|
-
const staticAssets = await Assets("assets", {
|
|
102
|
-
path: dist,
|
|
103
|
-
});
|
|
104
|
-
|
|
105
96
|
const worker = await Worker("worker", {
|
|
106
97
|
...props,
|
|
107
98
|
name: props.name ?? id,
|
|
@@ -116,15 +107,20 @@ export async function Website<B extends Bindings>(
|
|
|
116
107
|
? undefined
|
|
117
108
|
: `
|
|
118
109
|
export default {
|
|
119
|
-
async fetch(request, env) {
|
|
120
|
-
|
|
121
|
-
},
|
|
110
|
+
async fetch(request, env) {
|
|
111
|
+
return new Response("Not Found", { status: 404 });
|
|
112
|
+
},
|
|
122
113
|
};`,
|
|
123
114
|
url: true,
|
|
124
115
|
adopt: true,
|
|
125
116
|
bindings: {
|
|
126
117
|
...props.bindings,
|
|
127
|
-
ASSETS:
|
|
118
|
+
ASSETS: await Assets("assets", {
|
|
119
|
+
path:
|
|
120
|
+
typeof props.assets === "string"
|
|
121
|
+
? props.assets
|
|
122
|
+
: (props.assets?.dist ?? "dist"),
|
|
123
|
+
}),
|
|
128
124
|
},
|
|
129
125
|
});
|
|
130
126
|
|