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.
Files changed (214) hide show
  1. package/bin/alchemy.js +196353 -0
  2. package/bin/alchemy.ts +2 -2
  3. package/bin/commands/init.ts +1190 -0
  4. package/bin/constants.ts +18 -0
  5. package/bin/services/execute-alchemy.ts +7 -2
  6. package/bin/services/package-manager.ts +1 -1
  7. package/bin/types.ts +14 -5
  8. package/lib/aws/ec2/index.d.ts +10 -0
  9. package/lib/aws/ec2/index.d.ts.map +1 -0
  10. package/lib/aws/ec2/index.js +10 -0
  11. package/lib/aws/ec2/index.js.map +1 -0
  12. package/lib/aws/ec2/internet-gateway-attachment.d.ts +150 -0
  13. package/lib/aws/ec2/internet-gateway-attachment.d.ts.map +1 -0
  14. package/lib/aws/ec2/internet-gateway-attachment.js +248 -0
  15. package/lib/aws/ec2/internet-gateway-attachment.js.map +1 -0
  16. package/lib/aws/ec2/internet-gateway.d.ts +132 -0
  17. package/lib/aws/ec2/internet-gateway.d.ts.map +1 -0
  18. package/lib/aws/ec2/internet-gateway.js +311 -0
  19. package/lib/aws/ec2/internet-gateway.js.map +1 -0
  20. package/lib/aws/ec2/nat-gateway.d.ts +145 -0
  21. package/lib/aws/ec2/nat-gateway.d.ts.map +1 -0
  22. package/lib/aws/ec2/nat-gateway.js +618 -0
  23. package/lib/aws/ec2/nat-gateway.js.map +1 -0
  24. package/lib/aws/ec2/route-table-association.d.ts +134 -0
  25. package/lib/aws/ec2/route-table-association.d.ts.map +1 -0
  26. package/lib/aws/ec2/route-table-association.js +364 -0
  27. package/lib/aws/ec2/route-table-association.js.map +1 -0
  28. package/lib/aws/ec2/route-table.d.ts +94 -0
  29. package/lib/aws/ec2/route-table.d.ts.map +1 -0
  30. package/lib/aws/ec2/route-table.js +253 -0
  31. package/lib/aws/ec2/route-table.js.map +1 -0
  32. package/lib/aws/ec2/route.d.ts +130 -0
  33. package/lib/aws/ec2/route.d.ts.map +1 -0
  34. package/lib/aws/ec2/route.js +253 -0
  35. package/lib/aws/ec2/route.js.map +1 -0
  36. package/lib/aws/ec2/security-group-rule.d.ts +84 -0
  37. package/lib/aws/ec2/security-group-rule.d.ts.map +1 -0
  38. package/lib/aws/ec2/security-group-rule.js +123 -0
  39. package/lib/aws/ec2/security-group-rule.js.map +1 -0
  40. package/lib/aws/ec2/security-group.d.ts +84 -0
  41. package/lib/aws/ec2/security-group.d.ts.map +1 -0
  42. package/lib/aws/ec2/security-group.js +207 -0
  43. package/lib/aws/ec2/security-group.js.map +1 -0
  44. package/lib/aws/ec2/subnet.d.ts +110 -0
  45. package/lib/aws/ec2/subnet.d.ts.map +1 -0
  46. package/lib/aws/ec2/subnet.js +336 -0
  47. package/lib/aws/ec2/subnet.js.map +1 -0
  48. package/lib/aws/ec2/utils.d.ts +15 -0
  49. package/lib/aws/ec2/utils.d.ts.map +1 -0
  50. package/lib/aws/ec2/utils.js +79 -0
  51. package/lib/aws/ec2/utils.js.map +1 -0
  52. package/lib/aws/ec2/vpc.d.ts +160 -0
  53. package/lib/aws/ec2/vpc.d.ts.map +1 -0
  54. package/lib/aws/ec2/vpc.js +453 -0
  55. package/lib/aws/ec2/vpc.js.map +1 -0
  56. package/lib/aws/index.d.ts +7 -0
  57. package/lib/aws/index.d.ts.map +1 -1
  58. package/lib/aws/index.js +8 -0
  59. package/lib/aws/index.js.map +1 -1
  60. package/lib/aws/utils.d.ts +25 -0
  61. package/lib/aws/utils.d.ts.map +1 -0
  62. package/lib/aws/utils.js +89 -0
  63. package/lib/aws/utils.js.map +1 -0
  64. package/lib/build-date.d.ts +6 -0
  65. package/lib/build-date.d.ts.map +1 -0
  66. package/lib/build-date.js +8 -0
  67. package/lib/build-date.js.map +1 -0
  68. package/lib/cloudflare/astro.d.ts.map +1 -1
  69. package/lib/cloudflare/astro.js +4 -3
  70. package/lib/cloudflare/astro.js.map +1 -1
  71. package/lib/cloudflare/bundle/externals.d.ts +3 -0
  72. package/lib/cloudflare/bundle/externals.d.ts.map +1 -0
  73. package/lib/cloudflare/bundle/externals.js +35 -0
  74. package/lib/cloudflare/bundle/externals.js.map +1 -0
  75. package/lib/cloudflare/bundle/internal-worker-bundle.d.ts +8 -1
  76. package/lib/cloudflare/bundle/internal-worker-bundle.d.ts.map +1 -1
  77. package/lib/cloudflare/bundle/internal-worker-bundle.js +11 -4
  78. package/lib/cloudflare/bundle/internal-worker-bundle.js.map +1 -1
  79. package/lib/cloudflare/bundle/plugin-hot-reload.d.ts +4 -1
  80. package/lib/cloudflare/bundle/plugin-hot-reload.d.ts.map +1 -1
  81. package/lib/cloudflare/bundle/plugin-hot-reload.js +27 -11
  82. package/lib/cloudflare/bundle/plugin-hot-reload.js.map +1 -1
  83. package/lib/cloudflare/bundle/plugin-hybrid-node-compat.js +5 -1
  84. package/lib/cloudflare/bundle/plugin-hybrid-node-compat.js.map +1 -1
  85. package/lib/cloudflare/bundle/plugin-wasm.d.ts +6 -2
  86. package/lib/cloudflare/bundle/plugin-wasm.d.ts.map +1 -1
  87. package/lib/cloudflare/bundle/plugin-wasm.js +21 -47
  88. package/lib/cloudflare/bundle/plugin-wasm.js.map +1 -1
  89. package/lib/cloudflare/bundle/validate-node-compat.d.ts +2 -1
  90. package/lib/cloudflare/bundle/validate-node-compat.d.ts.map +1 -1
  91. package/lib/cloudflare/bundle/validate-node-compat.js +5 -4
  92. package/lib/cloudflare/bundle/validate-node-compat.js.map +1 -1
  93. package/lib/cloudflare/compatibility-date.gen.d.ts +1 -1
  94. package/lib/cloudflare/compatibility-date.gen.js +1 -1
  95. package/lib/cloudflare/d1-database.js +1 -1
  96. package/lib/cloudflare/d1-database.js.map +1 -1
  97. package/lib/cloudflare/d1-migrations.d.ts.map +1 -1
  98. package/lib/cloudflare/d1-migrations.js +8 -10
  99. package/lib/cloudflare/d1-migrations.js.map +1 -1
  100. package/lib/cloudflare/miniflare/miniflare-worker-options.d.ts +3 -3
  101. package/lib/cloudflare/miniflare/miniflare-worker-options.d.ts.map +1 -1
  102. package/lib/cloudflare/miniflare/miniflare-worker-options.js +23 -6
  103. package/lib/cloudflare/miniflare/miniflare-worker-options.js.map +1 -1
  104. package/lib/cloudflare/miniflare/miniflare.d.ts.map +1 -1
  105. package/lib/cloudflare/miniflare/miniflare.js +2 -4
  106. package/lib/cloudflare/miniflare/miniflare.js.map +1 -1
  107. package/lib/cloudflare/miniflare/remote-binding-proxy.d.ts.map +1 -1
  108. package/lib/cloudflare/miniflare/remote-binding-proxy.js +4 -6
  109. package/lib/cloudflare/miniflare/remote-binding-proxy.js.map +1 -1
  110. package/lib/cloudflare/react-router.d.ts +4 -0
  111. package/lib/cloudflare/react-router.d.ts.map +1 -1
  112. package/lib/cloudflare/react-router.js +8 -5
  113. package/lib/cloudflare/react-router.js.map +1 -1
  114. package/lib/cloudflare/worker-bundle.d.ts +80 -0
  115. package/lib/cloudflare/worker-bundle.d.ts.map +1 -0
  116. package/lib/cloudflare/worker-bundle.js +266 -0
  117. package/lib/cloudflare/worker-bundle.js.map +1 -0
  118. package/lib/cloudflare/worker.d.ts +1 -1
  119. package/lib/cloudflare/worker.d.ts.map +1 -1
  120. package/lib/cloudflare/worker.js +81 -195
  121. package/lib/cloudflare/worker.js.map +1 -1
  122. package/lib/esbuild/bundle.d.ts +1 -0
  123. package/lib/esbuild/bundle.d.ts.map +1 -1
  124. package/lib/state/cloudflare-state-store.js +1 -5
  125. package/lib/state/cloudflare-state-store.js.map +1 -1
  126. package/lib/state/dofs-state-store/store.d.ts.map +1 -1
  127. package/lib/state/dofs-state-store/store.js +4 -4
  128. package/lib/state/dofs-state-store/store.js.map +1 -1
  129. package/lib/util/params.d.ts +5 -0
  130. package/lib/util/params.d.ts.map +1 -0
  131. package/lib/util/params.js +30 -0
  132. package/lib/util/params.js.map +1 -0
  133. package/lib/util/timeout.d.ts +31 -0
  134. package/lib/util/timeout.d.ts.map +1 -0
  135. package/lib/util/timeout.js +109 -0
  136. package/lib/util/timeout.js.map +1 -0
  137. package/lib/util/xml.d.ts +5 -0
  138. package/lib/util/xml.d.ts.map +1 -0
  139. package/lib/util/xml.js +8 -0
  140. package/lib/util/xml.js.map +1 -0
  141. package/package.json +12 -5
  142. package/src/aws/ec2/index.ts +9 -0
  143. package/src/aws/ec2/internet-gateway-attachment.ts +468 -0
  144. package/src/aws/ec2/internet-gateway.ts +557 -0
  145. package/src/aws/ec2/nat-gateway.ts +1123 -0
  146. package/src/aws/ec2/route-table-association.ts +747 -0
  147. package/src/aws/ec2/route-table.ts +452 -0
  148. package/src/aws/ec2/route.ts +447 -0
  149. package/src/aws/ec2/security-group-rule.ts +229 -0
  150. package/src/aws/ec2/security-group.ts +418 -0
  151. package/src/aws/ec2/subnet.ts +625 -0
  152. package/src/aws/ec2/utils.ts +102 -0
  153. package/src/aws/ec2/vpc.ts +969 -0
  154. package/src/aws/index.ts +9 -0
  155. package/src/aws/utils.ts +137 -0
  156. package/src/build-date.ts +8 -0
  157. package/src/cloudflare/astro.ts +4 -3
  158. package/src/cloudflare/bundle/externals.ts +36 -0
  159. package/src/cloudflare/bundle/internal-worker-bundle.ts +12 -3
  160. package/src/cloudflare/bundle/plugin-hot-reload.ts +32 -12
  161. package/src/cloudflare/bundle/plugin-hybrid-node-compat.ts +6 -1
  162. package/src/cloudflare/bundle/plugin-wasm.ts +26 -54
  163. package/src/cloudflare/bundle/validate-node-compat.ts +6 -5
  164. package/src/cloudflare/compatibility-date.gen.ts +1 -1
  165. package/src/cloudflare/d1-database.ts +1 -1
  166. package/src/cloudflare/d1-migrations.ts +19 -18
  167. package/src/cloudflare/miniflare/miniflare-worker-options.ts +27 -13
  168. package/src/cloudflare/miniflare/miniflare.ts +2 -4
  169. package/src/cloudflare/miniflare/remote-binding-proxy.ts +5 -7
  170. package/src/cloudflare/react-router.ts +14 -6
  171. package/src/cloudflare/worker-bundle.ts +364 -0
  172. package/src/cloudflare/worker.ts +104 -241
  173. package/src/state/cloudflare-state-store.ts +1 -5
  174. package/src/state/dofs-state-store/store.ts +4 -4
  175. package/src/util/params.ts +33 -0
  176. package/src/util/timeout.ts +178 -0
  177. package/src/util/xml.ts +7 -0
  178. package/templates/nuxt/package.json +1 -1
  179. package/templates/nuxt/types/env.d.ts +11 -0
  180. package/templates/react-router/workers/app.ts +2 -2
  181. package/templates/rwsdk/.cursor/rules/alchemy_cloudflare.mdc +385 -0
  182. package/templates/rwsdk/wrangler.jsonc +10 -7
  183. package/templates/typescript/tsconfig.json +1 -2
  184. package/bin/alchemy.mjs +0 -51766
  185. package/lib/cloudflare/bundle/esbuild.d.ts +0 -16
  186. package/lib/cloudflare/bundle/esbuild.d.ts.map +0 -1
  187. package/lib/cloudflare/bundle/esbuild.js +0 -159
  188. package/lib/cloudflare/bundle/esbuild.js.map +0 -1
  189. package/lib/cloudflare/bundle/fs.d.ts +0 -18
  190. package/lib/cloudflare/bundle/fs.d.ts.map +0 -1
  191. package/lib/cloudflare/bundle/fs.js +0 -78
  192. package/lib/cloudflare/bundle/fs.js.map +0 -1
  193. package/lib/cloudflare/bundle/index.d.ts +0 -3
  194. package/lib/cloudflare/bundle/index.d.ts.map +0 -1
  195. package/lib/cloudflare/bundle/index.js +0 -2
  196. package/lib/cloudflare/bundle/index.js.map +0 -1
  197. package/lib/cloudflare/bundle/inline.d.ts +0 -12
  198. package/lib/cloudflare/bundle/inline.d.ts.map +0 -1
  199. package/lib/cloudflare/bundle/inline.js +0 -32
  200. package/lib/cloudflare/bundle/inline.js.map +0 -1
  201. package/lib/cloudflare/bundle/normalize.d.ts +0 -21
  202. package/lib/cloudflare/bundle/normalize.d.ts.map +0 -1
  203. package/lib/cloudflare/bundle/normalize.js +0 -49
  204. package/lib/cloudflare/bundle/normalize.js.map +0 -1
  205. package/lib/cloudflare/bundle/shared.d.ts +0 -30
  206. package/lib/cloudflare/bundle/shared.d.ts.map +0 -1
  207. package/lib/cloudflare/bundle/shared.js +0 -34
  208. package/lib/cloudflare/bundle/shared.js.map +0 -1
  209. package/src/cloudflare/bundle/esbuild.ts +0 -194
  210. package/src/cloudflare/bundle/fs.ts +0 -103
  211. package/src/cloudflare/bundle/index.ts +0 -6
  212. package/src/cloudflare/bundle/inline.ts +0 -42
  213. package/src/cloudflare/bundle/normalize.ts +0 -76
  214. package/src/cloudflare/bundle/shared.ts +0 -73
