alchemy 0.53.0 → 0.55.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 +196353 -0
- package/bin/alchemy.ts +2 -2
- package/bin/commands/init.ts +1190 -0
- package/bin/constants.ts +18 -0
- package/bin/services/execute-alchemy.ts +7 -2
- package/bin/services/package-manager.ts +1 -1
- package/bin/types.ts +14 -5
- package/lib/aws/ec2/index.d.ts +10 -0
- package/lib/aws/ec2/index.d.ts.map +1 -0
- package/lib/aws/ec2/index.js +10 -0
- package/lib/aws/ec2/index.js.map +1 -0
- package/lib/aws/ec2/internet-gateway-attachment.d.ts +150 -0
- package/lib/aws/ec2/internet-gateway-attachment.d.ts.map +1 -0
- package/lib/aws/ec2/internet-gateway-attachment.js +248 -0
- package/lib/aws/ec2/internet-gateway-attachment.js.map +1 -0
- package/lib/aws/ec2/internet-gateway.d.ts +132 -0
- package/lib/aws/ec2/internet-gateway.d.ts.map +1 -0
- package/lib/aws/ec2/internet-gateway.js +311 -0
- package/lib/aws/ec2/internet-gateway.js.map +1 -0
- package/lib/aws/ec2/nat-gateway.d.ts +145 -0
- package/lib/aws/ec2/nat-gateway.d.ts.map +1 -0
- package/lib/aws/ec2/nat-gateway.js +618 -0
- package/lib/aws/ec2/nat-gateway.js.map +1 -0
- package/lib/aws/ec2/route-table-association.d.ts +134 -0
- package/lib/aws/ec2/route-table-association.d.ts.map +1 -0
- package/lib/aws/ec2/route-table-association.js +364 -0
- package/lib/aws/ec2/route-table-association.js.map +1 -0
- package/lib/aws/ec2/route-table.d.ts +94 -0
- package/lib/aws/ec2/route-table.d.ts.map +1 -0
- package/lib/aws/ec2/route-table.js +253 -0
- package/lib/aws/ec2/route-table.js.map +1 -0
- package/lib/aws/ec2/route.d.ts +130 -0
- package/lib/aws/ec2/route.d.ts.map +1 -0
- package/lib/aws/ec2/route.js +253 -0
- package/lib/aws/ec2/route.js.map +1 -0
- package/lib/aws/ec2/security-group-rule.d.ts +84 -0
- package/lib/aws/ec2/security-group-rule.d.ts.map +1 -0
- package/lib/aws/ec2/security-group-rule.js +123 -0
- package/lib/aws/ec2/security-group-rule.js.map +1 -0
- package/lib/aws/ec2/security-group.d.ts +84 -0
- package/lib/aws/ec2/security-group.d.ts.map +1 -0
- package/lib/aws/ec2/security-group.js +207 -0
- package/lib/aws/ec2/security-group.js.map +1 -0
- package/lib/aws/ec2/subnet.d.ts +110 -0
- package/lib/aws/ec2/subnet.d.ts.map +1 -0
- package/lib/aws/ec2/subnet.js +336 -0
- package/lib/aws/ec2/subnet.js.map +1 -0
- package/lib/aws/ec2/utils.d.ts +15 -0
- package/lib/aws/ec2/utils.d.ts.map +1 -0
- package/lib/aws/ec2/utils.js +79 -0
- package/lib/aws/ec2/utils.js.map +1 -0
- package/lib/aws/ec2/vpc.d.ts +160 -0
- package/lib/aws/ec2/vpc.d.ts.map +1 -0
- package/lib/aws/ec2/vpc.js +453 -0
- package/lib/aws/ec2/vpc.js.map +1 -0
- package/lib/aws/index.d.ts +7 -0
- package/lib/aws/index.d.ts.map +1 -1
- package/lib/aws/index.js +8 -0
- package/lib/aws/index.js.map +1 -1
- package/lib/aws/utils.d.ts +25 -0
- package/lib/aws/utils.d.ts.map +1 -0
- package/lib/aws/utils.js +89 -0
- package/lib/aws/utils.js.map +1 -0
- package/lib/build-date.d.ts +6 -0
- package/lib/build-date.d.ts.map +1 -0
- package/lib/build-date.js +8 -0
- package/lib/build-date.js.map +1 -0
- package/lib/cloudflare/astro.d.ts.map +1 -1
- package/lib/cloudflare/astro.js +4 -3
- package/lib/cloudflare/astro.js.map +1 -1
- package/lib/cloudflare/bundle/externals.d.ts +3 -0
- package/lib/cloudflare/bundle/externals.d.ts.map +1 -0
- package/lib/cloudflare/bundle/externals.js +35 -0
- package/lib/cloudflare/bundle/externals.js.map +1 -0
- package/lib/cloudflare/bundle/internal-worker-bundle.d.ts +8 -1
- package/lib/cloudflare/bundle/internal-worker-bundle.d.ts.map +1 -1
- package/lib/cloudflare/bundle/internal-worker-bundle.js +11 -4
- package/lib/cloudflare/bundle/internal-worker-bundle.js.map +1 -1
- package/lib/cloudflare/bundle/plugin-hot-reload.d.ts +4 -1
- package/lib/cloudflare/bundle/plugin-hot-reload.d.ts.map +1 -1
- package/lib/cloudflare/bundle/plugin-hot-reload.js +27 -11
- package/lib/cloudflare/bundle/plugin-hot-reload.js.map +1 -1
- package/lib/cloudflare/bundle/plugin-hybrid-node-compat.js +5 -1
- package/lib/cloudflare/bundle/plugin-hybrid-node-compat.js.map +1 -1
- package/lib/cloudflare/bundle/plugin-wasm.d.ts +6 -2
- package/lib/cloudflare/bundle/plugin-wasm.d.ts.map +1 -1
- package/lib/cloudflare/bundle/plugin-wasm.js +21 -47
- package/lib/cloudflare/bundle/plugin-wasm.js.map +1 -1
- package/lib/cloudflare/bundle/validate-node-compat.d.ts +2 -1
- package/lib/cloudflare/bundle/validate-node-compat.d.ts.map +1 -1
- package/lib/cloudflare/bundle/validate-node-compat.js +5 -4
- package/lib/cloudflare/bundle/validate-node-compat.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-database.js +1 -1
- package/lib/cloudflare/d1-database.js.map +1 -1
- package/lib/cloudflare/d1-migrations.d.ts.map +1 -1
- package/lib/cloudflare/d1-migrations.js +8 -10
- package/lib/cloudflare/d1-migrations.js.map +1 -1
- package/lib/cloudflare/miniflare/miniflare-worker-options.d.ts +3 -3
- package/lib/cloudflare/miniflare/miniflare-worker-options.d.ts.map +1 -1
- package/lib/cloudflare/miniflare/miniflare-worker-options.js +23 -6
- package/lib/cloudflare/miniflare/miniflare-worker-options.js.map +1 -1
- package/lib/cloudflare/miniflare/miniflare.d.ts.map +1 -1
- package/lib/cloudflare/miniflare/miniflare.js +2 -4
- package/lib/cloudflare/miniflare/miniflare.js.map +1 -1
- package/lib/cloudflare/miniflare/remote-binding-proxy.d.ts.map +1 -1
- package/lib/cloudflare/miniflare/remote-binding-proxy.js +4 -6
- package/lib/cloudflare/miniflare/remote-binding-proxy.js.map +1 -1
- package/lib/cloudflare/react-router.d.ts +4 -0
- package/lib/cloudflare/react-router.d.ts.map +1 -1
- package/lib/cloudflare/react-router.js +8 -5
- package/lib/cloudflare/react-router.js.map +1 -1
- package/lib/cloudflare/worker-bundle.d.ts +80 -0
- package/lib/cloudflare/worker-bundle.d.ts.map +1 -0
- package/lib/cloudflare/worker-bundle.js +266 -0
- package/lib/cloudflare/worker-bundle.js.map +1 -0
- package/lib/cloudflare/worker.d.ts +1 -1
- package/lib/cloudflare/worker.d.ts.map +1 -1
- package/lib/cloudflare/worker.js +81 -195
- package/lib/cloudflare/worker.js.map +1 -1
- package/lib/esbuild/bundle.d.ts +1 -0
- package/lib/esbuild/bundle.d.ts.map +1 -1
- package/lib/state/cloudflare-state-store.js +1 -5
- package/lib/state/cloudflare-state-store.js.map +1 -1
- package/lib/state/dofs-state-store/store.d.ts.map +1 -1
- package/lib/state/dofs-state-store/store.js +4 -4
- package/lib/state/dofs-state-store/store.js.map +1 -1
- package/lib/util/params.d.ts +5 -0
- package/lib/util/params.d.ts.map +1 -0
- package/lib/util/params.js +30 -0
- package/lib/util/params.js.map +1 -0
- package/lib/util/timeout.d.ts +31 -0
- package/lib/util/timeout.d.ts.map +1 -0
- package/lib/util/timeout.js +109 -0
- package/lib/util/timeout.js.map +1 -0
- package/lib/util/xml.d.ts +5 -0
- package/lib/util/xml.d.ts.map +1 -0
- package/lib/util/xml.js +8 -0
- package/lib/util/xml.js.map +1 -0
- package/package.json +12 -5
- package/src/aws/ec2/index.ts +9 -0
- package/src/aws/ec2/internet-gateway-attachment.ts +468 -0
- package/src/aws/ec2/internet-gateway.ts +557 -0
- package/src/aws/ec2/nat-gateway.ts +1123 -0
- package/src/aws/ec2/route-table-association.ts +747 -0
- package/src/aws/ec2/route-table.ts +452 -0
- package/src/aws/ec2/route.ts +447 -0
- package/src/aws/ec2/security-group-rule.ts +229 -0
- package/src/aws/ec2/security-group.ts +418 -0
- package/src/aws/ec2/subnet.ts +625 -0
- package/src/aws/ec2/utils.ts +102 -0
- package/src/aws/ec2/vpc.ts +969 -0
- package/src/aws/index.ts +9 -0
- package/src/aws/utils.ts +137 -0
- package/src/build-date.ts +8 -0
- package/src/cloudflare/astro.ts +4 -3
- package/src/cloudflare/bundle/externals.ts +36 -0
- package/src/cloudflare/bundle/internal-worker-bundle.ts +12 -3
- package/src/cloudflare/bundle/plugin-hot-reload.ts +32 -12
- package/src/cloudflare/bundle/plugin-hybrid-node-compat.ts +6 -1
- package/src/cloudflare/bundle/plugin-wasm.ts +26 -54
- package/src/cloudflare/bundle/validate-node-compat.ts +6 -5
- package/src/cloudflare/compatibility-date.gen.ts +1 -1
- package/src/cloudflare/d1-database.ts +1 -1
- package/src/cloudflare/d1-migrations.ts +19 -18
- package/src/cloudflare/miniflare/miniflare-worker-options.ts +27 -13
- package/src/cloudflare/miniflare/miniflare.ts +2 -4
- package/src/cloudflare/miniflare/remote-binding-proxy.ts +5 -7
- package/src/cloudflare/react-router.ts +14 -6
- package/src/cloudflare/worker-bundle.ts +364 -0
- package/src/cloudflare/worker.ts +104 -241
- package/src/state/cloudflare-state-store.ts +1 -5
- package/src/state/dofs-state-store/store.ts +4 -4
- package/src/util/params.ts +33 -0
- package/src/util/timeout.ts +178 -0
- package/src/util/xml.ts +7 -0
- package/templates/nuxt/package.json +1 -1
- package/templates/nuxt/types/env.d.ts +11 -0
- package/templates/react-router/workers/app.ts +2 -2
- package/templates/rwsdk/.cursor/rules/alchemy_cloudflare.mdc +385 -0
- package/templates/rwsdk/wrangler.jsonc +10 -7
- package/templates/typescript/tsconfig.json +1 -2
- package/bin/alchemy.mjs +0 -51766
- package/lib/cloudflare/bundle/esbuild.d.ts +0 -16
- package/lib/cloudflare/bundle/esbuild.d.ts.map +0 -1
- package/lib/cloudflare/bundle/esbuild.js +0 -159
- package/lib/cloudflare/bundle/esbuild.js.map +0 -1
- package/lib/cloudflare/bundle/fs.d.ts +0 -18
- package/lib/cloudflare/bundle/fs.d.ts.map +0 -1
- package/lib/cloudflare/bundle/fs.js +0 -78
- package/lib/cloudflare/bundle/fs.js.map +0 -1
- package/lib/cloudflare/bundle/index.d.ts +0 -3
- package/lib/cloudflare/bundle/index.d.ts.map +0 -1
- package/lib/cloudflare/bundle/index.js +0 -2
- package/lib/cloudflare/bundle/index.js.map +0 -1
- package/lib/cloudflare/bundle/inline.d.ts +0 -12
- package/lib/cloudflare/bundle/inline.d.ts.map +0 -1
- package/lib/cloudflare/bundle/inline.js +0 -32
- package/lib/cloudflare/bundle/inline.js.map +0 -1
- package/lib/cloudflare/bundle/normalize.d.ts +0 -21
- package/lib/cloudflare/bundle/normalize.d.ts.map +0 -1
- package/lib/cloudflare/bundle/normalize.js +0 -49
- package/lib/cloudflare/bundle/normalize.js.map +0 -1
- package/lib/cloudflare/bundle/shared.d.ts +0 -30
- package/lib/cloudflare/bundle/shared.d.ts.map +0 -1
- package/lib/cloudflare/bundle/shared.js +0 -34
- package/lib/cloudflare/bundle/shared.js.map +0 -1
- package/src/cloudflare/bundle/esbuild.ts +0 -194
- package/src/cloudflare/bundle/fs.ts +0 -103
- package/src/cloudflare/bundle/index.ts +0 -6
- package/src/cloudflare/bundle/inline.ts +0 -42
- package/src/cloudflare/bundle/normalize.ts +0 -76
- package/src/cloudflare/bundle/shared.ts +0 -73
package/src/aws/index.ts
CHANGED
|
@@ -9,3 +9,12 @@ export * from "./s3-state-store.ts";
|
|
|
9
9
|
export * from "./ses.ts";
|
|
10
10
|
export * from "./ssm-parameter.ts";
|
|
11
11
|
export * from "./table.ts";
|
|
12
|
+
|
|
13
|
+
// EC2 Resources
|
|
14
|
+
export * from "./ec2/internet-gateway.ts";
|
|
15
|
+
export * from "./ec2/nat-gateway.ts";
|
|
16
|
+
export * from "./ec2/route-table.ts";
|
|
17
|
+
export * from "./ec2/route.ts";
|
|
18
|
+
export * from "./ec2/security-group.ts";
|
|
19
|
+
export * from "./ec2/subnet.ts";
|
|
20
|
+
export * from "./ec2/vpc.ts";
|
package/src/aws/utils.ts
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { fromNodeProviderChain } from "@aws-sdk/credential-providers";
|
|
2
|
+
import { loadConfig } from "@smithy/node-config-provider";
|
|
3
|
+
import { AwsClient } from "aws4fetch";
|
|
4
|
+
import { flattenParams } from "../util/params.ts";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Get AWS region from configuration
|
|
8
|
+
*/
|
|
9
|
+
export const getRegion = loadConfig({
|
|
10
|
+
environmentVariableSelector: (env: any) =>
|
|
11
|
+
env.AWS_REGION || env.AWS_DEFAULT_REGION,
|
|
12
|
+
configFileSelector: (profile: any) => profile.region,
|
|
13
|
+
default: "us-east-1",
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* AWS Service Configuration
|
|
18
|
+
*/
|
|
19
|
+
export interface AwsServiceConfig {
|
|
20
|
+
service: string;
|
|
21
|
+
version: string;
|
|
22
|
+
endpoint: (region: string) => string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* AWS API Caller interface
|
|
27
|
+
*/
|
|
28
|
+
export interface AwsApiCaller<T = any> {
|
|
29
|
+
createClient(): Promise<AwsClient>;
|
|
30
|
+
callApi<R = T>(
|
|
31
|
+
client: AwsClient,
|
|
32
|
+
action: string,
|
|
33
|
+
params?: Record<string, any>,
|
|
34
|
+
): Promise<R>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Create an AWS API caller for a specific service
|
|
39
|
+
*/
|
|
40
|
+
export function getAwsApiCaller<T = any>(
|
|
41
|
+
config: AwsServiceConfig,
|
|
42
|
+
responseParser: (xmlText: string) => T,
|
|
43
|
+
): AwsApiCaller<T> {
|
|
44
|
+
return {
|
|
45
|
+
async createClient(): Promise<AwsClient> {
|
|
46
|
+
const credentials = await fromNodeProviderChain()();
|
|
47
|
+
const region = await getRegion();
|
|
48
|
+
|
|
49
|
+
return new AwsClient({
|
|
50
|
+
...credentials,
|
|
51
|
+
service: config.service,
|
|
52
|
+
region,
|
|
53
|
+
});
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
async callApi<R = T>(
|
|
57
|
+
client: AwsClient,
|
|
58
|
+
action: string,
|
|
59
|
+
params: Record<string, any> = {},
|
|
60
|
+
): Promise<R> {
|
|
61
|
+
// Try the API call, and retry once with fresh credentials on auth failure
|
|
62
|
+
for (let attempt = 1; attempt <= 2; attempt++) {
|
|
63
|
+
try {
|
|
64
|
+
const region = await getRegion();
|
|
65
|
+
const url = config.endpoint(region);
|
|
66
|
+
|
|
67
|
+
const body = new URLSearchParams({
|
|
68
|
+
Action: action,
|
|
69
|
+
Version: config.version,
|
|
70
|
+
...flattenParams(params),
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const signedRequest = await client.sign(url, {
|
|
74
|
+
method: "POST",
|
|
75
|
+
headers: {
|
|
76
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
77
|
+
},
|
|
78
|
+
body: body.toString(),
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const response = await fetch(signedRequest);
|
|
82
|
+
|
|
83
|
+
if (!response.ok) {
|
|
84
|
+
const errorText = await response.text();
|
|
85
|
+
|
|
86
|
+
// Parse AWS error code from XML response
|
|
87
|
+
const errorCodeMatch = errorText.match(/<Code>([^<]+)<\/Code>/);
|
|
88
|
+
const errorCode = errorCodeMatch ? errorCodeMatch[1] : null;
|
|
89
|
+
|
|
90
|
+
// If this is an auth failure and we haven't retried yet, create a fresh client and retry
|
|
91
|
+
if (errorCode === "AuthFailure" && attempt === 1) {
|
|
92
|
+
console.log(
|
|
93
|
+
`🔄 Auth failure detected, refreshing credentials and retrying ${action}...`,
|
|
94
|
+
);
|
|
95
|
+
// Create a fresh client with new credentials
|
|
96
|
+
const freshCredentials = await fromNodeProviderChain()();
|
|
97
|
+
const region = await getRegion();
|
|
98
|
+
client = new AwsClient({
|
|
99
|
+
...freshCredentials,
|
|
100
|
+
service: config.service,
|
|
101
|
+
region,
|
|
102
|
+
});
|
|
103
|
+
continue; // Retry with fresh client
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const error = new Error(
|
|
107
|
+
`${config.service.toUpperCase()} API error: ${response.status} ${response.statusText}\n${errorText}`,
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
// Set the error code for the ignore function
|
|
111
|
+
if (errorCode) {
|
|
112
|
+
(error as any).code = errorCode;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const xmlText = await response.text();
|
|
119
|
+
const parsed = responseParser(xmlText);
|
|
120
|
+
return parsed as unknown as R;
|
|
121
|
+
} catch (error) {
|
|
122
|
+
// If it's not an auth failure or we've already retried, throw the error
|
|
123
|
+
if (
|
|
124
|
+
attempt === 2 ||
|
|
125
|
+
!(error as any)?.message?.includes("AuthFailure")
|
|
126
|
+
) {
|
|
127
|
+
throw error;
|
|
128
|
+
}
|
|
129
|
+
// Otherwise, continue to retry
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// This should never be reached, but TypeScript needs it
|
|
134
|
+
throw new Error("Unexpected error in API call retry logic");
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
}
|
package/src/cloudflare/astro.ts
CHANGED
|
@@ -77,6 +77,10 @@ export async function Astro<B extends Bindings>(
|
|
|
77
77
|
|
|
78
78
|
return Website(id, {
|
|
79
79
|
...props,
|
|
80
|
+
command: props.command ?? "astro build",
|
|
81
|
+
dev: props.dev ?? {
|
|
82
|
+
command: "astro dev",
|
|
83
|
+
},
|
|
80
84
|
noBundle: props.noBundle ?? true,
|
|
81
85
|
main,
|
|
82
86
|
assets: {
|
|
@@ -85,8 +89,5 @@ export async function Astro<B extends Bindings>(
|
|
|
85
89
|
run_worker_first: false,
|
|
86
90
|
},
|
|
87
91
|
wrangler,
|
|
88
|
-
dev: props.dev ?? {
|
|
89
|
-
command: "astro dev",
|
|
90
|
-
},
|
|
91
92
|
});
|
|
92
93
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// https://developers.cloudflare.com/workers/runtime-apis/nodejs/#supported-nodejs-apis
|
|
2
|
+
const nodejs_compat = [
|
|
3
|
+
"node:async_hooks",
|
|
4
|
+
"node:assert",
|
|
5
|
+
"node:buffer",
|
|
6
|
+
"node:console",
|
|
7
|
+
"node:crypto",
|
|
8
|
+
"node:debug",
|
|
9
|
+
"node:diagnostics_channel",
|
|
10
|
+
"node:dns",
|
|
11
|
+
"node:events",
|
|
12
|
+
"node:inspector",
|
|
13
|
+
"node:net",
|
|
14
|
+
"node:path",
|
|
15
|
+
"node:perf_hooks", // partially supported
|
|
16
|
+
"node:process",
|
|
17
|
+
"node:querystring",
|
|
18
|
+
"node:stream",
|
|
19
|
+
"node:string_decoder",
|
|
20
|
+
"node:timers",
|
|
21
|
+
"node:tls", // partially supported
|
|
22
|
+
"node:url",
|
|
23
|
+
"node:util",
|
|
24
|
+
"node:zlib",
|
|
25
|
+
// "node:*",
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
export const external = [
|
|
29
|
+
...nodejs_compat,
|
|
30
|
+
...nodejs_compat.map((p) => p.split(":")[1]),
|
|
31
|
+
"cloudflare:workers",
|
|
32
|
+
"cloudflare:workflows",
|
|
33
|
+
"cloudflare:*",
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
export const external_als = ["node:async_hooks", "async_hooks", "cloudflare:*"];
|
|
@@ -2,6 +2,7 @@ import crypto from "node:crypto";
|
|
|
2
2
|
import fs from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { memoize } from "../../util/memoize.ts";
|
|
5
|
+
import type { WorkerBundle } from "../worker-bundle.ts";
|
|
5
6
|
|
|
6
7
|
export type InternalWorker =
|
|
7
8
|
| "cloudflare-state-store"
|
|
@@ -11,11 +12,19 @@ export type InternalWorker =
|
|
|
11
12
|
export const getInternalWorkerBundle = memoize(async (name: InternalWorker) => {
|
|
12
13
|
const content = await fs.readFile(
|
|
13
14
|
path.join(import.meta.dirname, "..", "..", "..", "workers", `${name}.js`),
|
|
15
|
+
"utf-8",
|
|
14
16
|
);
|
|
15
17
|
return {
|
|
16
|
-
file: new File([content], `${name}.js`, {
|
|
17
|
-
type: "application/javascript+module",
|
|
18
|
-
}),
|
|
19
18
|
tag: `${name}:${crypto.createHash("sha256").update(content).digest("hex")}`,
|
|
19
|
+
bundle: {
|
|
20
|
+
entrypoint: `${name}.js`,
|
|
21
|
+
modules: [
|
|
22
|
+
{
|
|
23
|
+
type: "esm",
|
|
24
|
+
path: `${name}.js`,
|
|
25
|
+
content: content,
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
} satisfies WorkerBundle,
|
|
20
29
|
};
|
|
21
30
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type esbuild from "esbuild";
|
|
2
|
+
import assert from "node:assert";
|
|
2
3
|
|
|
3
4
|
export interface HotReloadPluginProps {
|
|
4
5
|
onBuildStart?: () => void | Promise<void>;
|
|
@@ -6,22 +7,41 @@ export interface HotReloadPluginProps {
|
|
|
6
7
|
onBuildError?: (errors: esbuild.Message[]) => void | Promise<void>;
|
|
7
8
|
}
|
|
8
9
|
|
|
9
|
-
export function
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
export function createHotReloadPlugin(): {
|
|
11
|
+
plugin: esbuild.Plugin;
|
|
12
|
+
iterator: AsyncIterable<esbuild.BuildResult>;
|
|
13
|
+
} {
|
|
14
|
+
let _controller:
|
|
15
|
+
| ReadableStreamDefaultController<esbuild.BuildResult>
|
|
16
|
+
| undefined;
|
|
17
|
+
const stream = new ReadableStream<esbuild.BuildResult>({
|
|
18
|
+
start: (controller) => {
|
|
19
|
+
_controller = controller;
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
const plugin: esbuild.Plugin = {
|
|
13
23
|
name: "alchemy-hot-reload",
|
|
14
24
|
setup(build) {
|
|
15
|
-
if (props.onBuildStart) {
|
|
16
|
-
build.onStart(props.onBuildStart);
|
|
17
|
-
}
|
|
18
25
|
build.onEnd(async (result) => {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
26
|
+
assert(_controller);
|
|
27
|
+
_controller.enqueue(result);
|
|
28
|
+
});
|
|
29
|
+
build.onDispose(() => {
|
|
30
|
+
_controller?.close();
|
|
24
31
|
});
|
|
25
32
|
},
|
|
26
33
|
};
|
|
34
|
+
return {
|
|
35
|
+
plugin,
|
|
36
|
+
iterator: (async function* () {
|
|
37
|
+
const reader = stream.getReader();
|
|
38
|
+
while (true) {
|
|
39
|
+
const { done, value } = await reader.read();
|
|
40
|
+
if (done) {
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
yield value;
|
|
44
|
+
}
|
|
45
|
+
})(),
|
|
46
|
+
};
|
|
27
47
|
}
|
|
@@ -144,12 +144,17 @@ function handleUnenvAliasedPackages(
|
|
|
144
144
|
|
|
145
145
|
build.onResolve({ filter: UNENV_ALIAS_RE }, (args) => {
|
|
146
146
|
const unresolvedAlias = alias[args.path];
|
|
147
|
+
|
|
147
148
|
// Convert `require()` calls for NPM packages to a virtual ES Module that can be imported avoiding the require calls.
|
|
148
149
|
// Note: Does not apply to Node.js packages that are handled in `handleRequireCallsToNodeJSBuiltins`
|
|
149
150
|
if (
|
|
150
151
|
args.kind === "require-call" &&
|
|
151
152
|
(unresolvedAlias.startsWith("unenv/npm/") ||
|
|
152
|
-
unresolvedAlias.startsWith("unenv/mock/")
|
|
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/"))
|
|
153
158
|
) {
|
|
154
159
|
return {
|
|
155
160
|
path: args.path,
|
|
@@ -1,62 +1,34 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import type esbuild from "esbuild";
|
|
2
|
+
import assert from "node:assert";
|
|
2
3
|
import fs from "node:fs/promises";
|
|
3
4
|
import path from "node:path";
|
|
5
|
+
import type { WorkerBundle } from "../worker-bundle.ts";
|
|
4
6
|
|
|
5
|
-
export function
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
build.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
if (args.
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
// resolve callback is given "resolveDir", the directory to
|
|
27
|
-
// resolve imports against.
|
|
28
|
-
if (args.resolveDir === "") {
|
|
29
|
-
return; // Ignore unresolvable paths
|
|
7
|
+
export function createWasmPlugin() {
|
|
8
|
+
const modules = new Map<string, WorkerBundle.Module>();
|
|
9
|
+
const plugin: esbuild.Plugin = {
|
|
10
|
+
name: "alchemy-wasm",
|
|
11
|
+
setup(build) {
|
|
12
|
+
build.onStart(() => {
|
|
13
|
+
modules.clear();
|
|
14
|
+
});
|
|
15
|
+
build.onResolve({ filter: /\.wasm$/ }, async (args) => {
|
|
16
|
+
if (!modules.has(args.path)) {
|
|
17
|
+
const name = path.normalize(args.path);
|
|
18
|
+
assert(build.initialOptions.outdir, "outdir is required");
|
|
19
|
+
await fs.mkdir(build.initialOptions.outdir, { recursive: true });
|
|
20
|
+
await fs.copyFile(
|
|
21
|
+
path.join(args.resolveDir, name),
|
|
22
|
+
path.join(build.initialOptions.outdir, name),
|
|
23
|
+
);
|
|
24
|
+
modules.set(args.path, {
|
|
25
|
+
type: "wasm",
|
|
26
|
+
path: name,
|
|
27
|
+
});
|
|
30
28
|
}
|
|
31
|
-
return {
|
|
32
|
-
path: path.isAbsolute(args.path)
|
|
33
|
-
? args.path
|
|
34
|
-
: path.join(args.resolveDir, args.path),
|
|
35
|
-
namespace: "wasm-stub",
|
|
36
|
-
};
|
|
29
|
+
return { external: true };
|
|
37
30
|
});
|
|
38
|
-
|
|
39
|
-
// Virtual modules in the "wasm-stub" namespace are filled with
|
|
40
|
-
// the JavaScript code for compiling the WebAssembly binary. The
|
|
41
|
-
// binary itself is imported from a second virtual module.
|
|
42
|
-
build.onLoad({ filter: /.*/, namespace: "wasm-stub" }, async (args) => ({
|
|
43
|
-
contents: `import wasm from ${JSON.stringify(args.path)}
|
|
44
|
-
export default (imports) =>
|
|
45
|
-
WebAssembly.instantiate(wasm, imports).then(
|
|
46
|
-
result => result.instance.exports)`,
|
|
47
|
-
}));
|
|
48
|
-
|
|
49
|
-
// Virtual modules in the "wasm-binary" namespace contain the
|
|
50
|
-
// actual bytes of the WebAssembly file. This uses esbuild's
|
|
51
|
-
// built-in "binary" loader instead of manually embedding the
|
|
52
|
-
// binary data inside JavaScript code ourselves.
|
|
53
|
-
build.onLoad(
|
|
54
|
-
{ filter: /.*/, namespace: "wasm-binary" },
|
|
55
|
-
async (args) => ({
|
|
56
|
-
contents: await fs.readFile(args.path),
|
|
57
|
-
loader: "binary",
|
|
58
|
-
}),
|
|
59
|
-
);
|
|
60
31
|
},
|
|
61
32
|
};
|
|
33
|
+
return { plugin, modules };
|
|
62
34
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { err, ok, type Result } from "neverthrow";
|
|
1
2
|
import { logger } from "../../util/logger.ts";
|
|
2
3
|
|
|
3
4
|
interface ValidateNodeCompatProps {
|
|
@@ -22,7 +23,7 @@ export function validateNodeCompat({
|
|
|
22
23
|
compatibilityDate,
|
|
23
24
|
compatibilityFlags,
|
|
24
25
|
noBundle,
|
|
25
|
-
}: ValidateNodeCompatProps) {
|
|
26
|
+
}: ValidateNodeCompatProps): Result<"v2" | "als" | null, string> {
|
|
26
27
|
const {
|
|
27
28
|
hasNodejsAlsFlag,
|
|
28
29
|
hasNodejsCompatFlag,
|
|
@@ -45,13 +46,13 @@ export function validateNodeCompat({
|
|
|
45
46
|
mode = "als";
|
|
46
47
|
}
|
|
47
48
|
if (hasExperimentalNodejsCompatV2Flag) {
|
|
48
|
-
|
|
49
|
+
return err(
|
|
49
50
|
"The `experimental:` prefix on `nodejs_compat_v2` is no longer valid. Please remove it and try again.",
|
|
50
51
|
);
|
|
51
52
|
}
|
|
52
53
|
|
|
53
54
|
if (hasNodejsCompatFlag && hasNodejsCompatV2Flag) {
|
|
54
|
-
|
|
55
|
+
return err(
|
|
55
56
|
"The `nodejs_compat` and `nodejs_compat_v2` compatibility flags cannot be used in together. Please select just one.",
|
|
56
57
|
);
|
|
57
58
|
}
|
|
@@ -63,12 +64,12 @@ export function validateNodeCompat({
|
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
if (mode === "v1") {
|
|
66
|
-
|
|
67
|
+
return err(
|
|
67
68
|
"You must set your compatibilty date >= 2024-09-23 when using 'nodejs_compat' compatibility flag",
|
|
68
69
|
);
|
|
69
70
|
}
|
|
70
71
|
|
|
71
|
-
return mode;
|
|
72
|
+
return ok(mode);
|
|
72
73
|
}
|
|
73
74
|
|
|
74
75
|
function parseNodeCompatibilityFlags(compatibilityFlags: string[]) {
|
|
@@ -251,7 +251,7 @@ const _D1Database = Resource(
|
|
|
251
251
|
const databaseName = props.name ?? id;
|
|
252
252
|
|
|
253
253
|
if (this.phase === "delete") {
|
|
254
|
-
if (props.delete !== false) {
|
|
254
|
+
if (props.delete !== false && this.output?.id !== id) {
|
|
255
255
|
await deleteDatabase(api, this.output?.id);
|
|
256
256
|
}
|
|
257
257
|
// Return void (a deleted database has no content)
|
|
@@ -159,28 +159,29 @@ async function migrateLegacySchema(
|
|
|
159
159
|
export async function listMigrationsFiles(
|
|
160
160
|
migrationsDir: string,
|
|
161
161
|
): Promise<Array<{ id: string; sql: string }>> {
|
|
162
|
-
const entries = await
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
const aNum = getPrefix(a);
|
|
168
|
-
const bNum = getPrefix(b);
|
|
162
|
+
const entries = await Array.fromAsync(
|
|
163
|
+
fs.glob("**/*.sql", {
|
|
164
|
+
cwd: migrationsDir,
|
|
165
|
+
}),
|
|
166
|
+
);
|
|
169
167
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
168
|
+
const sqlFiles = entries.sort((a: string, b: string) => {
|
|
169
|
+
const aNum = getPrefix(a);
|
|
170
|
+
const bNum = getPrefix(b);
|
|
173
171
|
|
|
174
|
-
|
|
175
|
-
|
|
172
|
+
if (aNum !== null && bNum !== null) return aNum - bNum;
|
|
173
|
+
if (aNum !== null) return -1;
|
|
174
|
+
if (bNum !== null) return 1;
|
|
176
175
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
const sql = await readMigrationFile(path.join(migrationsDir, file));
|
|
180
|
-
files.push({ id: file, sql });
|
|
181
|
-
}
|
|
176
|
+
return a.localeCompare(b);
|
|
177
|
+
});
|
|
182
178
|
|
|
183
|
-
return
|
|
179
|
+
return await Promise.all(
|
|
180
|
+
sqlFiles.map(async (file) => ({
|
|
181
|
+
id: file,
|
|
182
|
+
sql: await readMigrationFile(path.join(migrationsDir, file)),
|
|
183
|
+
})),
|
|
184
|
+
);
|
|
184
185
|
}
|
|
185
186
|
|
|
186
187
|
/**
|
|
@@ -7,7 +7,7 @@ import assert from "node:assert";
|
|
|
7
7
|
import { assertNever } from "../../util/assert-never.ts";
|
|
8
8
|
import { logger } from "../../util/logger.ts";
|
|
9
9
|
import { Self, type Binding, type WorkerBindingSpec } from "../bindings.ts";
|
|
10
|
-
import type { WorkerBundle } from "../bundle
|
|
10
|
+
import type { WorkerBundle } from "../worker-bundle.ts";
|
|
11
11
|
import type { WorkerProps } from "../worker.ts";
|
|
12
12
|
|
|
13
13
|
export type MiniflareWorkerOptions = Pick<
|
|
@@ -208,30 +208,44 @@ function buildRemoteBinding(
|
|
|
208
208
|
}
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
-
|
|
211
|
+
const moduleTypes = {
|
|
212
|
+
esm: "ESModule",
|
|
213
|
+
cjs: "CommonJS",
|
|
214
|
+
text: "Text",
|
|
215
|
+
data: "Data",
|
|
216
|
+
wasm: "CompiledWasm",
|
|
217
|
+
sourcemap: "Text",
|
|
218
|
+
} as const;
|
|
219
|
+
|
|
220
|
+
function parseModules(bundle: WorkerBundle) {
|
|
221
|
+
const modules = bundle.modules.map((module) => ({
|
|
222
|
+
type: moduleTypes[module.type],
|
|
223
|
+
path: module.path,
|
|
224
|
+
contents: module.content,
|
|
225
|
+
}));
|
|
226
|
+
const entry = modules.find((module) => module.path === bundle.entrypoint);
|
|
227
|
+
if (!entry) {
|
|
228
|
+
throw new Error(`Entrypoint "${bundle.entrypoint}" not found in bundle.`);
|
|
229
|
+
}
|
|
230
|
+
return [entry, ...modules.filter((module) => module.path !== entry.path)];
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export function buildMiniflareWorkerOptions({
|
|
212
234
|
name: workerName,
|
|
213
235
|
assets,
|
|
214
236
|
bundle,
|
|
215
237
|
bindings,
|
|
216
|
-
format,
|
|
217
238
|
eventSources,
|
|
218
239
|
compatibilityDate,
|
|
219
240
|
compatibilityFlags,
|
|
220
241
|
remoteProxyConnectionString,
|
|
221
242
|
}: MiniflareWorkerOptions & {
|
|
222
243
|
remoteProxyConnectionString: RemoteProxyConnectionString | undefined;
|
|
223
|
-
}):
|
|
244
|
+
}): WorkerOptions {
|
|
224
245
|
const options: WorkerOptions = {
|
|
225
246
|
name: workerName,
|
|
226
|
-
modules:
|
|
227
|
-
|
|
228
|
-
type: (format === "cjs" ? "CommonJS" : "ESModule") as
|
|
229
|
-
| "CommonJS"
|
|
230
|
-
| "ESModule",
|
|
231
|
-
path: file.name,
|
|
232
|
-
contents: await file.text(),
|
|
233
|
-
})),
|
|
234
|
-
),
|
|
247
|
+
modules: parseModules(bundle),
|
|
248
|
+
rootPath: bundle.root,
|
|
235
249
|
compatibilityDate,
|
|
236
250
|
compatibilityFlags,
|
|
237
251
|
// TODO: Setting `proxy: true` here causes the following error when connecting via a websocket:
|
|
@@ -56,7 +56,7 @@ class MiniflareServer {
|
|
|
56
56
|
private async set(worker: MiniflareWorkerOptions) {
|
|
57
57
|
this.workers.set(
|
|
58
58
|
worker.name,
|
|
59
|
-
|
|
59
|
+
buildMiniflareWorkerOptions({
|
|
60
60
|
...worker,
|
|
61
61
|
remoteProxyConnectionString: await this.maybeCreateRemoteProxy(worker),
|
|
62
62
|
}),
|
|
@@ -69,9 +69,7 @@ class MiniflareServer {
|
|
|
69
69
|
// Miniflare intercepts SIGINT and exits with 130, which is not a failure.
|
|
70
70
|
// No one likes to see a non-zero exit code when they Ctrl+C, so here's our workaround.
|
|
71
71
|
process.on("exit", (code) => {
|
|
72
|
-
|
|
73
|
-
process.exit(0);
|
|
74
|
-
}
|
|
72
|
+
process.exit(code === 130 ? 0 : code);
|
|
75
73
|
});
|
|
76
74
|
this.miniflare = new miniflare.Miniflare(await this.miniflareOptions());
|
|
77
75
|
await withErrorRewrite(this.miniflare.ready);
|
|
@@ -4,6 +4,7 @@ import { extractCloudflareResult } from "../api-response.ts";
|
|
|
4
4
|
import { createCloudflareApi, type CloudflareApi } from "../api.ts";
|
|
5
5
|
import type { WorkerBindingSpec } from "../bindings.ts";
|
|
6
6
|
import { getInternalWorkerBundle } from "../bundle/internal-worker-bundle.ts";
|
|
7
|
+
import { WorkerBundle } from "../worker-bundle.ts";
|
|
7
8
|
import type { WorkerMetadata } from "../worker-metadata.ts";
|
|
8
9
|
|
|
9
10
|
type WranglerSessionConfig =
|
|
@@ -38,14 +39,14 @@ export async function createRemoteProxyWorker(input: {
|
|
|
38
39
|
createWorkersPreviewToken(api, {
|
|
39
40
|
name: input.name,
|
|
40
41
|
metadata: {
|
|
41
|
-
main_module: script.
|
|
42
|
+
main_module: script.bundle.entrypoint,
|
|
42
43
|
compatibility_date: "2025-06-16",
|
|
43
44
|
bindings: input.bindings,
|
|
44
45
|
observability: {
|
|
45
46
|
enabled: false,
|
|
46
47
|
},
|
|
47
48
|
},
|
|
48
|
-
|
|
49
|
+
bundle: script.bundle,
|
|
49
50
|
session: {
|
|
50
51
|
workers_dev: true,
|
|
51
52
|
minimal_mode: true,
|
|
@@ -98,16 +99,13 @@ async function createWorkersPreviewToken(
|
|
|
98
99
|
input: {
|
|
99
100
|
name: string;
|
|
100
101
|
metadata: WorkerMetadata;
|
|
101
|
-
|
|
102
|
+
bundle: WorkerBundle;
|
|
102
103
|
session: WranglerSessionConfig;
|
|
103
104
|
},
|
|
104
105
|
) {
|
|
105
106
|
const session = await createWorkersPreviewSession(api);
|
|
106
|
-
const formData =
|
|
107
|
+
const formData = await WorkerBundle.toFormData(input.bundle);
|
|
107
108
|
formData.append("metadata", JSON.stringify(input.metadata));
|
|
108
|
-
for (const file of input.files) {
|
|
109
|
-
formData.append(file.name, file);
|
|
110
|
-
}
|
|
111
109
|
formData.append("wrangler-session-config", JSON.stringify(input.session));
|
|
112
110
|
const res = await extractCloudflareResult<{ preview_token: string }>(
|
|
113
111
|
"create workers preview token",
|