alchemy 0.1.11 → 0.1.12

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 (277) hide show
  1. package/README.md +324 -0
  2. package/lib/apply.d.ts +2 -2
  3. package/lib/apply.d.ts.map +1 -1
  4. package/lib/apply.js +2 -2
  5. package/lib/apply.js.map +1 -1
  6. package/lib/aws/index.d.ts +1 -0
  7. package/lib/aws/index.d.ts.map +1 -1
  8. package/lib/aws/index.js +1 -0
  9. package/lib/aws/index.js.map +1 -1
  10. package/lib/aws/ses.d.ts +75 -0
  11. package/lib/aws/ses.d.ts.map +1 -0
  12. package/lib/aws/ses.js +197 -0
  13. package/lib/aws/ses.js.map +1 -0
  14. package/lib/cloudflare/api.d.ts +84 -0
  15. package/lib/cloudflare/api.d.ts.map +1 -0
  16. package/lib/cloudflare/api.js +178 -0
  17. package/lib/cloudflare/api.js.map +1 -0
  18. package/lib/cloudflare/asset-manifest.d.ts +15 -0
  19. package/lib/cloudflare/asset-manifest.d.ts.map +1 -0
  20. package/lib/cloudflare/asset-manifest.js +2 -0
  21. package/lib/cloudflare/asset-manifest.js.map +1 -0
  22. package/lib/cloudflare/auth.d.ts +52 -0
  23. package/lib/cloudflare/auth.d.ts.map +1 -0
  24. package/lib/cloudflare/auth.js +114 -0
  25. package/lib/cloudflare/auth.js.map +1 -0
  26. package/lib/cloudflare/bindings.d.ts +244 -0
  27. package/lib/cloudflare/bindings.d.ts.map +1 -0
  28. package/lib/cloudflare/bindings.js +7 -0
  29. package/lib/cloudflare/bindings.js.map +1 -0
  30. package/lib/cloudflare/generate-asset-manifest.d.ts +3 -0
  31. package/lib/cloudflare/generate-asset-manifest.d.ts.map +1 -0
  32. package/lib/cloudflare/generate-asset-manifest.js +69 -0
  33. package/lib/cloudflare/generate-asset-manifest.js.map +1 -0
  34. package/lib/cloudflare/index.d.ts +6 -0
  35. package/lib/cloudflare/index.d.ts.map +1 -0
  36. package/lib/cloudflare/index.js +6 -0
  37. package/lib/cloudflare/index.js.map +1 -0
  38. package/lib/cloudflare/kv-namespace.d.ts +61 -0
  39. package/lib/cloudflare/kv-namespace.d.ts.map +1 -0
  40. package/lib/cloudflare/kv-namespace.js +93 -0
  41. package/lib/cloudflare/kv-namespace.js.map +1 -0
  42. package/lib/cloudflare/state.d.ts +83 -0
  43. package/lib/cloudflare/state.d.ts.map +1 -0
  44. package/lib/cloudflare/state.js +109 -0
  45. package/lib/cloudflare/state.js.map +1 -0
  46. package/lib/cloudflare/static-site-router.d.ts +10 -0
  47. package/lib/cloudflare/static-site-router.d.ts.map +1 -0
  48. package/lib/cloudflare/static-site-router.js +88 -0
  49. package/lib/cloudflare/static-site-router.js.map +1 -0
  50. package/lib/cloudflare/static-site.d.ts +166 -0
  51. package/lib/cloudflare/static-site.d.ts.map +1 -0
  52. package/lib/cloudflare/static-site.js +152 -0
  53. package/lib/cloudflare/static-site.js.map +1 -0
  54. package/lib/cloudflare/types.d.ts +52 -0
  55. package/lib/cloudflare/types.d.ts.map +1 -0
  56. package/lib/cloudflare/types.js +21 -0
  57. package/lib/cloudflare/types.js.map +1 -0
  58. package/lib/cloudflare/upload-asset-manifest.d.ts +12 -0
  59. package/lib/cloudflare/upload-asset-manifest.d.ts.map +1 -0
  60. package/lib/cloudflare/upload-asset-manifest.js +55 -0
  61. package/lib/cloudflare/upload-asset-manifest.js.map +1 -0
  62. package/lib/cloudflare/worker.d.ts +87 -0
  63. package/lib/cloudflare/worker.d.ts.map +1 -0
  64. package/lib/cloudflare/worker.js +364 -0
  65. package/lib/cloudflare/worker.js.map +1 -0
  66. package/lib/esbuild.d.ts +82 -0
  67. package/lib/esbuild.d.ts.map +1 -1
  68. package/lib/esbuild.js +24 -17
  69. package/lib/esbuild.js.map +1 -1
  70. package/lib/fs.d.ts +1 -1
  71. package/lib/global.d.ts.map +1 -1
  72. package/lib/global.js +3 -1
  73. package/lib/global.js.map +1 -1
  74. package/lib/index.d.ts +0 -1
  75. package/lib/index.d.ts.map +1 -1
  76. package/lib/index.js +0 -1
  77. package/lib/index.js.map +1 -1
  78. package/lib/main.js +1 -1
  79. package/lib/main.js.map +1 -1
  80. package/lib/output.d.ts +17 -13
  81. package/lib/output.d.ts.map +1 -1
  82. package/lib/output.js +2 -2
  83. package/lib/output.js.map +1 -1
  84. package/lib/resource.d.ts +3 -2
  85. package/lib/resource.d.ts.map +1 -1
  86. package/lib/resource.js +2 -2
  87. package/lib/resource.js.map +1 -1
  88. package/lib/utils/content-type.d.ts +8 -0
  89. package/lib/utils/content-type.d.ts.map +1 -0
  90. package/lib/utils/content-type.js +41 -0
  91. package/lib/utils/content-type.js.map +1 -0
  92. package/package.json +26 -8
  93. package/src/apply.ts +5 -5
  94. package/src/aws/index.ts +1 -0
  95. package/src/aws/ses.ts +346 -0
  96. package/src/cloudflare/api.ts +276 -0
  97. package/src/cloudflare/asset-manifest.ts +16 -0
  98. package/src/cloudflare/auth.ts +187 -0
  99. package/src/cloudflare/bindings.ts +286 -0
  100. package/src/cloudflare/generate-asset-manifest.ts +93 -0
  101. package/src/cloudflare/index.ts +5 -0
  102. package/src/cloudflare/kv-namespace.ts +195 -0
  103. package/src/cloudflare/state.ts +138 -0
  104. package/src/cloudflare/static-site-router.ts +108 -0
  105. package/src/cloudflare/static-site.ts +379 -0
  106. package/src/cloudflare/types.ts +71 -0
  107. package/src/cloudflare/upload-asset-manifest.ts +83 -0
  108. package/src/cloudflare/worker.ts +568 -0
  109. package/src/esbuild.ts +31 -22
  110. package/src/global.ts +1 -0
  111. package/src/index.ts +0 -1
  112. package/src/main.ts +1 -1
  113. package/src/output.ts +32 -32
  114. package/src/resource.ts +11 -5
  115. package/src/utils/content-type.ts +42 -0
  116. package/lib/$.d.ts +0 -7
  117. package/lib/$.d.ts.map +0 -1
  118. package/lib/$.js +0 -31
  119. package/lib/$.js.map +0 -1
  120. package/lib/agent/ai.d.ts +0 -40
  121. package/lib/agent/ai.d.ts.map +0 -1
  122. package/lib/agent/ai.js +0 -132
  123. package/lib/agent/ai.js.map +0 -1
  124. package/lib/agent/anthropic.d.ts +0 -9
  125. package/lib/agent/anthropic.d.ts.map +0 -1
  126. package/lib/agent/anthropic.js +0 -25
  127. package/lib/agent/anthropic.js.map +0 -1
  128. package/lib/agent/dependencies.d.ts +0 -4
  129. package/lib/agent/dependencies.d.ts.map +0 -1
  130. package/lib/agent/dependencies.js +0 -48
  131. package/lib/agent/dependencies.js.map +0 -1
  132. package/lib/agent/file-context.d.ts +0 -13
  133. package/lib/agent/file-context.d.ts.map +0 -1
  134. package/lib/agent/file-context.js +0 -6
  135. package/lib/agent/file-context.js.map +0 -1
  136. package/lib/agent/index.d.ts +0 -10
  137. package/lib/agent/index.d.ts.map +0 -1
  138. package/lib/agent/index.js +0 -10
  139. package/lib/agent/index.js.map +0 -1
  140. package/lib/agent/model.d.ts +0 -8
  141. package/lib/agent/model.d.ts.map +0 -1
  142. package/lib/agent/model.js +0 -29
  143. package/lib/agent/model.js.map +0 -1
  144. package/lib/agent/module.d.ts +0 -81
  145. package/lib/agent/module.d.ts.map +0 -1
  146. package/lib/agent/module.js +0 -309
  147. package/lib/agent/module.js.map +0 -1
  148. package/lib/agent/openai.d.ts +0 -6
  149. package/lib/agent/openai.d.ts.map +0 -1
  150. package/lib/agent/openai.js +0 -41
  151. package/lib/agent/openai.js.map +0 -1
  152. package/lib/agent/program.d.ts +0 -12
  153. package/lib/agent/program.d.ts.map +0 -1
  154. package/lib/agent/program.js +0 -21
  155. package/lib/agent/program.js.map +0 -1
  156. package/lib/agent/prompts.d.ts +0 -4
  157. package/lib/agent/prompts.d.ts.map +0 -1
  158. package/lib/agent/prompts.js +0 -11
  159. package/lib/agent/prompts.js.map +0 -1
  160. package/lib/agent/scrape.d.ts +0 -71
  161. package/lib/agent/scrape.d.ts.map +0 -1
  162. package/lib/agent/scrape.js +0 -45
  163. package/lib/agent/scrape.js.map +0 -1
  164. package/lib/aws/auto/docs.d.ts +0 -11
  165. package/lib/aws/auto/docs.d.ts.map +0 -1
  166. package/lib/aws/auto/docs.js +0 -56
  167. package/lib/aws/auto/docs.js.map +0 -1
  168. package/lib/aws/auto/index.d.ts +0 -5
  169. package/lib/aws/auto/index.d.ts.map +0 -1
  170. package/lib/aws/auto/index.js +0 -5
  171. package/lib/aws/auto/index.js.map +0 -1
  172. package/lib/aws/auto/resource.d.ts +0 -24
  173. package/lib/aws/auto/resource.d.ts.map +0 -1
  174. package/lib/aws/auto/resource.js +0 -194
  175. package/lib/aws/auto/resource.js.map +0 -1
  176. package/lib/aws/auto/service.d.ts +0 -10
  177. package/lib/aws/auto/service.d.ts.map +0 -1
  178. package/lib/aws/auto/service.js +0 -34
  179. package/lib/aws/auto/service.js.map +0 -1
  180. package/lib/aws/auto/spec.d.ts +0 -83
  181. package/lib/aws/auto/spec.d.ts.map +0 -1
  182. package/lib/aws/auto/spec.js +0 -58
  183. package/lib/aws/auto/spec.js.map +0 -1
  184. package/lib/markdown/design.d.ts +0 -17
  185. package/lib/markdown/design.d.ts.map +0 -1
  186. package/lib/markdown/design.js +0 -92
  187. package/lib/markdown/design.js.map +0 -1
  188. package/lib/markdown/extract.d.ts +0 -7
  189. package/lib/markdown/extract.d.ts.map +0 -1
  190. package/lib/markdown/extract.js +0 -10
  191. package/lib/markdown/extract.js.map +0 -1
  192. package/lib/markdown/index.d.ts +0 -4
  193. package/lib/markdown/index.d.ts.map +0 -1
  194. package/lib/markdown/index.js +0 -4
  195. package/lib/markdown/index.js.map +0 -1
  196. package/lib/markdown/requirements.d.ts +0 -79
  197. package/lib/markdown/requirements.d.ts.map +0 -1
  198. package/lib/markdown/requirements.js +0 -105
  199. package/lib/markdown/requirements.js.map +0 -1
  200. package/lib/typescript/check-omission.d.ts +0 -2
  201. package/lib/typescript/check-omission.d.ts.map +0 -1
  202. package/lib/typescript/check-omission.js +0 -43
  203. package/lib/typescript/check-omission.js.map +0 -1
  204. package/lib/typescript/debug-type-errors.d.ts +0 -3
  205. package/lib/typescript/debug-type-errors.d.ts.map +0 -1
  206. package/lib/typescript/debug-type-errors.js +0 -35
  207. package/lib/typescript/debug-type-errors.js.map +0 -1
  208. package/lib/typescript/extract.d.ts +0 -7
  209. package/lib/typescript/extract.d.ts.map +0 -1
  210. package/lib/typescript/extract.js +0 -10
  211. package/lib/typescript/extract.js.map +0 -1
  212. package/lib/typescript/index.d.ts +0 -7
  213. package/lib/typescript/index.d.ts.map +0 -1
  214. package/lib/typescript/index.js +0 -7
  215. package/lib/typescript/index.js.map +0 -1
  216. package/lib/typescript/install-dependencies.d.ts +0 -29
  217. package/lib/typescript/install-dependencies.d.ts.map +0 -1
  218. package/lib/typescript/install-dependencies.js +0 -52
  219. package/lib/typescript/install-dependencies.js.map +0 -1
  220. package/lib/typescript/package.d.ts +0 -157
  221. package/lib/typescript/package.d.ts.map +0 -1
  222. package/lib/typescript/package.js +0 -115
  223. package/lib/typescript/package.js.map +0 -1
  224. package/lib/typescript/repair-omissions.d.ts +0 -3
  225. package/lib/typescript/repair-omissions.d.ts.map +0 -1
  226. package/lib/typescript/repair-omissions.js +0 -23
  227. package/lib/typescript/repair-omissions.js.map +0 -1
  228. package/lib/typescript/repair.d.ts +0 -3
  229. package/lib/typescript/repair.d.ts.map +0 -1
  230. package/lib/typescript/repair.js +0 -34
  231. package/lib/typescript/repair.js.map +0 -1
  232. package/lib/typescript/tsconfig.d.ts +0 -469
  233. package/lib/typescript/tsconfig.d.ts.map +0 -1
  234. package/lib/typescript/tsconfig.js +0 -143
  235. package/lib/typescript/tsconfig.js.map +0 -1
  236. package/lib/typescript/typescript.d.ts +0 -107
  237. package/lib/typescript/typescript.d.ts.map +0 -1
  238. package/lib/typescript/typescript.js +0 -180
  239. package/lib/typescript/typescript.js.map +0 -1
  240. package/lib/typescript/validate.d.ts +0 -10
  241. package/lib/typescript/validate.d.ts.map +0 -1
  242. package/lib/typescript/validate.js +0 -49
  243. package/lib/typescript/validate.js.map +0 -1
  244. package/src/$.ts +0 -36
  245. package/src/agent/ai.ts +0 -215
  246. package/src/agent/anthropic.ts +0 -31
  247. package/src/agent/dependencies.ts +0 -62
  248. package/src/agent/file-context.ts +0 -8
  249. package/src/agent/index.ts +0 -9
  250. package/src/agent/model.ts +0 -39
  251. package/src/agent/module.ts +0 -418
  252. package/src/agent/openai.ts +0 -50
  253. package/src/agent/program.md +0 -38
  254. package/src/agent/program.ts +0 -37
  255. package/src/agent/prompts.ts +0 -20
  256. package/src/agent/scrape.ts +0 -47
  257. package/src/aws/auto/cfn.json +0 -225310
  258. package/src/aws/auto/docs.ts +0 -73
  259. package/src/aws/auto/index.ts +0 -4
  260. package/src/aws/auto/resource.ts +0 -269
  261. package/src/aws/auto/service.ts +0 -51
  262. package/src/aws/auto/spec.ts +0 -160
  263. package/src/markdown/design.ts +0 -125
  264. package/src/markdown/extract.ts +0 -9
  265. package/src/markdown/index.ts +0 -3
  266. package/src/markdown/requirements.ts +0 -135
  267. package/src/typescript/check-omission.ts +0 -47
  268. package/src/typescript/debug-type-errors.ts +0 -42
  269. package/src/typescript/extract.ts +0 -9
  270. package/src/typescript/index.ts +0 -6
  271. package/src/typescript/install-dependencies.ts +0 -61
  272. package/src/typescript/package.ts +0 -143
  273. package/src/typescript/repair-omissions.ts +0 -31
  274. package/src/typescript/repair.ts +0 -45
  275. package/src/typescript/tsconfig.ts +0 -170
  276. package/src/typescript/typescript.ts +0 -217
  277. package/src/typescript/validate.ts +0 -73
