alchemy 0.7.2 → 0.8.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/lib/aws/table.js +22 -5
- package/lib/cloudflare/r2-rest-state-store.js +20 -32
- package/lib/cloudflare/worker.js +4 -0
- package/lib/esbuild/bundle.d.ts +11 -14
- package/lib/esbuild/bundle.js +6 -3
- package/lib/web/vitepress/process-front-matter-files.js +1 -1
- package/package.json +1 -1
- package/src/aws/table.ts +34 -16
- package/src/cloudflare/r2-rest-state-store.ts +23 -45
- package/src/cloudflare/worker.ts +4 -0
- package/src/esbuild/bundle.ts +9 -6
- package/src/web/vitepress/process-front-matter-files.ts +1 -1
package/lib/aws/table.js
CHANGED
|
@@ -45,9 +45,9 @@ export const Table = Resource("dynamo::Table", async function (id, props) {
|
|
|
45
45
|
await ignore(ResourceNotFoundException.name, () => client.send(new DeleteTableCommand({
|
|
46
46
|
TableName: props.tableName,
|
|
47
47
|
})));
|
|
48
|
-
},
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
}, isRetryableError, 10, // Max attempts
|
|
49
|
+
200 // Initial delay in ms
|
|
50
|
+
);
|
|
51
51
|
// Wait for table to be deleted
|
|
52
52
|
let tableDeleted = false;
|
|
53
53
|
let retryCount = 0;
|
|
@@ -143,8 +143,9 @@ export const Table = Resource("dynamo::Table", async function (id, props) {
|
|
|
143
143
|
throw error;
|
|
144
144
|
}
|
|
145
145
|
}
|
|
146
|
-
},
|
|
147
|
-
200
|
|
146
|
+
}, isRetryableError, 10, // Max attempts
|
|
147
|
+
200 // Initial delay in ms
|
|
148
|
+
);
|
|
148
149
|
// Wait for table to be active with timeout
|
|
149
150
|
let tableActive = false;
|
|
150
151
|
let tableDescription;
|
|
@@ -185,3 +186,19 @@ export const Table = Resource("dynamo::Table", async function (id, props) {
|
|
|
185
186
|
});
|
|
186
187
|
}
|
|
187
188
|
});
|
|
189
|
+
const retryableErrors = [
|
|
190
|
+
"ResourceInUseException",
|
|
191
|
+
"ResourceNotFoundException",
|
|
192
|
+
"InternalServerError",
|
|
193
|
+
"ThrottlingException",
|
|
194
|
+
"ProvisionedThroughputExceededException",
|
|
195
|
+
"LimitExceededException",
|
|
196
|
+
"RequestLimitExceeded",
|
|
197
|
+
];
|
|
198
|
+
function isRetryableError(error) {
|
|
199
|
+
return (error instanceof ResourceInUseException ||
|
|
200
|
+
error instanceof InternalServerError ||
|
|
201
|
+
retryableErrors.includes(error?.name) ||
|
|
202
|
+
retryableErrors.includes(error?.code) ||
|
|
203
|
+
error?.$metadata?.httpStatusCode === 500);
|
|
204
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { deserialize, serialize } from "../serde";
|
|
2
2
|
import { withExponentialBackoff } from "../util/retry";
|
|
3
3
|
import { createCloudflareApi, } from "./api";
|
|
4
|
+
import { CloudflareApiError, handleApiError } from "./api-error";
|
|
4
5
|
/**
|
|
5
6
|
* State store implementation using Cloudflare R2 API
|
|
6
7
|
* Uses R2 for immediate consistency compared to KV's eventual consistency
|
|
@@ -69,17 +70,12 @@ export class R2RestStateStore {
|
|
|
69
70
|
const response = await withExponentialBackoff(async () => {
|
|
70
71
|
const response = await this.api.get(listPath);
|
|
71
72
|
if (!response.ok) {
|
|
72
|
-
|
|
73
|
-
errors: [{ message: response.statusText }],
|
|
74
|
-
}));
|
|
75
|
-
throw new Error(`Error listing R2 objects: ${errorData.errors?.[0]?.message || response.statusText}`);
|
|
73
|
+
await handleApiError(response, "list", "bucket", this.bucketName);
|
|
76
74
|
}
|
|
77
75
|
return response;
|
|
78
76
|
},
|
|
79
77
|
// Retry on transient errors
|
|
80
|
-
|
|
81
|
-
error.message?.includes("503") ||
|
|
82
|
-
error.message?.includes("timeout"), 5, // 5 retry attempts
|
|
78
|
+
isRetryableError, 5, // 5 retry attempts
|
|
83
79
|
1000 // Start with 1 second delay
|
|
84
80
|
);
|
|
85
81
|
const data = (await response.json());
|
|
@@ -117,21 +113,13 @@ export class R2RestStateStore {
|
|
|
117
113
|
try {
|
|
118
114
|
const response = await withExponentialBackoff(async () => {
|
|
119
115
|
const response = await this.api.get(`/accounts/${this.api.accountId}/r2/buckets/${this.bucketName}/objects/${this.getObjectKey(key)}`);
|
|
120
|
-
if (!response.ok) {
|
|
121
|
-
|
|
122
|
-
return response;
|
|
123
|
-
}
|
|
124
|
-
const errorData = await response.json().catch(() => ({
|
|
125
|
-
errors: [{ message: response.statusText }],
|
|
126
|
-
}));
|
|
127
|
-
throw new Error(`Error getting R2 object: ${errorData.errors?.[0]?.message || response.statusText}`);
|
|
116
|
+
if (!response.ok && response.status !== 404) {
|
|
117
|
+
await handleApiError(response, "get", "object", key);
|
|
128
118
|
}
|
|
129
119
|
return response;
|
|
130
120
|
},
|
|
131
121
|
// Retry on transient errors
|
|
132
|
-
|
|
133
|
-
error.message?.includes("503") ||
|
|
134
|
-
error.message?.includes("timeout"), 5, // 5 retry attempts
|
|
122
|
+
isRetryableError, 5, // 5 retry attempts
|
|
135
123
|
1000 // Start with 1 second delay
|
|
136
124
|
);
|
|
137
125
|
if (response.status === 404) {
|
|
@@ -202,15 +190,12 @@ export class R2RestStateStore {
|
|
|
202
190
|
},
|
|
203
191
|
});
|
|
204
192
|
if (!response.ok) {
|
|
205
|
-
|
|
206
|
-
errors: [{ message: response.statusText }],
|
|
207
|
-
}));
|
|
208
|
-
throw new Error(`Error writing to R2: ${errorData.errors?.[0]?.message || response.statusText}`);
|
|
193
|
+
await handleApiError(response, "put", "object", objectKey);
|
|
209
194
|
}
|
|
210
195
|
return response;
|
|
211
196
|
},
|
|
212
197
|
// Retry on transient errors
|
|
213
|
-
|
|
198
|
+
isRetryableError, 5, // 5 retry attempts
|
|
214
199
|
1000 // Start with 1 second delay
|
|
215
200
|
);
|
|
216
201
|
}
|
|
@@ -224,17 +209,10 @@ export class R2RestStateStore {
|
|
|
224
209
|
await withExponentialBackoff(async () => {
|
|
225
210
|
const response = await this.api.delete(`/accounts/${this.api.accountId}/r2/buckets/${this.bucketName}/objects/${this.getObjectKey(key)}`);
|
|
226
211
|
if (!response.ok && response.status !== 404) {
|
|
227
|
-
|
|
228
|
-
errors: [{ message: response.statusText }],
|
|
229
|
-
}));
|
|
230
|
-
throw new Error(`Error deleting from R2: ${errorData.errors?.[0]?.message || response.statusText}`);
|
|
212
|
+
await handleApiError(response, "delete", "object", key);
|
|
231
213
|
}
|
|
232
214
|
return response;
|
|
233
|
-
},
|
|
234
|
-
// Retry on transient errors
|
|
235
|
-
(error) => error.message?.includes("502") ||
|
|
236
|
-
error.message?.includes("503") ||
|
|
237
|
-
error.message?.includes("timeout"), 5, // 5 retry attempts
|
|
215
|
+
}, isRetryableError, 5, // 5 retry attempts
|
|
238
216
|
1000 // Start with 1 second delay
|
|
239
217
|
);
|
|
240
218
|
}
|
|
@@ -275,3 +253,13 @@ export class R2RestStateStore {
|
|
|
275
253
|
}
|
|
276
254
|
}
|
|
277
255
|
}
|
|
256
|
+
function isRetryableError(error) {
|
|
257
|
+
if (error instanceof CloudflareApiError) {
|
|
258
|
+
return (error.status === 500 ||
|
|
259
|
+
error.status === 502 ||
|
|
260
|
+
error.status === 503 ||
|
|
261
|
+
error.message.includes("timeout") ||
|
|
262
|
+
error.message.includes("internal error"));
|
|
263
|
+
}
|
|
264
|
+
return false;
|
|
265
|
+
}
|
package/lib/cloudflare/worker.js
CHANGED
|
@@ -431,6 +431,10 @@ async function bundleWorkerScript(props) {
|
|
|
431
431
|
minify: true,
|
|
432
432
|
options: {
|
|
433
433
|
keepNames: true, // Important for Durable Object classes
|
|
434
|
+
loader: {
|
|
435
|
+
".sql": "text",
|
|
436
|
+
".json": "json",
|
|
437
|
+
},
|
|
434
438
|
},
|
|
435
439
|
};
|
|
436
440
|
// Merge with user-provided options
|
package/lib/esbuild/bundle.d.ts
CHANGED
|
@@ -94,14 +94,21 @@ export interface Bundle extends Resource<"esbuild::Bundle"> {
|
|
|
94
94
|
*/
|
|
95
95
|
export declare const Bundle: (((this: any, id: string, props?: {}) => never) & (new (_: never) => never)) | ((this: Context<Bundle>, id: string, props: BundleProps) => Promise<Bundle>);
|
|
96
96
|
export declare function bundle(props: BundleProps): Promise<esbuild.BuildResult<{
|
|
97
|
-
|
|
97
|
+
entryPoints: string[];
|
|
98
|
+
outfile: string;
|
|
99
|
+
bundle: true;
|
|
100
|
+
format: "iife" | "cjs" | "esm" | undefined;
|
|
101
|
+
target: string | string[] | undefined;
|
|
102
|
+
minify: boolean | undefined;
|
|
103
|
+
sourcemap: boolean | "inline" | "external" | "both" | undefined;
|
|
104
|
+
external: string[];
|
|
105
|
+
platform: "browser" | "node" | "neutral" | undefined;
|
|
106
|
+
metafile: true;
|
|
107
|
+
write: true;
|
|
98
108
|
splitting?: boolean;
|
|
99
109
|
preserveSymlinks?: boolean;
|
|
100
|
-
outfile: string;
|
|
101
|
-
metafile: boolean;
|
|
102
110
|
outdir?: string;
|
|
103
111
|
outbase?: string;
|
|
104
|
-
external: string[];
|
|
105
112
|
packages?: "bundle" | "external";
|
|
106
113
|
alias?: Record<string, string>;
|
|
107
114
|
loader?: {
|
|
@@ -110,7 +117,6 @@ export declare function bundle(props: BundleProps): Promise<esbuild.BuildResult<
|
|
|
110
117
|
resolveExtensions?: string[];
|
|
111
118
|
mainFields?: string[];
|
|
112
119
|
conditions?: string[];
|
|
113
|
-
write: boolean;
|
|
114
120
|
allowOverwrite?: boolean;
|
|
115
121
|
tsconfig?: string;
|
|
116
122
|
outExtension?: {
|
|
@@ -127,30 +133,21 @@ export declare function bundle(props: BundleProps): Promise<esbuild.BuildResult<
|
|
|
127
133
|
footer?: {
|
|
128
134
|
[type: string]: string;
|
|
129
135
|
};
|
|
130
|
-
entryPoints: string[] | Record<string, string> | {
|
|
131
|
-
in: string;
|
|
132
|
-
out: string;
|
|
133
|
-
}[];
|
|
134
136
|
stdin?: esbuild.StdinOptions;
|
|
135
137
|
plugins?: esbuild.Plugin[];
|
|
136
138
|
absWorkingDir?: string;
|
|
137
139
|
nodePaths?: string[];
|
|
138
|
-
sourcemap: boolean | "linked" | "inline" | "external" | "both";
|
|
139
140
|
legalComments?: "none" | "inline" | "eof" | "linked" | "external";
|
|
140
141
|
sourceRoot?: string;
|
|
141
142
|
sourcesContent?: boolean;
|
|
142
|
-
format: esbuild.Format;
|
|
143
143
|
globalName?: string;
|
|
144
|
-
target: string | string[];
|
|
145
144
|
supported?: Record<string, boolean>;
|
|
146
|
-
platform: esbuild.Platform;
|
|
147
145
|
mangleProps?: RegExp;
|
|
148
146
|
reserveProps?: RegExp;
|
|
149
147
|
mangleQuoted?: boolean;
|
|
150
148
|
mangleCache?: Record<string, string | false>;
|
|
151
149
|
drop?: esbuild.Drop[];
|
|
152
150
|
dropLabels?: string[];
|
|
153
|
-
minify: boolean;
|
|
154
151
|
minifyWhitespace?: boolean;
|
|
155
152
|
minifyIdentifiers?: boolean;
|
|
156
153
|
minifySyntax?: boolean;
|
package/lib/esbuild/bundle.js
CHANGED
|
@@ -47,8 +47,8 @@ export const Bundle = Resource("esbuild::Bundle", {
|
|
|
47
47
|
});
|
|
48
48
|
export async function bundle(props) {
|
|
49
49
|
const outputPath = getOutputPath(props);
|
|
50
|
-
// Build the bundle
|
|
51
50
|
return await esbuild.build({
|
|
51
|
+
...props.options,
|
|
52
52
|
entryPoints: [props.entryPoint],
|
|
53
53
|
outfile: outputPath,
|
|
54
54
|
bundle: true,
|
|
@@ -56,11 +56,14 @@ export async function bundle(props) {
|
|
|
56
56
|
target: props.target,
|
|
57
57
|
minify: props.minify,
|
|
58
58
|
sourcemap: props.sourcemap,
|
|
59
|
-
external:
|
|
59
|
+
external: [
|
|
60
|
+
"node:async_hooks",
|
|
61
|
+
...(props.external ?? []),
|
|
62
|
+
...(props.options?.external ?? []),
|
|
63
|
+
],
|
|
60
64
|
platform: props.platform,
|
|
61
65
|
metafile: true,
|
|
62
66
|
write: true,
|
|
63
|
-
...props.options,
|
|
64
67
|
});
|
|
65
68
|
}
|
|
66
69
|
function getOutputPath(props) {
|
|
@@ -35,7 +35,7 @@ export async function processFrontmatterFiles(directoryPath, linkPrefix) {
|
|
|
35
35
|
const frontmatter = frontmatterMatch[1];
|
|
36
36
|
const orderMatch = frontmatter.match(/order:\s*(\d+)/);
|
|
37
37
|
if (orderMatch) {
|
|
38
|
-
order =
|
|
38
|
+
order = parseFloat(orderMatch[1]);
|
|
39
39
|
}
|
|
40
40
|
const titleMatch = frontmatter.match(/title:\s*(.+)/);
|
|
41
41
|
if (titleMatch) {
|
package/package.json
CHANGED
package/src/aws/table.ts
CHANGED
|
@@ -143,7 +143,7 @@ export const Table = Resource(
|
|
|
143
143
|
async function (
|
|
144
144
|
this: Context<Table>,
|
|
145
145
|
id: string,
|
|
146
|
-
props: TableProps
|
|
146
|
+
props: TableProps
|
|
147
147
|
): Promise<Table> {
|
|
148
148
|
const client = new DynamoDBClient({});
|
|
149
149
|
|
|
@@ -154,15 +154,13 @@ export const Table = Resource(
|
|
|
154
154
|
client.send(
|
|
155
155
|
new DeleteTableCommand({
|
|
156
156
|
TableName: props.tableName,
|
|
157
|
-
})
|
|
158
|
-
)
|
|
157
|
+
})
|
|
158
|
+
)
|
|
159
159
|
);
|
|
160
160
|
},
|
|
161
|
-
|
|
162
|
-
error instanceof ResourceInUseException ||
|
|
163
|
-
error instanceof InternalServerError,
|
|
161
|
+
isRetryableError,
|
|
164
162
|
10, // Max attempts
|
|
165
|
-
200
|
|
163
|
+
200 // Initial delay in ms
|
|
166
164
|
);
|
|
167
165
|
|
|
168
166
|
// Wait for table to be deleted
|
|
@@ -175,7 +173,7 @@ export const Table = Resource(
|
|
|
175
173
|
await client.send(
|
|
176
174
|
new DescribeTableCommand({
|
|
177
175
|
TableName: props.tableName,
|
|
178
|
-
})
|
|
176
|
+
})
|
|
179
177
|
);
|
|
180
178
|
// If we get here, table still exists
|
|
181
179
|
retryCount++;
|
|
@@ -193,7 +191,7 @@ export const Table = Resource(
|
|
|
193
191
|
|
|
194
192
|
if (!tableDeleted) {
|
|
195
193
|
throw new Error(
|
|
196
|
-
`Timed out waiting for table ${props.tableName} to be deleted
|
|
194
|
+
`Timed out waiting for table ${props.tableName} to be deleted`
|
|
197
195
|
);
|
|
198
196
|
}
|
|
199
197
|
|
|
@@ -233,7 +231,7 @@ export const Table = Resource(
|
|
|
233
231
|
const describeResponse = await client.send(
|
|
234
232
|
new DescribeTableCommand({
|
|
235
233
|
TableName: props.tableName,
|
|
236
|
-
})
|
|
234
|
+
})
|
|
237
235
|
);
|
|
238
236
|
|
|
239
237
|
// If table exists and is ACTIVE, no need to create it
|
|
@@ -267,16 +265,16 @@ export const Table = Resource(
|
|
|
267
265
|
Value,
|
|
268
266
|
}))
|
|
269
267
|
: undefined,
|
|
270
|
-
})
|
|
268
|
+
})
|
|
271
269
|
);
|
|
272
270
|
} else {
|
|
273
271
|
throw error;
|
|
274
272
|
}
|
|
275
273
|
}
|
|
276
274
|
},
|
|
277
|
-
|
|
275
|
+
isRetryableError,
|
|
278
276
|
10, // Max attempts
|
|
279
|
-
200
|
|
277
|
+
200 // Initial delay in ms
|
|
280
278
|
);
|
|
281
279
|
|
|
282
280
|
// Wait for table to be active with timeout
|
|
@@ -290,7 +288,7 @@ export const Table = Resource(
|
|
|
290
288
|
const response = await client.send(
|
|
291
289
|
new DescribeTableCommand({
|
|
292
290
|
TableName: props.tableName,
|
|
293
|
-
})
|
|
291
|
+
})
|
|
294
292
|
);
|
|
295
293
|
|
|
296
294
|
tableActive = response.Table?.TableStatus === "ACTIVE";
|
|
@@ -313,7 +311,7 @@ export const Table = Resource(
|
|
|
313
311
|
|
|
314
312
|
if (!tableActive) {
|
|
315
313
|
throw new Error(
|
|
316
|
-
`Timed out waiting for table ${props.tableName} to become active
|
|
314
|
+
`Timed out waiting for table ${props.tableName} to become active`
|
|
317
315
|
);
|
|
318
316
|
}
|
|
319
317
|
|
|
@@ -324,5 +322,25 @@ export const Table = Resource(
|
|
|
324
322
|
tableId: tableDescription!.TableId!,
|
|
325
323
|
});
|
|
326
324
|
}
|
|
327
|
-
}
|
|
325
|
+
}
|
|
328
326
|
);
|
|
327
|
+
|
|
328
|
+
const retryableErrors = [
|
|
329
|
+
"ResourceInUseException",
|
|
330
|
+
"ResourceNotFoundException",
|
|
331
|
+
"InternalServerError",
|
|
332
|
+
"ThrottlingException",
|
|
333
|
+
"ProvisionedThroughputExceededException",
|
|
334
|
+
"LimitExceededException",
|
|
335
|
+
"RequestLimitExceeded",
|
|
336
|
+
];
|
|
337
|
+
|
|
338
|
+
function isRetryableError(error: any) {
|
|
339
|
+
return (
|
|
340
|
+
error instanceof ResourceInUseException ||
|
|
341
|
+
error instanceof InternalServerError ||
|
|
342
|
+
retryableErrors.includes(error?.name) ||
|
|
343
|
+
retryableErrors.includes(error?.code) ||
|
|
344
|
+
error?.$metadata?.httpStatusCode === 500
|
|
345
|
+
);
|
|
346
|
+
}
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
type CloudflareApiOptions,
|
|
8
8
|
createCloudflareApi,
|
|
9
9
|
} from "./api";
|
|
10
|
+
import { CloudflareApiError, handleApiError } from "./api-error";
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Options for CloudflareR2StateStore
|
|
@@ -106,21 +107,13 @@ export class R2RestStateStore implements StateStore {
|
|
|
106
107
|
const response = await this.api.get(listPath);
|
|
107
108
|
|
|
108
109
|
if (!response.ok) {
|
|
109
|
-
|
|
110
|
-
errors: [{ message: response.statusText }],
|
|
111
|
-
}));
|
|
112
|
-
throw new Error(
|
|
113
|
-
`Error listing R2 objects: ${errorData.errors?.[0]?.message || response.statusText}`
|
|
114
|
-
);
|
|
110
|
+
await handleApiError(response, "list", "bucket", this.bucketName);
|
|
115
111
|
}
|
|
116
112
|
|
|
117
113
|
return response;
|
|
118
114
|
},
|
|
119
115
|
// Retry on transient errors
|
|
120
|
-
|
|
121
|
-
error.message?.includes("502") ||
|
|
122
|
-
error.message?.includes("503") ||
|
|
123
|
-
error.message?.includes("timeout"),
|
|
116
|
+
isRetryableError,
|
|
124
117
|
5, // 5 retry attempts
|
|
125
118
|
1000 // Start with 1 second delay
|
|
126
119
|
);
|
|
@@ -173,26 +166,14 @@ export class R2RestStateStore implements StateStore {
|
|
|
173
166
|
`/accounts/${this.api.accountId}/r2/buckets/${this.bucketName}/objects/${this.getObjectKey(key)}`
|
|
174
167
|
);
|
|
175
168
|
|
|
176
|
-
if (!response.ok) {
|
|
177
|
-
|
|
178
|
-
return response;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
const errorData: any = await response.json().catch(() => ({
|
|
182
|
-
errors: [{ message: response.statusText }],
|
|
183
|
-
}));
|
|
184
|
-
throw new Error(
|
|
185
|
-
`Error getting R2 object: ${errorData.errors?.[0]?.message || response.statusText}`
|
|
186
|
-
);
|
|
169
|
+
if (!response.ok && response.status !== 404) {
|
|
170
|
+
await handleApiError(response, "get", "object", key);
|
|
187
171
|
}
|
|
188
172
|
|
|
189
173
|
return response;
|
|
190
174
|
},
|
|
191
175
|
// Retry on transient errors
|
|
192
|
-
|
|
193
|
-
error.message?.includes("502") ||
|
|
194
|
-
error.message?.includes("503") ||
|
|
195
|
-
error.message?.includes("timeout"),
|
|
176
|
+
isRetryableError,
|
|
196
177
|
5, // 5 retry attempts
|
|
197
178
|
1000 // Start with 1 second delay
|
|
198
179
|
);
|
|
@@ -280,19 +261,12 @@ export class R2RestStateStore implements StateStore {
|
|
|
280
261
|
);
|
|
281
262
|
|
|
282
263
|
if (!response.ok) {
|
|
283
|
-
|
|
284
|
-
errors: [{ message: response.statusText }],
|
|
285
|
-
}));
|
|
286
|
-
throw new Error(
|
|
287
|
-
`Error writing to R2: ${errorData.errors?.[0]?.message || response.statusText}`
|
|
288
|
-
);
|
|
264
|
+
await handleApiError(response, "put", "object", objectKey);
|
|
289
265
|
}
|
|
290
|
-
|
|
291
266
|
return response;
|
|
292
267
|
},
|
|
293
268
|
// Retry on transient errors
|
|
294
|
-
|
|
295
|
-
error.message?.includes("503") || error.message?.includes("timeout"),
|
|
269
|
+
isRetryableError,
|
|
296
270
|
5, // 5 retry attempts
|
|
297
271
|
1000 // Start with 1 second delay
|
|
298
272
|
);
|
|
@@ -313,21 +287,12 @@ export class R2RestStateStore implements StateStore {
|
|
|
313
287
|
);
|
|
314
288
|
|
|
315
289
|
if (!response.ok && response.status !== 404) {
|
|
316
|
-
|
|
317
|
-
errors: [{ message: response.statusText }],
|
|
318
|
-
}));
|
|
319
|
-
throw new Error(
|
|
320
|
-
`Error deleting from R2: ${errorData.errors?.[0]?.message || response.statusText}`
|
|
321
|
-
);
|
|
290
|
+
await handleApiError(response, "delete", "object", key);
|
|
322
291
|
}
|
|
323
292
|
|
|
324
293
|
return response;
|
|
325
294
|
},
|
|
326
|
-
|
|
327
|
-
(error) =>
|
|
328
|
-
error.message?.includes("502") ||
|
|
329
|
-
error.message?.includes("503") ||
|
|
330
|
-
error.message?.includes("timeout"),
|
|
295
|
+
isRetryableError,
|
|
331
296
|
5, // 5 retry attempts
|
|
332
297
|
1000 // Start with 1 second delay
|
|
333
298
|
);
|
|
@@ -373,3 +338,16 @@ export class R2RestStateStore implements StateStore {
|
|
|
373
338
|
}
|
|
374
339
|
}
|
|
375
340
|
}
|
|
341
|
+
|
|
342
|
+
function isRetryableError(error: any): boolean {
|
|
343
|
+
if (error instanceof CloudflareApiError) {
|
|
344
|
+
return (
|
|
345
|
+
error.status === 500 ||
|
|
346
|
+
error.status === 502 ||
|
|
347
|
+
error.status === 503 ||
|
|
348
|
+
error.message.includes("timeout") ||
|
|
349
|
+
error.message.includes("internal error")
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
return false;
|
|
353
|
+
}
|
package/src/cloudflare/worker.ts
CHANGED
|
@@ -720,6 +720,10 @@ async function bundleWorkerScript<B extends Bindings>(props: WorkerProps) {
|
|
|
720
720
|
minify: true,
|
|
721
721
|
options: {
|
|
722
722
|
keepNames: true, // Important for Durable Object classes
|
|
723
|
+
loader: {
|
|
724
|
+
".sql": "text",
|
|
725
|
+
".json": "json",
|
|
726
|
+
},
|
|
723
727
|
},
|
|
724
728
|
};
|
|
725
729
|
|
package/src/esbuild/bundle.ts
CHANGED
|
@@ -116,7 +116,7 @@ export const Bundle = Resource(
|
|
|
116
116
|
async function (
|
|
117
117
|
this: Context<Bundle>,
|
|
118
118
|
id: string,
|
|
119
|
-
props: BundleProps
|
|
119
|
+
props: BundleProps
|
|
120
120
|
): Promise<Bundle> {
|
|
121
121
|
// Determine output path
|
|
122
122
|
const outputPath = getOutputPath(props);
|
|
@@ -145,13 +145,13 @@ export const Bundle = Resource(
|
|
|
145
145
|
path: outputPath,
|
|
146
146
|
hash,
|
|
147
147
|
});
|
|
148
|
-
}
|
|
148
|
+
}
|
|
149
149
|
);
|
|
150
150
|
|
|
151
151
|
export async function bundle(props: BundleProps) {
|
|
152
152
|
const outputPath = getOutputPath(props);
|
|
153
|
-
// Build the bundle
|
|
154
153
|
return await esbuild.build({
|
|
154
|
+
...props.options,
|
|
155
155
|
entryPoints: [props.entryPoint],
|
|
156
156
|
outfile: outputPath,
|
|
157
157
|
bundle: true,
|
|
@@ -159,11 +159,14 @@ export async function bundle(props: BundleProps) {
|
|
|
159
159
|
target: props.target,
|
|
160
160
|
minify: props.minify,
|
|
161
161
|
sourcemap: props.sourcemap,
|
|
162
|
-
external:
|
|
162
|
+
external: [
|
|
163
|
+
"node:async_hooks",
|
|
164
|
+
...(props.external ?? []),
|
|
165
|
+
...(props.options?.external ?? []),
|
|
166
|
+
],
|
|
163
167
|
platform: props.platform,
|
|
164
168
|
metafile: true,
|
|
165
169
|
write: true,
|
|
166
|
-
...props.options,
|
|
167
170
|
});
|
|
168
171
|
}
|
|
169
172
|
|
|
@@ -172,7 +175,7 @@ function getOutputPath(props: BundleProps) {
|
|
|
172
175
|
props.outfile ||
|
|
173
176
|
path.join(
|
|
174
177
|
props.outdir || "dist",
|
|
175
|
-
path.basename(props.entryPoint, path.extname(props.entryPoint)) + ".js"
|
|
178
|
+
path.basename(props.entryPoint, path.extname(props.entryPoint)) + ".js"
|
|
176
179
|
)
|
|
177
180
|
);
|
|
178
181
|
}
|
|
@@ -58,7 +58,7 @@ export async function processFrontmatterFiles(
|
|
|
58
58
|
const frontmatter = frontmatterMatch[1];
|
|
59
59
|
const orderMatch = frontmatter.match(/order:\s*(\d+)/);
|
|
60
60
|
if (orderMatch) {
|
|
61
|
-
order =
|
|
61
|
+
order = parseFloat(orderMatch[1]);
|
|
62
62
|
}
|
|
63
63
|
const titleMatch = frontmatter.match(/title:\s*(.+)/);
|
|
64
64
|
if (titleMatch) {
|