@@ -4,7 +4,12 @@ import type { Bindings } from "./bindings.js";
4
4
  import { Website, type WebsiteProps } from "./website.js";
5
5
  import type { Worker } from "./worker.js";
6
6
 
7
- export interface ReactRouterProps<B extends Bindings> extends WebsiteProps<B> {}
7
+ export interface ReactRouterProps<B extends Bindings> extends WebsiteProps<B> {
8
+ /**
9
+ * @default workers/app.ts
10
+ */
11
+ main?: string;
12
+ }
8
13
 
9
14
  // don't allow the ASSETS to be overriden
10
15
  export type ReactRouter<B extends Bindings> = B extends { ASSETS: any }
@@ -16,8 +21,14 @@ export async function ReactRouter<B extends Bindings>(
16
21
  props: ReactRouterProps<B>,
17
22
  ): Promise<ReactRouter<B>> {
18
23
  const defaultAssets = path.join("build", "client");
24
+ const main = props.main ?? path.join("workers", "app.ts");
19
25
  return Website(id, {
20
26
  ...props,
27
+ command: props.command ?? "react-router typegen && react-router build",
28
+ dev: props.dev ?? {
29
+ command: "react-router typegen && react-router dev",
30
+ },
31
+ compatibility: "node",
21
32
  // Alchemy should bundle the result of `vite build`, not the user's main
22
33
  // TODO: we probably need bundling to properly handle WASM/rules
23
34
  main: path.join(props.cwd ?? process.cwd(), "build", "server", "index.js"),
@@ -25,8 +36,8 @@ export async function ReactRouter<B extends Bindings>(
25
36
  // wrangler should point to the user's main (e.g. `worker.ts`), unless overridden
26
37
  main:
27
38
  typeof props.wrangler === "object"
28
- ? (props.wrangler.main ?? props.main)
29
- : props.main,
39
+ ? (props.wrangler.main ?? main)
40
+ : main,
30
41
  // write to wrangler.json by default but respect overrides
31
42
  path:
32
43
  typeof props.wrangler === "string"
@@ -41,8 +52,5 @@ export async function ReactRouter<B extends Bindings>(
41
52
  dist: props.assets.dist ?? defaultAssets,
42
53
  }
43
54
  : (props.assets ?? defaultAssets),
44
- dev: props.dev ?? {
45
- command: "react-router dev",
46
- },
47
55
  });
48
56
  }
@@ -0,0 +1,364 @@
1
+ import esbuild from "esbuild";
2
+ import { err, ok, type Result } from "neverthrow";
3
+ import fs from "node:fs/promises";
4
+ import path from "node:path";
5
+ import { external, external_als } from "./bundle/externals.ts";
6
+ import { esbuildPluginCompatWarning } from "./bundle/plugin-compat-warning.ts";
7
+ import { createHotReloadPlugin } from "./bundle/plugin-hot-reload.ts";
8
+ import { esbuildPluginHybridNodeCompat } from "./bundle/plugin-hybrid-node-compat.ts";
9
+ import { createWasmPlugin } from "./bundle/plugin-wasm.ts";
10
+ import { validateNodeCompat } from "./bundle/validate-node-compat.ts";
11
+
12
+ export interface WorkerBundle {
13
+ entrypoint: string;
14
+ root?: string;
15
+ modules: WorkerBundle.Module[];
16
+ }
17
+
18
+ export function normalizeWorkerBundle(props: {
19
+ script: string | undefined;
20
+ entrypoint: string | undefined;
21
+ noBundle: boolean | undefined;
22
+ format: "cjs" | "esm" | undefined;
23
+ compatibilityDate: string;
24
+ compatibilityFlags: string[];
25
+ rules:
26
+ | {
27
+ globs: string[];
28
+ }[]
29
+ | undefined;
30
+ bundle?: Omit<
31
+ esbuild.BuildOptions,
32
+ "entryPoints" | "format" | "absWorkingDir"
33
+ >;
34
+ cwd: string;
35
+ outdir: string;
36
+ sourceMap: boolean | undefined;
37
+ }): Result<WorkerBundleSource, string> {
38
+ return validateNodeCompat({
39
+ compatibilityDate: props.compatibilityDate,
40
+ compatibilityFlags: props.compatibilityFlags,
41
+ noBundle: props.noBundle ?? false,
42
+ }).andThen((nodeCompat) => {
43
+ if (props.script) {
44
+ return ok(
45
+ new WorkerBundleSource.Inline({
46
+ content: props.script,
47
+ format: props.format ?? "esm",
48
+ nodeCompat,
49
+ }),
50
+ );
51
+ }
52
+ if (!props.entrypoint) {
53
+ return err(
54
+ "Either `script` or `entrypoint` must be provided for workers",
55
+ );
56
+ }
57
+ return ok(
58
+ props.noBundle
59
+ ? new WorkerBundleSource.FS({
60
+ entrypoint: props.entrypoint,
61
+ format: props.format ?? "esm",
62
+ nodeCompat,
63
+ cwd: props.cwd,
64
+ globs: props.rules?.flatMap((rule) => rule.globs),
65
+ sourcemaps: props.sourceMap !== false,
66
+ })
67
+ : new WorkerBundleSource.ESBuild({
68
+ entrypoint: props.entrypoint,
69
+ format: props.format ?? "esm",
70
+ nodeCompat,
71
+ cwd: props.cwd,
72
+ outdir: props.outdir,
73
+ sourcemap: props.sourceMap !== false ? "linked" : undefined,
74
+ ...props.bundle,
75
+ }),
76
+ );
77
+ });
78
+ }
79
+
80
+ export namespace WorkerBundle {
81
+ export interface Module {
82
+ type: "esm" | "cjs" | "text" | "data" | "wasm" | "sourcemap";
83
+ path: string;
84
+ content?: string | Uint8Array<ArrayBuffer>;
85
+ }
86
+
87
+ export const parseModules = (
88
+ paths: string[],
89
+ format: "esm" | "cjs",
90
+ ): WorkerBundle.Module[] => {
91
+ return paths.map((path) => {
92
+ const ext = path.split(".").pop();
93
+ switch (ext) {
94
+ case "js":
95
+ return { type: format, path };
96
+ case "mjs":
97
+ return { type: "esm", path };
98
+ case "cjs":
99
+ return { type: "cjs", path };
100
+ case "wasm":
101
+ return { type: "wasm", path };
102
+ case "map":
103
+ return { type: "sourcemap", path };
104
+ default:
105
+ return { type: "text", path };
106
+ }
107
+ });
108
+ };
109
+
110
+ export const toFormData = async (bundle: WorkerBundle) => {
111
+ const types = {
112
+ esm: "application/javascript+module",
113
+ cjs: "application/javascript",
114
+ text: "text/plain",
115
+ data: "application/octet-stream",
116
+ wasm: "application/wasm",
117
+ sourcemap: "application/source-map",
118
+ } as const;
119
+ const form = new FormData();
120
+ await Promise.all(
121
+ bundle.modules.map(async (module) => {
122
+ const content =
123
+ module.content ??
124
+ (await fs.readFile(path.join(bundle.root!, module.path)));
125
+ form.append(
126
+ module.path,
127
+ new Blob([content], {
128
+ type: types[module.type],
129
+ }),
130
+ module.path,
131
+ );
132
+ }),
133
+ );
134
+ return form;
135
+ };
136
+ }
137
+
138
+ export interface WorkerBundleSource {
139
+ create(): Promise<WorkerBundle>;
140
+ watch(signal: AbortSignal): AsyncIterable<WorkerBundle>;
141
+ delete?(): Promise<void>;
142
+ }
143
+
144
+ export namespace WorkerBundleSource {
145
+ export interface BaseProps {
146
+ format: "cjs" | "esm";
147
+ nodeCompat: "als" | "v2" | null;
148
+ }
149
+
150
+ export class Inline implements WorkerBundleSource {
151
+ constructor(
152
+ private props: WorkerBundleSource.BaseProps & { content: string },
153
+ ) {}
154
+
155
+ async create(): Promise<WorkerBundle> {
156
+ return {
157
+ entrypoint: "worker.js",
158
+ modules: [
159
+ {
160
+ path: "worker.js",
161
+ type: this.props.format,
162
+ content: this.props.content,
163
+ },
164
+ ],
165
+ };
166
+ }
167
+
168
+ async *watch(): AsyncIterable<WorkerBundle> {
169
+ yield await this.create();
170
+ }
171
+ }
172
+
173
+ export class FS implements WorkerBundleSource {
174
+ private root: string;
175
+ private entrypoint: string;
176
+ private globs: string[];
177
+ private format: "esm" | "cjs";
178
+
179
+ constructor(
180
+ props: WorkerBundleSource.BaseProps & {
181
+ entrypoint: string;
182
+ globs: string[] | undefined;
183
+ cwd: string;
184
+ sourcemaps: boolean;
185
+ },
186
+ ) {
187
+ const entrypoint = path.resolve(props.cwd, props.entrypoint);
188
+ this.root = path.dirname(entrypoint);
189
+ this.entrypoint = path.relative(this.root, entrypoint);
190
+ this.globs = props.globs ?? [
191
+ "**/*.js",
192
+ "**/*.mjs",
193
+ "**/*.wasm",
194
+ ...(props.sourcemaps ? ["**/*.js.map"] : []),
195
+ ];
196
+ this.format = props.format;
197
+ }
198
+
199
+ async create(): Promise<WorkerBundle> {
200
+ return {
201
+ entrypoint: this.entrypoint,
202
+ root: this.root,
203
+ modules: await this.readFiles(),
204
+ };
205
+ }
206
+
207
+ async *watch(signal: AbortSignal): AsyncIterable<WorkerBundle> {
208
+ const watcher = fs.watch(this.root, { recursive: true, signal });
209
+ for await (const event of watcher) {
210
+ if (event.eventType === "change") {
211
+ yield await this.create();
212
+ }
213
+ }
214
+ }
215
+
216
+ private async readFiles() {
217
+ const fileNames = new Set<string>();
218
+ await Promise.all(
219
+ this.globs.map(async (glob) => {
220
+ for await (const file of fs.glob(glob, { cwd: this.root })) {
221
+ fileNames.add(file);
222
+ }
223
+ }),
224
+ );
225
+ if (fileNames.size === 0) {
226
+ throw new Error(
227
+ `No files found matching ${this.globs.join(", ")} in ${this.root}`,
228
+ );
229
+ }
230
+ return WorkerBundle.parseModules(Array.from(fileNames), this.format);
231
+ }
232
+ }
233
+
234
+ export interface ESBuildProps
235
+ extends WorkerBundleSource.BaseProps,
236
+ Omit<
237
+ esbuild.BuildOptions,
238
+ "entryPoints" | "format" | "absWorkingDir" | "outdir"
239
+ > {
240
+ entrypoint: string;
241
+ cwd: string;
242
+ outdir: string;
243
+ }
244
+
245
+ export class ESBuild implements WorkerBundleSource {
246
+ constructor(private props: ESBuildProps) {
247
+ // Normalize paths to ensure consistency between esbuild inputs and outputs:
248
+ // - the `cwd` is absolute
249
+ // - the `entrypoint` and `outdir` are relative to the `cwd`
250
+ // This is so we can identify the entrypoint from the metafile.
251
+ this.props.cwd = path.resolve(this.props.cwd);
252
+ this.props.entrypoint = path.isAbsolute(props.entrypoint)
253
+ ? path.relative(this.props.cwd, props.entrypoint)
254
+ : path.normalize(props.entrypoint);
255
+ this.props.outdir = path.isAbsolute(props.outdir)
256
+ ? path.relative(this.props.cwd, props.outdir)
257
+ : path.normalize(props.outdir);
258
+ }
259
+
260
+ async create(): Promise<WorkerBundle> {
261
+ const wasmPlugin = createWasmPlugin();
262
+ const options = this.buildOptions([wasmPlugin.plugin]);
263
+ const result = await esbuild.build(options);
264
+ const { entrypoint, root, modules } = this.resolveBuildOutput(
265
+ result.metafile,
266
+ );
267
+ return {
268
+ entrypoint,
269
+ root,
270
+ modules: [...modules, ...wasmPlugin.modules.values()],
271
+ };
272
+ }
273
+
274
+ async *watch(signal: AbortSignal): AsyncIterable<WorkerBundle> {
275
+ const wasm = createWasmPlugin();
276
+ const hotReload = createHotReloadPlugin();
277
+ const options = this.buildOptions([wasm.plugin, hotReload.plugin]);
278
+
279
+ const context = await esbuild.context(options);
280
+ signal.addEventListener("abort", () => context.dispose());
281
+ await context.watch();
282
+
283
+ for await (const result of hotReload.iterator) {
284
+ const { entrypoint, root, modules } = this.resolveBuildOutput(
285
+ result.metafile!,
286
+ );
287
+ yield {
288
+ entrypoint,
289
+ root,
290
+ modules: [...modules, ...wasm.modules.values()],
291
+ };
292
+ }
293
+ }
294
+
295
+ async delete(): Promise<void> {
296
+ await fs.rm(path.join(this.props.cwd, this.props.outdir), {
297
+ recursive: true,
298
+ force: true,
299
+ });
300
+ }
301
+
302
+ private buildOptions(additionalPlugins: esbuild.Plugin[]) {
303
+ const { entrypoint, nodeCompat, cwd, format, ...props } = this.props;
304
+ return {
305
+ entryPoints: [entrypoint],
306
+ absWorkingDir: cwd,
307
+ format,
308
+ target: "esnext",
309
+ ...props,
310
+ metafile: true,
311
+ write: true,
312
+ bundle: true,
313
+ conditions: props.conditions ?? ["workerd", "worker", "browser"],
314
+ mainFields: props.mainFields,
315
+ loader: {
316
+ ".sql": "text",
317
+ ".json": "json",
318
+ ".wasm": "binary",
319
+ ...props.loader,
320
+ },
321
+ plugins: [
322
+ nodeCompat === "v2"
323
+ ? esbuildPluginHybridNodeCompat()
324
+ : esbuildPluginCompatWarning(nodeCompat ?? null),
325
+ ...(props.plugins ?? []),
326
+ ...additionalPlugins,
327
+ ],
328
+ alias: props.alias,
329
+ external: [
330
+ ...(nodeCompat === "als" ? external_als : external),
331
+ ...(props.external ?? []),
332
+ ],
333
+ } satisfies esbuild.BuildOptions;
334
+ }
335
+
336
+ private resolveBuildOutput(metafile: esbuild.Metafile): WorkerBundle {
337
+ const outdir = path.resolve(this.props.cwd, this.props.outdir);
338
+ const paths: string[] = [];
339
+ let entrypoint: string | undefined;
340
+ for (const [key, value] of Object.entries(metafile.outputs)) {
341
+ const name = path.relative(outdir, path.resolve(this.props.cwd, key));
342
+ paths.push(name);
343
+ if (value.entryPoint === this.props.entrypoint) {
344
+ entrypoint = name;
345
+ }
346
+ }
347
+ if (!entrypoint) {
348
+ throw new Error(
349
+ `Failed to find entrypoint in metafile - expected ${this.props.entrypoint} but found ${Object.values(
350
+ metafile.outputs,
351
+ )
352
+ .map((v) => v.entryPoint)
353
+ .filter((v) => v !== undefined)
354
+ .join(", ")}`,
355
+ );
356
+ }
357
+ return {
358
+ entrypoint,
359
+ root: outdir,
360
+ modules: WorkerBundle.parseModules(paths, this.props.format),
361
+ };
362
+ }
363
+ }
364
+ }