@@ -0,0 +1,379 @@
1
+ import { exec } from "child_process";
2
+ import { promises as fs } from "fs";
3
+ import path from "path";
4
+ import { promisify } from "util";
5
+ import { apply } from "../apply";
6
+ import type { BundleProps } from "../esbuild";
7
+ import { type Context, Resource } from "../resource";
8
+ import { createCloudflareApi } from "./api";
9
+ import type { WorkerBinding } from "./bindings";
10
+ import { generateAssetManifest } from "./generate-asset-manifest";
11
+ import { KVNamespace } from "./kv-namespace";
12
+ import { uploadAssetManifest } from "./upload-asset-manifest";
13
+ import type { WorkerProps } from "./worker";
14
+ import { Worker } from "./worker";
15
+
16
+ /**
17
+ * Idea of using KV with timeout inspired by SST: https://github.com/sst/sst/blob/dev/platform/src/components/cloudflare/static-site.ts
18
+ */
19
+
20
+ /**
21
+ * Properties for creating or updating a StaticSite
22
+ */
23
+ export interface StaticSiteProps {
24
+ /**
25
+ * Name for the site
26
+ * This is mandatory - must be explicitly specified
27
+ */
28
+ name: string;
29
+
30
+ /**
31
+ * Path to the directory containing static assets
32
+ */
33
+ dir: string;
34
+
35
+ /**
36
+ * Routes to associate with this site
37
+ * Format: example.com/* or *.example.com/*
38
+ */
39
+ routes?: string[];
40
+
41
+ /**
42
+ * Custom Worker script to serve the site
43
+ * If not provided, a default script will be used
44
+ */
45
+ workerScript?: string;
46
+
47
+ /**
48
+ * Worker script format
49
+ * 'esm' - ECMAScript modules (default)
50
+ * 'cjs' - CommonJS modules
51
+ * @default 'esm'
52
+ */
53
+ format?: "esm" | "cjs";
54
+
55
+ /**
56
+ * Custom error page path (relative to directory)
57
+ * @example "404.html"
58
+ */
59
+ errorPage?: string;
60
+
61
+ /**
62
+ * Index page filename
63
+ * @default "index.html"
64
+ */
65
+ indexPage?: string;
66
+
67
+ /**
68
+ * Configure how the static site's assets are uploaded to KV
69
+ */
70
+ assets?: {
71
+ /**
72
+ * File options for configuring caching behavior
73
+ */
74
+ fileOptions?: {
75
+ /**
76
+ * File pattern(s) to match
77
+ * Can be a glob string or array of glob strings
78
+ */
79
+ files: string | string[];
80
+
81
+ /**
82
+ * Files to ignore (glob patterns)
83
+ */
84
+ ignore?: string | string[];
85
+
86
+ /**
87
+ * Cache-Control header to set for matching files
88
+ */
89
+ cacheControl: string;
90
+
91
+ /**
92
+ * Content-Type to set (overrides auto-detection)
93
+ */
94
+ contentType?: string;
95
+ }[];
96
+ };
97
+
98
+ /**
99
+ * Additional Worker bindings to include
100
+ */
101
+ additionalBindings?: WorkerProps["bindings"];
102
+
103
+ /**
104
+ * Whether the site should be deployed to production
105
+ * @default true
106
+ */
107
+ production?: boolean;
108
+
109
+ /**
110
+ * Custom domain for the site
111
+ */
112
+ domain?:
113
+ | string
114
+ | {
115
+ name: string;
116
+ redirects?: string[];
117
+ };
118
+
119
+ build?: {
120
+ /**
121
+ * Command to run before deploying the site
122
+ * Will be executed in the shell to build the site
123
+ */
124
+ command?: string;
125
+ };
126
+
127
+ bundle?: Partial<BundleProps>;
128
+ }
129
+
130
+ /**
131
+ * Output returned after StaticSite creation/update
132
+ */
133
+ export interface StaticSiteOutput {
134
+ /**
135
+ * The ID of the site
136
+ */
137
+ id: string;
138
+
139
+ /**
140
+ * The ID of the worker
141
+ */
142
+ workerId: string;
143
+
144
+ /**
145
+ * Name for the site
146
+ */
147
+ name: string;
148
+
149
+ /**
150
+ * Path to the directory containing static assets
151
+ */
152
+ directory: string;
153
+
154
+ /**
155
+ * Routes to associate with this site
156
+ */
157
+ routes?: string[];
158
+
159
+ /**
160
+ * Worker script format
161
+ */
162
+ format?: "esm" | "cjs";
163
+
164
+ /**
165
+ * Custom error page path
166
+ */
167
+ errorPage?: string;
168
+
169
+ /**
170
+ * Index page filename
171
+ */
172
+ indexPage?: string;
173
+
174
+ /**
175
+ * Time at which the site was created
176
+ */
177
+ createdAt: number;
178
+
179
+ /**
180
+ * Time at which the site was last updated
181
+ */
182
+ updatedAt: number;
183
+
184
+ /**
185
+ * List of uploaded asset files
186
+ */
187
+ assets: string[];
188
+
189
+ /**
190
+ * Custom domain for the site
191
+ */
192
+ domain?:
193
+ | string
194
+ | {
195
+ name: string;
196
+ redirects?: string[];
197
+ };
198
+
199
+ /**
200
+ * Whether the site is deployed to production
201
+ */
202
+ production?: boolean;
203
+
204
+ /**
205
+ * The URL of the deployed site
206
+ */
207
+ url?: string;
208
+ }
209
+
210
+ export class StaticSite extends Resource(
211
+ "cloudflare::StaticSite",
212
+ {
213
+ alwaysUpdate: true,
214
+ },
215
+ async (ctx: Context<StaticSiteOutput>, props: StaticSiteProps) => {
216
+ if (ctx.event === "delete") {
217
+ // For delete operations, we'll rely on the Worker delete to clean up
218
+ // Return empty output for deleted state
219
+ return;
220
+ }
221
+
222
+ // Validate that a name is provided
223
+ if (!props.name) {
224
+ throw new Error(
225
+ "StaticSite name is required - must be explicitly specified",
226
+ );
227
+ }
228
+
229
+ // Validate directory exists
230
+ if (!props.dir) {
231
+ throw new Error("Directory is required for StaticSite");
232
+ }
233
+
234
+ try {
235
+ const dirStat = await fs.stat(props.dir);
236
+ if (!dirStat.isDirectory()) {
237
+ throw new Error(`"${props.dir}" is not a directory`);
238
+ }
239
+ } catch (error: any) {
240
+ throw new Error(
241
+ `Directory "${props.dir}" does not exist: ${error.message}`,
242
+ );
243
+ }
244
+
245
+ // Run build command if provided
246
+ if (props.build?.command) {
247
+ try {
248
+ console.log(props.build.command);
249
+ const execAsync = promisify(exec);
250
+ const { stdout, stderr } = await execAsync(props.build.command, {
251
+ cwd: process.cwd(),
252
+ });
253
+
254
+ if (stdout) console.log(stdout);
255
+ } catch (error: any) {
256
+ // Log detailed error information
257
+ console.error(`Build command failed with exit code ${error.code}`);
258
+ if (error.stdout) console.error(`Command stdout: ${error.stdout}`);
259
+ if (error.stderr) console.error(`Command stderr: ${error.stderr}`);
260
+
261
+ // Throw a more descriptive error that includes the exit code and stderr
262
+ throw new Error(
263
+ `Build command "${props.build.command}" failed with exit code ${error.code}:\n${error.stderr || error.message}`,
264
+ );
265
+ }
266
+ }
267
+
268
+ // Use the provided name
269
+ const siteName = props.name;
270
+ const indexPage = props.indexPage || "index.html";
271
+
272
+ // Create Cloudflare API client with automatic account discovery
273
+ const api = await createCloudflareApi();
274
+
275
+ // Step 1: Create or get the KV namespace for assets
276
+ const namespace = new KVNamespace("assets", {
277
+ title: `${siteName}-assets`,
278
+ });
279
+
280
+ const [{ id: kvNamespaceId }, assetManifest] = await Promise.all([
281
+ apply(namespace),
282
+ generateAssetManifest(props.dir),
283
+ ]);
284
+
285
+ // Step 3: Upload assets to KV
286
+ await uploadAssetManifest(api, kvNamespaceId, assetManifest);
287
+
288
+ // Define the worker script path
289
+ const routerScriptPath = path.resolve(__dirname, "static-site-router.ts");
290
+
291
+ // Prepare the bindings for the worker
292
+ const bindings: WorkerBinding[] = [
293
+ {
294
+ name: "ASSETS",
295
+ type: "kv_namespace",
296
+ namespace_id: kvNamespaceId,
297
+ },
298
+ {
299
+ name: "INDEX_PAGE",
300
+ type: "plain_text",
301
+ text: indexPage,
302
+ },
303
+ ];
304
+
305
+ // Add error page binding if specified
306
+ if (props.errorPage) {
307
+ bindings.push({
308
+ name: "ERROR_PAGE",
309
+ type: "plain_text",
310
+ text: props.errorPage,
311
+ });
312
+ }
313
+
314
+ // Add any additional bindings
315
+ if (props.additionalBindings) {
316
+ bindings.push(...props.additionalBindings);
317
+ }
318
+
319
+ // Create asset manifest banner for static site router
320
+ const assetManifestBanner = `const __ASSET_MANIFEST__ = ${JSON.stringify(
321
+ Object.fromEntries(assetManifest.map((item) => [item.key, item.hash])),
322
+ )};\n`;
323
+
324
+ const worker = new Worker(
325
+ "worker",
326
+ {
327
+ name: siteName,
328
+ url: true,
329
+ format: props.format || "esm",
330
+ routes: props.routes || [],
331
+ // If a custom worker script is provided, use it, otherwise use the entrypoint from router
332
+ ...(props.workerScript
333
+ ? { script: props.workerScript }
334
+ : {
335
+ entrypoint: routerScriptPath,
336
+ bundleOptions: {
337
+ ...props.bundle,
338
+ options: {
339
+ ...props.bundle?.options,
340
+ banner: {
341
+ js: assetManifestBanner,
342
+ ...props.bundle?.options?.banner,
343
+ },
344
+ },
345
+ },
346
+ }),
347
+ bindings,
348
+ },
349
+ // place a dependency on the namespace
350
+ namespace.id,
351
+ );
352
+
353
+ // Step 4: Create or update the worker
354
+ const { id: workerId, url } = await apply(worker);
355
+
356
+ // Get current timestamp
357
+ const now = Date.now();
358
+
359
+ // Construct the output
360
+ const output: StaticSiteOutput = {
361
+ id: siteName,
362
+ workerId,
363
+ name: siteName,
364
+ directory: props.dir,
365
+ routes: props.routes || [],
366
+ format: props.format || "esm",
367
+ errorPage: props.errorPage,
368
+ indexPage,
369
+ assets: assetManifest.map((item) => item.key),
370
+ createdAt: ctx.output?.createdAt || now,
371
+ updatedAt: now,
372
+ domain: props.domain,
373
+ production: props.production !== false,
374
+ url,
375
+ };
376
+
377
+ return output;
378
+ },
379
+ ) {}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Cloudflare API response format
3
+ */
4
+ export interface CloudflareApiResponse<T> {
5
+ /**
6
+ * API response result
7
+ */
8
+ result: T;
9
+
10
+ /**
11
+ * Success status
12
+ */
13
+ success: boolean;
14
+
15
+ /**
16
+ * Error details if success is false
17
+ */
18
+ errors: CloudflareApiError[];
19
+
20
+ /**
21
+ * Response messages
22
+ */
23
+ messages: string[];
24
+
25
+ /**
26
+ * Result information (typically for paginated results)
27
+ */
28
+ result_info?: {
29
+ page: number;
30
+ per_page: number;
31
+ total_pages: number;
32
+ count: number;
33
+ total_count: number;
34
+ };
35
+ }
36
+
37
+ /**
38
+ * Cloudflare API error format
39
+ */
40
+ export interface CloudflareApiError {
41
+ /**
42
+ * Error code
43
+ */
44
+ code: number;
45
+
46
+ /**
47
+ * Error message
48
+ */
49
+ message: string;
50
+ }
51
+
52
+ /**
53
+ * Helper to extract and handle Cloudflare API errors
54
+ *
55
+ * @param response Fetch response object
56
+ * @returns Formatted error message
57
+ */
58
+ export async function extractCloudflareError(
59
+ response: Response,
60
+ ): Promise<string> {
61
+ try {
62
+ const data = (await response.json()) as CloudflareApiResponse<any>;
63
+ if (data.errors && data.errors.length > 0) {
64
+ return data.errors.map((e) => `Error ${e.code}: ${e.message}`).join(", ");
65
+ } else {
66
+ return `HTTP ${response.status}: ${response.statusText}`;
67
+ }
68
+ } catch (e) {
69
+ return `HTTP ${response.status}: ${response.statusText}`;
70
+ }
71
+ }
@@ -0,0 +1,83 @@
1
+ import fs from "node:fs/promises";
2
+ import type { CloudflareApi } from "./api";
3
+ import type { AssetManifest } from "./asset-manifest";
4
+
5
+ // Maximum number of concurrent uploads
6
+ const MAX_CONCURRENT = 100; // Adjust based on API limits and performance testing
7
+
8
+ // Define types for our queue operations
9
+ type AssetItem = AssetManifest[number];
10
+ type UploadResult = {
11
+ item: AssetItem;
12
+ success: boolean;
13
+ status?: number;
14
+ error?: unknown;
15
+ };
16
+
17
+ export async function uploadAssetManifest(
18
+ api: CloudflareApi,
19
+ namespaceId: string,
20
+ manifest: AssetManifest,
21
+ ): Promise<UploadResult[]> {
22
+ const results: UploadResult[] = [];
23
+
24
+ // Process in batches with controlled concurrency
25
+ let index = 0;
26
+ const activePromises = new Set<Promise<void>>();
27
+
28
+ while (index < manifest.length || activePromises.size > 0) {
29
+ // Fill up to MAX_CONCURRENT active uploads
30
+ while (activePromises.size < MAX_CONCURRENT && index < manifest.length) {
31
+ const item = manifest[index++];
32
+ const promise = uploadItem(item).then((result) => {
33
+ results.push(result);
34
+ activePromises.delete(promise);
35
+ });
36
+ activePromises.add(promise);
37
+ }
38
+
39
+ // Wait for at least one promise to complete if we have any active
40
+ if (activePromises.size > 0) {
41
+ await Promise.race(activePromises);
42
+ }
43
+ }
44
+
45
+ return results;
46
+
47
+ async function uploadItem(item: AssetItem): Promise<UploadResult> {
48
+ const content = await fs.readFile(item.source);
49
+
50
+ // Create metadata object
51
+ const metadata = {
52
+ key: item.key,
53
+ hash: item.hash,
54
+ contentType: item.contentType,
55
+ cacheControl: item.cacheControl,
56
+ };
57
+
58
+ // Create FormData for multipart upload
59
+ const formData = new FormData();
60
+ formData.append("metadata", JSON.stringify(metadata));
61
+
62
+ // Add file content as 'value'
63
+ const blob = new Blob([content]);
64
+ formData.append("value", blob);
65
+
66
+ try {
67
+ const response = await api.put(
68
+ `/accounts/${api.accountId}/storage/kv/namespaces/${namespaceId}/values/${item.key}`,
69
+ formData,
70
+ );
71
+
72
+ const result = { item, success: response.ok, status: response.status };
73
+ if (!result.success) {
74
+ console.warn(`Error uploading asset ${item.key}: ${result.status}`);
75
+ }
76
+ return result;
77
+ } catch (error) {
78
+ const result = { item, success: false, error };
79
+ console.warn(`Error uploading asset ${item.key}: ${error}`);
80
+ return result;
81
+ }
82
+ }
83
+ }