alchemy 0.63.1 → 0.65.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/bin/alchemy.js +7664 -5857
- package/bin/commands/init.ts +130 -9
- package/bin/constants.ts +4 -0
- package/bin/services/cdp-manager/cdp-proxy.ts +69 -0
- package/bin/services/cdp-manager/server.ts +173 -0
- package/bin/services/execute-alchemy.ts +83 -4
- package/bin/types.ts +1 -0
- package/lib/alchemy.d.ts +4 -0
- package/lib/alchemy.d.ts.map +1 -1
- package/lib/alchemy.js +10 -4
- package/lib/alchemy.js.map +1 -1
- package/lib/apply.d.ts +3 -0
- package/lib/apply.d.ts.map +1 -1
- package/lib/apply.js +11 -1
- package/lib/apply.js.map +1 -1
- package/lib/cloudflare/bindings.d.ts +3 -1
- package/lib/cloudflare/bindings.d.ts.map +1 -1
- package/lib/cloudflare/bucket.d.ts +2 -1
- package/lib/cloudflare/bucket.d.ts.map +1 -1
- package/lib/cloudflare/bucket.js.map +1 -1
- package/lib/cloudflare/bundle/cloudflare-internal.d.ts +6 -0
- package/lib/cloudflare/bundle/cloudflare-internal.d.ts.map +1 -0
- package/lib/cloudflare/bundle/cloudflare-internal.js +39 -0
- package/lib/cloudflare/bundle/cloudflare-internal.js.map +1 -0
- package/lib/cloudflare/bundle/nodejs-builtin-modules.d.ts +2 -0
- package/lib/cloudflare/bundle/nodejs-builtin-modules.d.ts.map +1 -0
- package/lib/cloudflare/bundle/nodejs-builtin-modules.js +9 -0
- package/lib/cloudflare/bundle/nodejs-builtin-modules.js.map +1 -0
- package/lib/cloudflare/bundle/plugin-als-external.d.ts +6 -0
- package/lib/cloudflare/bundle/plugin-als-external.d.ts.map +1 -0
- package/lib/cloudflare/bundle/plugin-als-external.js +12 -0
- package/lib/cloudflare/bundle/plugin-als-external.js.map +1 -0
- package/lib/cloudflare/bundle/plugin-hybrid-node-compat.d.ts +4 -1
- package/lib/cloudflare/bundle/plugin-hybrid-node-compat.d.ts.map +1 -1
- package/lib/cloudflare/bundle/plugin-hybrid-node-compat.js +23 -23
- package/lib/cloudflare/bundle/plugin-hybrid-node-compat.js.map +1 -1
- package/lib/cloudflare/bundle/plugin-node-compat.d.ts +11 -0
- package/lib/cloudflare/bundle/plugin-node-compat.d.ts.map +1 -0
- package/lib/cloudflare/bundle/plugin-node-compat.js +93 -0
- package/lib/cloudflare/bundle/plugin-node-compat.js.map +1 -0
- package/lib/cloudflare/bundle/plugin-wasm.d.ts.map +1 -1
- package/lib/cloudflare/bundle/plugin-wasm.js +20 -11
- package/lib/cloudflare/bundle/plugin-wasm.js.map +1 -1
- package/lib/cloudflare/compatibility-date.gen.d.ts +1 -1
- package/lib/cloudflare/compatibility-date.gen.js +1 -1
- package/lib/cloudflare/d1-local-migrations.js.map +1 -1
- package/lib/cloudflare/durable-object-namespace.d.ts +1 -0
- package/lib/cloudflare/durable-object-namespace.d.ts.map +1 -1
- package/lib/cloudflare/durable-object-namespace.js.map +1 -1
- package/lib/cloudflare/hyperdrive.d.ts +7 -2
- package/lib/cloudflare/hyperdrive.d.ts.map +1 -1
- package/lib/cloudflare/hyperdrive.js +39 -57
- package/lib/cloudflare/hyperdrive.js.map +1 -1
- package/lib/cloudflare/index.d.ts +1 -0
- package/lib/cloudflare/index.d.ts.map +1 -1
- package/lib/cloudflare/index.js +1 -0
- package/lib/cloudflare/index.js.map +1 -1
- package/lib/cloudflare/next.d.ts +13 -0
- package/lib/cloudflare/next.d.ts.map +1 -0
- package/lib/cloudflare/next.js +91 -0
- package/lib/cloudflare/next.js.map +1 -0
- package/lib/cloudflare/website.d.ts.map +1 -1
- package/lib/cloudflare/website.js +80 -82
- package/lib/cloudflare/website.js.map +1 -1
- package/lib/cloudflare/worker-assets.d.ts +3 -3
- package/lib/cloudflare/worker-assets.d.ts.map +1 -1
- package/lib/cloudflare/worker-assets.js +22 -47
- package/lib/cloudflare/worker-assets.js.map +1 -1
- package/lib/cloudflare/worker-bundle.d.ts +6 -0
- package/lib/cloudflare/worker-bundle.d.ts.map +1 -1
- package/lib/cloudflare/worker-bundle.js +34 -10
- package/lib/cloudflare/worker-bundle.js.map +1 -1
- package/lib/cloudflare/worker-metadata.d.ts.map +1 -1
- package/lib/cloudflare/worker-metadata.js +1 -0
- package/lib/cloudflare/worker-metadata.js.map +1 -1
- package/lib/cloudflare/worker.d.ts.map +1 -1
- package/lib/cloudflare/worker.js +24 -6
- package/lib/cloudflare/worker.js.map +1 -1
- package/lib/cloudflare/wrangler.json.d.ts +4 -6
- package/lib/cloudflare/wrangler.json.d.ts.map +1 -1
- package/lib/cloudflare/wrangler.json.js +20 -15
- package/lib/cloudflare/wrangler.json.js.map +1 -1
- package/lib/context.d.ts +3 -1
- package/lib/context.d.ts.map +1 -1
- package/lib/context.js +2 -2
- package/lib/context.js.map +1 -1
- package/lib/destroy.d.ts +8 -0
- package/lib/destroy.d.ts.map +1 -1
- package/lib/destroy.js +20 -4
- package/lib/destroy.js.map +1 -1
- package/lib/planetscale/api/client.gen.d.ts +1750 -0
- package/lib/planetscale/api/client.gen.d.ts.map +1 -0
- package/lib/planetscale/api/client.gen.js +2401 -0
- package/lib/planetscale/api/client.gen.js.map +1 -0
- package/lib/planetscale/api/index.d.ts +3 -0
- package/lib/planetscale/api/index.d.ts.map +1 -0
- package/lib/planetscale/api/index.js +4 -0
- package/lib/planetscale/api/index.js.map +1 -0
- package/lib/planetscale/api/types.gen.d.ts +12156 -0
- package/lib/planetscale/api/types.gen.d.ts.map +1 -0
- package/lib/planetscale/api/types.gen.js +2 -0
- package/lib/planetscale/api/types.gen.js.map +1 -0
- package/lib/planetscale/branch.d.ts +5 -8
- package/lib/planetscale/branch.d.ts.map +1 -1
- package/lib/planetscale/branch.js +122 -97
- package/lib/planetscale/branch.js.map +1 -1
- package/lib/planetscale/database.d.ts +24 -11
- package/lib/planetscale/database.d.ts.map +1 -1
- package/lib/planetscale/database.js +163 -118
- package/lib/planetscale/database.js.map +1 -1
- package/lib/planetscale/index.d.ts +2 -1
- package/lib/planetscale/index.d.ts.map +1 -1
- package/lib/planetscale/index.js +2 -1
- package/lib/planetscale/index.js.map +1 -1
- package/lib/planetscale/password.d.ts +7 -8
- package/lib/planetscale/password.d.ts.map +1 -1
- package/lib/planetscale/password.js +74 -57
- package/lib/planetscale/password.js.map +1 -1
- package/lib/planetscale/role.d.ts +126 -0
- package/lib/planetscale/role.d.ts.map +1 -0
- package/lib/planetscale/role.js +144 -0
- package/lib/planetscale/role.js.map +1 -0
- package/lib/planetscale/utils.d.ts +23 -7
- package/lib/planetscale/utils.d.ts.map +1 -1
- package/lib/planetscale/utils.js +169 -75
- package/lib/planetscale/utils.js.map +1 -1
- package/lib/scope.d.ts +5 -1
- package/lib/scope.d.ts.map +1 -1
- package/lib/scope.js +11 -3
- package/lib/scope.js.map +1 -1
- package/lib/secret.d.ts +0 -3
- package/lib/secret.d.ts.map +1 -1
- package/lib/secret.js +0 -2
- package/lib/secret.js.map +1 -1
- package/lib/state/cloudflare-state-store.js +3 -3
- package/lib/state/cloudflare-state-store.js.map +1 -1
- package/lib/test/bun.d.ts +2 -2
- package/lib/test/bun.d.ts.map +1 -1
- package/lib/test/vitest.d.ts +2 -2
- package/lib/test/vitest.d.ts.map +1 -1
- package/lib/test/vitest.js +4 -4
- package/lib/test/vitest.js.map +1 -1
- package/lib/util/content-type.js +2 -2
- package/lib/util/content-type.js.map +1 -1
- package/lib/util/dedent.d.ts +3 -14
- package/lib/util/dedent.d.ts.map +1 -1
- package/lib/util/dedent.js +33 -45
- package/lib/util/dedent.js.map +1 -1
- package/lib/util/memoize.d.ts.map +1 -1
- package/lib/util/memoize.js +11 -1
- package/lib/util/memoize.js.map +1 -1
- package/package.json +8 -3
- package/src/alchemy.ts +14 -6
- package/src/apply.ts +13 -1
- package/src/cloudflare/bindings.ts +3 -1
- package/src/cloudflare/bucket.ts +3 -1
- package/src/cloudflare/bundle/cloudflare-internal.ts +42 -0
- package/src/cloudflare/bundle/nodejs-builtin-modules.ts +14 -0
- package/src/cloudflare/bundle/plugin-als-external.ts +13 -0
- package/src/cloudflare/bundle/plugin-hybrid-node-compat.ts +29 -28
- package/src/cloudflare/bundle/plugin-node-compat.ts +114 -0
- package/src/cloudflare/bundle/plugin-wasm.ts +34 -14
- package/src/cloudflare/compatibility-date.gen.ts +1 -1
- package/src/cloudflare/d1-local-migrations.ts +2 -2
- package/src/cloudflare/durable-object-namespace.ts +1 -0
- package/src/cloudflare/hyperdrive.ts +136 -95
- package/src/cloudflare/index.ts +1 -0
- package/src/cloudflare/next.ts +123 -0
- package/src/cloudflare/website.ts +88 -89
- package/src/cloudflare/worker-assets.ts +43 -105
- package/src/cloudflare/worker-bundle.ts +46 -9
- package/src/cloudflare/worker-metadata.ts +2 -0
- package/src/cloudflare/worker.ts +35 -7
- package/src/cloudflare/wrangler.json.ts +114 -113
- package/src/context.ts +5 -3
- package/src/destroy.ts +26 -8
- package/src/planetscale/api/client.gen.ts +2882 -0
- package/src/planetscale/api/index.ts +4 -0
- package/src/planetscale/api/types.gen.ts +13041 -0
- package/src/planetscale/branch.ts +170 -162
- package/src/planetscale/database.ts +263 -243
- package/src/planetscale/index.ts +2 -1
- package/src/planetscale/password.ts +89 -86
- package/src/planetscale/role.ts +278 -0
- package/src/planetscale/utils.ts +289 -128
- package/src/scope.ts +12 -3
- package/src/secret.ts +0 -4
- package/src/state/cloudflare-state-store.ts +4 -4
- package/src/test/bun.ts +2 -2
- package/src/test/vitest.ts +6 -6
- package/src/util/content-type.ts +2 -2
- package/src/util/dedent.ts +34 -50
- package/src/util/memoize.ts +13 -1
- package/templates/astro/alchemy.run.ts +1 -3
- package/templates/hono/alchemy.run.ts +0 -1
- package/templates/nextjs/README.md +85 -0
- package/templates/nextjs/_env +1 -0
- package/templates/nextjs/_env.example +1 -0
- package/templates/nextjs/_gitignore +46 -0
- package/templates/nextjs/alchemy.run.ts +16 -0
- package/templates/nextjs/eslint.config.mjs +16 -0
- package/templates/nextjs/next-env.d.ts +5 -0
- package/templates/nextjs/next.config.ts +10 -0
- package/templates/nextjs/open-next.config.ts +5 -0
- package/templates/nextjs/package.json +31 -0
- package/templates/nextjs/src/app/api/hello/route.ts +19 -0
- package/templates/nextjs/src/app/favicon.ico +0 -0
- package/templates/nextjs/src/app/globals.css +72 -0
- package/templates/nextjs/src/app/layout.tsx +19 -0
- package/templates/nextjs/src/app/page.tsx +55 -0
- package/templates/nextjs/tsconfig.json +33 -0
- package/templates/nextjs/types/env.d.ts +14 -0
- package/templates/nuxt/alchemy.run.ts +1 -3
- package/templates/react-router/alchemy.run.ts +1 -3
- package/templates/rwsdk/alchemy.run.ts +0 -2
- package/templates/sveltekit/alchemy.run.ts +1 -3
- package/templates/tanstack-start/alchemy.run.ts +1 -3
- package/templates/typescript/alchemy.run.ts +0 -1
- package/templates/vite/alchemy.run.ts +0 -1
- package/workers/cloudflare-state-store.js +58 -58
- package/lib/cloudflare/bundle/externals.d.ts +0 -3
- package/lib/cloudflare/bundle/externals.d.ts.map +0 -1
- package/lib/cloudflare/bundle/externals.js +0 -35
- package/lib/cloudflare/bundle/externals.js.map +0 -1
- package/lib/cloudflare/bundle/plugin-compat-warning.d.ts +0 -10
- package/lib/cloudflare/bundle/plugin-compat-warning.d.ts.map +0 -1
- package/lib/cloudflare/bundle/plugin-compat-warning.js +0 -67
- package/lib/cloudflare/bundle/plugin-compat-warning.js.map +0 -1
- package/lib/planetscale/api.d.ts +0 -53
- package/lib/planetscale/api.d.ts.map +0 -1
- package/lib/planetscale/api.js +0 -84
- package/lib/planetscale/api.js.map +0 -1
- package/src/cloudflare/bundle/externals.ts +0 -36
- package/src/cloudflare/bundle/plugin-compat-warning.ts +0 -94
- package/src/planetscale/api.ts +0 -115
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "alchemy",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.65.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"author": "Sam Goodwin <sam@alchemy.run>",
|
|
6
6
|
"homepage": "https://alchemy.run",
|
|
@@ -147,7 +147,7 @@
|
|
|
147
147
|
},
|
|
148
148
|
"dependencies": {
|
|
149
149
|
"@aws-sdk/credential-providers": "^3.0.0",
|
|
150
|
-
"@cloudflare/unenv-preset": "^2.6.
|
|
150
|
+
"@cloudflare/unenv-preset": "^2.6.3",
|
|
151
151
|
"@iarna/toml": "^2.2.5",
|
|
152
152
|
"@smithy/node-config-provider": "^4.0.0",
|
|
153
153
|
"aws4fetch": "^1.0.20",
|
|
@@ -182,9 +182,10 @@
|
|
|
182
182
|
"@aws-sdk/client-ssm": "^3.0.0",
|
|
183
183
|
"@aws-sdk/client-sts": "^3.0.0",
|
|
184
184
|
"@cloudflare/vite-plugin": "^1.10.1",
|
|
185
|
-
"@cloudflare/workers-types": "
|
|
185
|
+
"@cloudflare/workers-types": "^4.20250805.0",
|
|
186
186
|
"@libsql/client": "^0.15.12",
|
|
187
187
|
"@octokit/rest": "^21.1.1",
|
|
188
|
+
"@opennextjs/cloudflare": "^1.6.5",
|
|
188
189
|
"astro": "^5.13.2",
|
|
189
190
|
"drizzle-orm": "^0.44.2",
|
|
190
191
|
"rwsdk": "^0.1.36",
|
|
@@ -224,6 +225,9 @@
|
|
|
224
225
|
"@cloudflare/workers-types": {
|
|
225
226
|
"optional": true
|
|
226
227
|
},
|
|
228
|
+
"@opennextjs/cloudflare": {
|
|
229
|
+
"optional": true
|
|
230
|
+
},
|
|
227
231
|
"@octokit/rest": {
|
|
228
232
|
"optional": true
|
|
229
233
|
},
|
|
@@ -269,6 +273,7 @@
|
|
|
269
273
|
"@types/libsodium-wrappers": "^0.7.14",
|
|
270
274
|
"@types/node": "latest",
|
|
271
275
|
"@types/ws": "^8.18.1",
|
|
276
|
+
"@workos-inc/node": "^7.69.1",
|
|
272
277
|
"arktype": "^2.1.16",
|
|
273
278
|
"astro": "^5.13.2",
|
|
274
279
|
"braintrust": "^0.0.201",
|
package/src/alchemy.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { execArgv } from "node:process";
|
|
2
2
|
import { onExit } from "signal-exit";
|
|
3
|
-
import {
|
|
4
|
-
import { DestroyStrategy,
|
|
3
|
+
import { isReplacedSignal } from "./apply.ts";
|
|
4
|
+
import { DestroyStrategy, destroy, isDestroyedSignal } from "./destroy.ts";
|
|
5
5
|
import { env } from "./env.ts";
|
|
6
6
|
import {
|
|
7
7
|
ResourceFQN,
|
|
@@ -239,6 +239,10 @@ export interface AlchemyOptions {
|
|
|
239
239
|
* @default "sequential"
|
|
240
240
|
*/
|
|
241
241
|
destroyStrategy?: DestroyStrategy;
|
|
242
|
+
/**
|
|
243
|
+
* If true, children of the resource will not be destroyed (but their state will be deleted).
|
|
244
|
+
*/
|
|
245
|
+
noop?: boolean;
|
|
242
246
|
/**
|
|
243
247
|
* If true, will not print any Create/Update/Delete messages.
|
|
244
248
|
*
|
|
@@ -327,6 +331,7 @@ async function run<T>(
|
|
|
327
331
|
scopeName: id,
|
|
328
332
|
telemetryClient,
|
|
329
333
|
});
|
|
334
|
+
let noop = options?.noop ?? false;
|
|
330
335
|
try {
|
|
331
336
|
if (options?.isResource !== true && _scope.parent) {
|
|
332
337
|
// TODO(sam): this is an awful hack to differentiate between naked scopes and resources
|
|
@@ -364,13 +369,16 @@ async function run<T>(
|
|
|
364
369
|
}
|
|
365
370
|
return await _scope.run(async () => fn.bind(_scope)(_scope));
|
|
366
371
|
} catch (error) {
|
|
367
|
-
if (
|
|
368
|
-
!(error instanceof DestroyedSignal || error instanceof ReplacedSignal)
|
|
369
|
-
) {
|
|
372
|
+
if (!(isDestroyedSignal(error) || isReplacedSignal(error))) {
|
|
370
373
|
_scope.fail();
|
|
371
374
|
}
|
|
375
|
+
if (isDestroyedSignal(error)) {
|
|
376
|
+
noop = noop || error.noop;
|
|
377
|
+
}
|
|
372
378
|
throw error;
|
|
373
379
|
} finally {
|
|
374
|
-
await _scope.finalize(
|
|
380
|
+
await _scope.finalize({
|
|
381
|
+
noop,
|
|
382
|
+
});
|
|
375
383
|
}
|
|
376
384
|
}
|
package/src/apply.ts
CHANGED
|
@@ -22,6 +22,7 @@ import type { Telemetry } from "./util/telemetry/index.ts";
|
|
|
22
22
|
export interface ApplyOptions {
|
|
23
23
|
quiet?: boolean;
|
|
24
24
|
alwaysUpdate?: boolean;
|
|
25
|
+
noop?: boolean;
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
export function apply<Out extends Resource>(
|
|
@@ -32,7 +33,12 @@ export function apply<Out extends Resource>(
|
|
|
32
33
|
return _apply(resource, props, options);
|
|
33
34
|
}
|
|
34
35
|
|
|
36
|
+
export function isReplacedSignal(error: any): error is ReplacedSignal {
|
|
37
|
+
return error instanceof Error && (error as any).kind === "ReplacedSignal";
|
|
38
|
+
}
|
|
39
|
+
|
|
35
40
|
export class ReplacedSignal extends Error {
|
|
41
|
+
readonly kind = "ReplacedSignal";
|
|
36
42
|
public force: boolean;
|
|
37
43
|
|
|
38
44
|
constructor(force?: boolean) {
|
|
@@ -185,6 +191,7 @@ async function _apply<Out extends Resource>(
|
|
|
185
191
|
isResource: true,
|
|
186
192
|
parent: scope,
|
|
187
193
|
destroyStrategy: provider.options?.destroyStrategy ?? "sequential",
|
|
194
|
+
noop: options?.noop,
|
|
188
195
|
},
|
|
189
196
|
async () =>
|
|
190
197
|
await provider.handler.bind(ctx)(resource[ResourceID], props),
|
|
@@ -199,6 +206,7 @@ async function _apply<Out extends Resource>(
|
|
|
199
206
|
props: state.oldProps,
|
|
200
207
|
output: oldOutput,
|
|
201
208
|
},
|
|
209
|
+
noop: options?.noop,
|
|
202
210
|
});
|
|
203
211
|
} else {
|
|
204
212
|
if (
|
|
@@ -219,7 +227,11 @@ async function _apply<Out extends Resource>(
|
|
|
219
227
|
|
|
220
228
|
output = await alchemy.run(
|
|
221
229
|
resource[ResourceID],
|
|
222
|
-
{
|
|
230
|
+
{
|
|
231
|
+
isResource: true,
|
|
232
|
+
parent: scope,
|
|
233
|
+
noop: options?.noop,
|
|
234
|
+
},
|
|
223
235
|
async () =>
|
|
224
236
|
provider.handler.bind(
|
|
225
237
|
context({
|
|
@@ -10,7 +10,7 @@ import type { AnalyticsEngineDataset } from "./analytics-engine.ts";
|
|
|
10
10
|
import type { Assets } from "./assets.ts";
|
|
11
11
|
import type { Bound } from "./bound.ts";
|
|
12
12
|
import type { BrowserRendering } from "./browser-rendering.ts";
|
|
13
|
-
import type { R2Bucket } from "./bucket.ts";
|
|
13
|
+
import type { R2Bucket, R2BucketJurisdiction } from "./bucket.ts";
|
|
14
14
|
import type { Container } from "./container.ts";
|
|
15
15
|
import type { D1Database } from "./d1-database.ts";
|
|
16
16
|
import type { DispatchNamespace } from "./dispatch-namespace.ts";
|
|
@@ -317,6 +317,8 @@ export interface WorkerBindingR2Bucket {
|
|
|
317
317
|
type: "r2_bucket";
|
|
318
318
|
/** Bucket name */
|
|
319
319
|
bucket_name: string;
|
|
320
|
+
/** Jurisdiction */
|
|
321
|
+
jurisdiction?: R2BucketJurisdiction;
|
|
320
322
|
}
|
|
321
323
|
|
|
322
324
|
/**
|
package/src/cloudflare/bucket.ts
CHANGED
|
@@ -15,6 +15,8 @@ import {
|
|
|
15
15
|
} from "./api.ts";
|
|
16
16
|
import { deleteMiniflareBinding } from "./miniflare/delete.ts";
|
|
17
17
|
|
|
18
|
+
export type R2BucketJurisdiction = "default" | "eu" | "fedramp";
|
|
19
|
+
|
|
18
20
|
/**
|
|
19
21
|
* Properties for creating or updating an R2 Bucket
|
|
20
22
|
*/
|
|
@@ -44,7 +46,7 @@ export interface BucketProps extends CloudflareApiOptions {
|
|
|
44
46
|
* Optional jurisdiction for the bucket
|
|
45
47
|
* Determines the regulatory jurisdiction the bucket data falls under
|
|
46
48
|
*/
|
|
47
|
-
jurisdiction?:
|
|
49
|
+
jurisdiction?: R2BucketJurisdiction;
|
|
48
50
|
|
|
49
51
|
/**
|
|
50
52
|
* Whether to allow public access through the r2.dev subdomain
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Plugin } from "esbuild";
|
|
2
|
+
import { dedent } from "../../util/dedent.ts";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* An esbuild plugin that will mark any `cloudflare:...` imports as external.
|
|
6
|
+
*/
|
|
7
|
+
export const cloudflareInternalPlugin: Plugin = {
|
|
8
|
+
name: "cloudflare-internal-imports",
|
|
9
|
+
setup(pluginBuild) {
|
|
10
|
+
const paths = new Set();
|
|
11
|
+
pluginBuild.onStart(() => paths.clear());
|
|
12
|
+
pluginBuild.onResolve({ filter: /^cloudflare:.*/ }, (args) => {
|
|
13
|
+
paths.add(args.path);
|
|
14
|
+
return { external: true };
|
|
15
|
+
});
|
|
16
|
+
pluginBuild.onEnd(() => {
|
|
17
|
+
if (pluginBuild.initialOptions.format === "iife" && paths.size > 0) {
|
|
18
|
+
// If we are bundling in "Service Worker" mode,
|
|
19
|
+
// imports of external modules such as `cloudflare:...`,
|
|
20
|
+
// which won't be inlined/bundled by esbuild, are invalid.
|
|
21
|
+
const pathList = new Intl.ListFormat("en-US").format(
|
|
22
|
+
Array.from(paths.keys())
|
|
23
|
+
.map((p) => `"${p}"`)
|
|
24
|
+
.sort(),
|
|
25
|
+
);
|
|
26
|
+
return {
|
|
27
|
+
errors: [
|
|
28
|
+
{
|
|
29
|
+
text: dedent`
|
|
30
|
+
Unexpected external import of ${pathList}.
|
|
31
|
+
Your worker has no default export, which means it is assumed to be a Service Worker format Worker.
|
|
32
|
+
Did you mean to create a ES Module format Worker?
|
|
33
|
+
If so, try adding \`export default { ... }\` in your entry-point.
|
|
34
|
+
See https://developers.cloudflare.com/workers/reference/migrate-to-module-workers/.
|
|
35
|
+
`,
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
},
|
|
42
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { builtinModules } from "node:module";
|
|
2
|
+
|
|
3
|
+
export const NODEJS_MODULES_RE = new RegExp(
|
|
4
|
+
`^(node:)?(${builtinModules
|
|
5
|
+
.filter(
|
|
6
|
+
(m) =>
|
|
7
|
+
![
|
|
8
|
+
// in some runtimes (like bun), `ws` is a built-in module but is not in `node`
|
|
9
|
+
// bundling for `nodejs_compat` should not polyfill these modules
|
|
10
|
+
"ws",
|
|
11
|
+
].includes(m),
|
|
12
|
+
)
|
|
13
|
+
.join("|")})$`,
|
|
14
|
+
);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Plugin } from "esbuild";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* An esbuild plugin that will mark `node:async_hooks` imports as external.
|
|
5
|
+
*/
|
|
6
|
+
export const esbuildPluginAsyncLocalStorage: Plugin = {
|
|
7
|
+
name: "async-local-storage-imports",
|
|
8
|
+
setup(pluginBuild) {
|
|
9
|
+
pluginBuild.onResolve({ filter: /^node:async_hooks(\/|$)/ }, () => {
|
|
10
|
+
return { external: true };
|
|
11
|
+
});
|
|
12
|
+
},
|
|
13
|
+
};
|
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
import type { Plugin, PluginBuild } from "esbuild";
|
|
6
6
|
import assert from "node:assert";
|
|
7
|
-
import
|
|
7
|
+
import { createRequire } from "node:module";
|
|
8
8
|
import nodePath from "node:path";
|
|
9
9
|
import { dedent } from "../../util/dedent.ts";
|
|
10
|
+
import { NODEJS_MODULES_RE } from "./nodejs-builtin-modules.ts";
|
|
10
11
|
|
|
11
12
|
const _require =
|
|
12
13
|
typeof require === "undefined" ? createRequire(import.meta.url) : require;
|
|
@@ -19,15 +20,34 @@ const REQUIRED_UNENV_ALIAS_NAMESPACE = "required-unenv-alias";
|
|
|
19
20
|
*
|
|
20
21
|
* @returns ESBuild plugin
|
|
21
22
|
*/
|
|
22
|
-
export function esbuildPluginHybridNodeCompat(
|
|
23
|
+
export function esbuildPluginHybridNodeCompat({
|
|
24
|
+
compatibilityDate,
|
|
25
|
+
compatibilityFlags,
|
|
26
|
+
}: {
|
|
27
|
+
compatibilityDate?: string;
|
|
28
|
+
compatibilityFlags?: string[];
|
|
29
|
+
}): Plugin {
|
|
23
30
|
return {
|
|
24
31
|
name: "hybrid-nodejs_compat",
|
|
25
|
-
|
|
32
|
+
async setup(build) {
|
|
26
33
|
// `unenv` and `@cloudflare/unenv-preset` only publish esm
|
|
27
34
|
const { defineEnv } = await import("unenv");
|
|
28
|
-
const {
|
|
35
|
+
const { getCloudflarePreset } = await import("@cloudflare/unenv-preset");
|
|
36
|
+
|
|
29
37
|
const { alias, inject, external, polyfill } = defineEnv({
|
|
30
|
-
presets: [
|
|
38
|
+
presets: [
|
|
39
|
+
getCloudflarePreset({
|
|
40
|
+
compatibilityDate,
|
|
41
|
+
compatibilityFlags,
|
|
42
|
+
}),
|
|
43
|
+
{
|
|
44
|
+
alias: {
|
|
45
|
+
// Force esbuild to use the node implementation of debug instead of unenv's no-op stub.
|
|
46
|
+
// The alias is processed by handleUnenvAliasedPackages which uses require.resolve().
|
|
47
|
+
debug: "debug",
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
],
|
|
31
51
|
npmShims: true,
|
|
32
52
|
}).env;
|
|
33
53
|
|
|
@@ -39,19 +59,6 @@ export function esbuildPluginHybridNodeCompat(): Plugin {
|
|
|
39
59
|
};
|
|
40
60
|
}
|
|
41
61
|
|
|
42
|
-
const NODEJS_MODULES_RE = new RegExp(
|
|
43
|
-
`^(node:)?(${module.builtinModules
|
|
44
|
-
.filter(
|
|
45
|
-
(m) =>
|
|
46
|
-
![
|
|
47
|
-
// in some runtimes (like bun), `ws` is a built-in module but is not in `node`
|
|
48
|
-
// bundling for `nodejs_compat` should not polyfill these modules
|
|
49
|
-
"ws",
|
|
50
|
-
].includes(m),
|
|
51
|
-
)
|
|
52
|
-
.join("|")})$`,
|
|
53
|
-
);
|
|
54
|
-
|
|
55
62
|
/**
|
|
56
63
|
* If we are bundling a "Service Worker" formatted Worker, imports of external modules,
|
|
57
64
|
* which won't be inlined/bundled by esbuild, are invalid.
|
|
@@ -108,8 +115,8 @@ function handleRequireCallsToNodeJSBuiltins(build: PluginBuild) {
|
|
|
108
115
|
({ path }) => {
|
|
109
116
|
return {
|
|
110
117
|
contents: dedent`
|
|
111
|
-
|
|
112
|
-
|
|
118
|
+
import libDefault from '${path}';
|
|
119
|
+
module.exports = libDefault;`,
|
|
113
120
|
loader: "js",
|
|
114
121
|
};
|
|
115
122
|
},
|
|
@@ -133,7 +140,7 @@ function handleUnenvAliasedPackages(
|
|
|
133
140
|
for (const [module, unresolvedAlias] of Object.entries(alias)) {
|
|
134
141
|
try {
|
|
135
142
|
aliasAbsolute[module] = _require.resolve(unresolvedAlias);
|
|
136
|
-
} catch
|
|
143
|
+
} catch {
|
|
137
144
|
// this is an alias for package that is not installed in the current app => ignore
|
|
138
145
|
}
|
|
139
146
|
}
|
|
@@ -144,17 +151,12 @@ function handleUnenvAliasedPackages(
|
|
|
144
151
|
|
|
145
152
|
build.onResolve({ filter: UNENV_ALIAS_RE }, (args) => {
|
|
146
153
|
const unresolvedAlias = alias[args.path];
|
|
147
|
-
|
|
148
154
|
// Convert `require()` calls for NPM packages to a virtual ES Module that can be imported avoiding the require calls.
|
|
149
155
|
// Note: Does not apply to Node.js packages that are handled in `handleRequireCallsToNodeJSBuiltins`
|
|
150
156
|
if (
|
|
151
157
|
args.kind === "require-call" &&
|
|
152
158
|
(unresolvedAlias.startsWith("unenv/npm/") ||
|
|
153
|
-
unresolvedAlias.startsWith("unenv/mock/")
|
|
154
|
-
// this does not exist in the original wrangler code but does seem to resolve the problem
|
|
155
|
-
// TODO(sam): is this the right solution? Why does the same code work in wrangler?
|
|
156
|
-
unresolvedAlias.startsWith("@cloudflare/unenv-preset/npm/") ||
|
|
157
|
-
unresolvedAlias.startsWith("@cloudflare/unenv-preset/mock/"))
|
|
159
|
+
unresolvedAlias.startsWith("unenv/mock/"))
|
|
158
160
|
) {
|
|
159
161
|
return {
|
|
160
162
|
path: args.path,
|
|
@@ -200,7 +202,6 @@ function handleNodeJSGlobals(
|
|
|
200
202
|
) {
|
|
201
203
|
const UNENV_VIRTUAL_MODULE_RE = /_virtual_unenv_global_polyfill-(.+)$/;
|
|
202
204
|
const prefix = nodePath.resolve(
|
|
203
|
-
// getBasePath(),
|
|
204
205
|
import.meta.dirname,
|
|
205
206
|
"_virtual_unenv_global_polyfill-",
|
|
206
207
|
);
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import type { Plugin } from "esbuild";
|
|
2
|
+
import type { NodeJSCompatMode } from "miniflare";
|
|
3
|
+
import { relative } from "node:path";
|
|
4
|
+
import chalk from "picocolors";
|
|
5
|
+
import { dedent } from "../../util/dedent.ts";
|
|
6
|
+
import { logger } from "../../util/logger.ts";
|
|
7
|
+
import { NODEJS_MODULES_RE } from "./nodejs-builtin-modules.ts";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* An esbuild plugin that will:
|
|
11
|
+
* - mark any `node:...` imports as external
|
|
12
|
+
* - warn if there are node imports (if not in v1 mode)
|
|
13
|
+
*
|
|
14
|
+
* Applies to: null, als, legacy and v1 modes.
|
|
15
|
+
*/
|
|
16
|
+
export const esbuildPluginNodeCompatImports = (
|
|
17
|
+
mode: NodeJSCompatMode,
|
|
18
|
+
): Plugin => ({
|
|
19
|
+
name: "nodejs_compat-imports",
|
|
20
|
+
setup(pluginBuild) {
|
|
21
|
+
// Infinite loop detection
|
|
22
|
+
const seen = new Set<string>();
|
|
23
|
+
|
|
24
|
+
// Prevent multiple warnings per package
|
|
25
|
+
const warnedPackages = new Map<string, string[]>();
|
|
26
|
+
|
|
27
|
+
pluginBuild.onStart(() => {
|
|
28
|
+
seen.clear();
|
|
29
|
+
warnedPackages.clear();
|
|
30
|
+
});
|
|
31
|
+
pluginBuild.onResolve(
|
|
32
|
+
{ filter: NODEJS_MODULES_RE },
|
|
33
|
+
async ({ path, kind, resolveDir, importer }) => {
|
|
34
|
+
const specifier = `${path}:${kind}:${resolveDir}:${importer}`;
|
|
35
|
+
if (seen.has(specifier)) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
seen.add(specifier);
|
|
40
|
+
// Try to resolve this import as a normal package
|
|
41
|
+
const result = await pluginBuild.resolve(path, {
|
|
42
|
+
kind,
|
|
43
|
+
resolveDir,
|
|
44
|
+
importer,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
if (result.errors.length > 0) {
|
|
48
|
+
// esbuild couldn't resolve the package
|
|
49
|
+
// We should warn the user, but not fail the build
|
|
50
|
+
const pathWarnedPackages = warnedPackages.get(path) ?? [];
|
|
51
|
+
pathWarnedPackages.push(importer);
|
|
52
|
+
warnedPackages.set(path, pathWarnedPackages);
|
|
53
|
+
|
|
54
|
+
return { external: true };
|
|
55
|
+
}
|
|
56
|
+
// This is a normal package—don't treat it specially
|
|
57
|
+
return result;
|
|
58
|
+
},
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* If we are bundling a "Service Worker" formatted Worker, imports of external modules,
|
|
63
|
+
* which won't be inlined/bundled by esbuild, are invalid.
|
|
64
|
+
*
|
|
65
|
+
* This `onEnd()` handler will error if it identifies node.js external imports.
|
|
66
|
+
*/
|
|
67
|
+
pluginBuild.onEnd(() => {
|
|
68
|
+
if (
|
|
69
|
+
pluginBuild.initialOptions.format === "iife" &&
|
|
70
|
+
warnedPackages.size > 0
|
|
71
|
+
) {
|
|
72
|
+
const paths = new Intl.ListFormat("en-US").format(
|
|
73
|
+
Array.from(warnedPackages.keys())
|
|
74
|
+
.map((p) => `"${p}"`)
|
|
75
|
+
.sort(),
|
|
76
|
+
);
|
|
77
|
+
return {
|
|
78
|
+
errors: [
|
|
79
|
+
{
|
|
80
|
+
text: dedent`
|
|
81
|
+
Unexpected external import of ${paths}.
|
|
82
|
+
Your worker has no default export, which means it is assumed to be a Service Worker format Worker.
|
|
83
|
+
Did you mean to create a ES Module format Worker?
|
|
84
|
+
If so, try adding \`export default { ... }\` in your entry-point.
|
|
85
|
+
See https://developers.cloudflare.com/workers/reference/migrate-to-module-workers/.
|
|
86
|
+
`,
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// Wait until the build finishes to log warnings, so that all files which import a package
|
|
94
|
+
// can be collated
|
|
95
|
+
pluginBuild.onEnd(() => {
|
|
96
|
+
if (mode !== "v1") {
|
|
97
|
+
warnedPackages.forEach((importers: string[], path: string) => {
|
|
98
|
+
logger.warn(
|
|
99
|
+
dedent`
|
|
100
|
+
The package "${path}" wasn't found on the file system but is built into node.
|
|
101
|
+
Your Worker may throw errors at runtime unless you enable the "nodejs_compat" compatibility flag. Refer to https://developers.cloudflare.com/workers/runtime-apis/nodejs/ for more details. Imported from:
|
|
102
|
+
${toList(importers, pluginBuild.initialOptions.absWorkingDir)}`,
|
|
103
|
+
);
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
function toList(items: string[], absWorkingDir: string | undefined): string {
|
|
111
|
+
return items
|
|
112
|
+
.map((i) => ` - ${chalk.blue(relative(absWorkingDir ?? "/", i))}`)
|
|
113
|
+
.join("\n");
|
|
114
|
+
}
|
|
@@ -12,21 +12,41 @@ export function createWasmPlugin() {
|
|
|
12
12
|
build.onStart(() => {
|
|
13
13
|
modules.clear();
|
|
14
14
|
});
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
path.join(build.initialOptions.outdir, name),
|
|
23
|
-
);
|
|
24
|
-
modules.set(args.path, {
|
|
25
|
-
type: "wasm",
|
|
26
|
-
path: name,
|
|
27
|
-
});
|
|
15
|
+
|
|
16
|
+
// Handle imports like `import "./foo.wasm"` and `import "./foo.wasm?module"`
|
|
17
|
+
// TODO(john): Figure out why this suddenly became necessary
|
|
18
|
+
build.onResolve({ filter: /\.wasm(\?.*)?$/ }, async (args) => {
|
|
19
|
+
const resolved = modules.get(args.path);
|
|
20
|
+
if (resolved) {
|
|
21
|
+
return { path: resolved.path, external: true };
|
|
28
22
|
}
|
|
29
|
-
|
|
23
|
+
|
|
24
|
+
// Normalize path and remove the `?module` query param so we have the actual file name to copy
|
|
25
|
+
const name = path.normalize(args.path).replace(/\?.*$/, "");
|
|
26
|
+
|
|
27
|
+
// Resolve path to outdir (required for monorepos if the workdir is not the same as process.cwd())
|
|
28
|
+
assert(
|
|
29
|
+
build.initialOptions.absWorkingDir && build.initialOptions.outdir,
|
|
30
|
+
"Missing absWorkingDir or outdir from esbuild options",
|
|
31
|
+
);
|
|
32
|
+
const outdir = path.resolve(
|
|
33
|
+
build.initialOptions.absWorkingDir,
|
|
34
|
+
build.initialOptions.outdir,
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
// Copy to outdir so it's included in the upload
|
|
38
|
+
await fs.mkdir(outdir, { recursive: true });
|
|
39
|
+
await fs.copyFile(
|
|
40
|
+
path.join(args.resolveDir, name),
|
|
41
|
+
path.join(outdir, name),
|
|
42
|
+
);
|
|
43
|
+
modules.set(args.path, {
|
|
44
|
+
type: "wasm",
|
|
45
|
+
path: name,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Resolve to the normalized file name (the `?module` query param is not needed in workerd)
|
|
49
|
+
return { path: name, external: true };
|
|
30
50
|
});
|
|
31
51
|
},
|
|
32
52
|
};
|
|
@@ -20,8 +20,8 @@ export const applyLocalD1Migrations = async (
|
|
|
20
20
|
});
|
|
21
21
|
try {
|
|
22
22
|
await miniflare.ready;
|
|
23
|
-
const db = await miniflare.getD1Database("DB");
|
|
24
|
-
const session = db.withSession("first-primary");
|
|
23
|
+
const db: D1Database = await miniflare.getD1Database("DB");
|
|
24
|
+
const session: D1DatabaseSession = db.withSession("first-primary");
|
|
25
25
|
await session
|
|
26
26
|
.prepare(
|
|
27
27
|
`CREATE TABLE IF NOT EXISTS ${options.migrationsTable} (
|