alchemy 0.1.11 → 0.1.13

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 (312) hide show
  1. package/README.md +324 -0
  2. package/lib/$.d.ts +8 -3
  3. package/lib/$.d.ts.map +1 -1
  4. package/lib/$.js +38 -27
  5. package/lib/$.js.map +1 -1
  6. package/lib/alchemize.d.ts.map +1 -1
  7. package/lib/alchemize.js +7 -0
  8. package/lib/alchemize.js.map +1 -1
  9. package/lib/apply.d.ts +2 -2
  10. package/lib/apply.d.ts.map +1 -1
  11. package/lib/apply.js +3 -3
  12. package/lib/apply.js.map +1 -1
  13. package/lib/aws/index.d.ts +1 -0
  14. package/lib/aws/index.d.ts.map +1 -1
  15. package/lib/aws/index.js +1 -0
  16. package/lib/aws/index.js.map +1 -1
  17. package/lib/aws/ses.d.ts +75 -0
  18. package/lib/aws/ses.d.ts.map +1 -0
  19. package/lib/aws/ses.js +197 -0
  20. package/lib/aws/ses.js.map +1 -0
  21. package/lib/cloudflare/api.d.ts +88 -0
  22. package/lib/cloudflare/api.d.ts.map +1 -0
  23. package/lib/cloudflare/api.js +184 -0
  24. package/lib/cloudflare/api.js.map +1 -0
  25. package/lib/cloudflare/asset-manifest.d.ts +15 -0
  26. package/lib/cloudflare/asset-manifest.d.ts.map +1 -0
  27. package/lib/cloudflare/asset-manifest.js +2 -0
  28. package/lib/cloudflare/asset-manifest.js.map +1 -0
  29. package/lib/cloudflare/auth.d.ts +52 -0
  30. package/lib/cloudflare/auth.d.ts.map +1 -0
  31. package/lib/cloudflare/auth.js +114 -0
  32. package/lib/cloudflare/auth.js.map +1 -0
  33. package/lib/cloudflare/bindings.d.ts +254 -0
  34. package/lib/cloudflare/bindings.d.ts.map +1 -0
  35. package/lib/cloudflare/bindings.js +2 -0
  36. package/lib/cloudflare/bindings.js.map +1 -0
  37. package/lib/cloudflare/durable-object-namespace.d.ts +23 -0
  38. package/lib/cloudflare/durable-object-namespace.d.ts.map +1 -0
  39. package/lib/cloudflare/durable-object-namespace.js +26 -0
  40. package/lib/cloudflare/durable-object-namespace.js.map +1 -0
  41. package/lib/cloudflare/generate-asset-manifest.d.ts +3 -0
  42. package/lib/cloudflare/generate-asset-manifest.d.ts.map +1 -0
  43. package/lib/cloudflare/generate-asset-manifest.js +69 -0
  44. package/lib/cloudflare/generate-asset-manifest.js.map +1 -0
  45. package/lib/cloudflare/index.d.ts +7 -0
  46. package/lib/cloudflare/index.d.ts.map +1 -0
  47. package/lib/cloudflare/index.js +7 -0
  48. package/lib/cloudflare/index.js.map +1 -0
  49. package/lib/cloudflare/kv-namespace.d.ts +61 -0
  50. package/lib/cloudflare/kv-namespace.d.ts.map +1 -0
  51. package/lib/cloudflare/kv-namespace.js +93 -0
  52. package/lib/cloudflare/kv-namespace.js.map +1 -0
  53. package/lib/cloudflare/state.d.ts +83 -0
  54. package/lib/cloudflare/state.d.ts.map +1 -0
  55. package/lib/cloudflare/state.js +109 -0
  56. package/lib/cloudflare/state.js.map +1 -0
  57. package/lib/cloudflare/static-site-router.d.ts +19 -0
  58. package/lib/cloudflare/static-site-router.d.ts.map +1 -0
  59. package/lib/cloudflare/static-site-router.js +110 -0
  60. package/lib/cloudflare/static-site-router.js.map +1 -0
  61. package/lib/cloudflare/static-site.d.ts +166 -0
  62. package/lib/cloudflare/static-site.d.ts.map +1 -0
  63. package/lib/cloudflare/static-site.js +168 -0
  64. package/lib/cloudflare/static-site.js.map +1 -0
  65. package/lib/cloudflare/types.d.ts +52 -0
  66. package/lib/cloudflare/types.d.ts.map +1 -0
  67. package/lib/cloudflare/types.js +21 -0
  68. package/lib/cloudflare/types.js.map +1 -0
  69. package/lib/cloudflare/upload-asset-manifest.d.ts +12 -0
  70. package/lib/cloudflare/upload-asset-manifest.d.ts.map +1 -0
  71. package/lib/cloudflare/upload-asset-manifest.js +55 -0
  72. package/lib/cloudflare/upload-asset-manifest.js.map +1 -0
  73. package/lib/cloudflare/worker-metadata.d.ts +130 -0
  74. package/lib/cloudflare/worker-metadata.d.ts.map +1 -0
  75. package/lib/cloudflare/worker-metadata.js +2 -0
  76. package/lib/cloudflare/worker-metadata.js.map +1 -0
  77. package/lib/cloudflare/worker-migration.d.ts +110 -0
  78. package/lib/cloudflare/worker-migration.d.ts.map +1 -0
  79. package/lib/cloudflare/worker-migration.js +11 -0
  80. package/lib/cloudflare/worker-migration.js.map +1 -0
  81. package/lib/cloudflare/worker.d.ts +105 -0
  82. package/lib/cloudflare/worker.d.ts.map +1 -0
  83. package/lib/cloudflare/worker.js +358 -0
  84. package/lib/cloudflare/worker.js.map +1 -0
  85. package/lib/destroy.d.ts +1 -1
  86. package/lib/destroy.d.ts.map +1 -1
  87. package/lib/destroy.js +2 -1
  88. package/lib/destroy.js.map +1 -1
  89. package/lib/esbuild.d.ts +83 -1
  90. package/lib/esbuild.d.ts.map +1 -1
  91. package/lib/esbuild.js +27 -18
  92. package/lib/esbuild.js.map +1 -1
  93. package/lib/fs.d.ts +1 -1
  94. package/lib/global.d.ts +0 -2
  95. package/lib/global.d.ts.map +1 -1
  96. package/lib/global.js +3 -3
  97. package/lib/global.js.map +1 -1
  98. package/lib/index.d.ts +1 -0
  99. package/lib/index.d.ts.map +1 -1
  100. package/lib/index.js +1 -0
  101. package/lib/index.js.map +1 -1
  102. package/lib/main.js +1 -1
  103. package/lib/main.js.map +1 -1
  104. package/lib/output.d.ts +18 -13
  105. package/lib/output.d.ts.map +1 -1
  106. package/lib/output.js +12 -5
  107. package/lib/output.js.map +1 -1
  108. package/lib/print.d.ts +7 -0
  109. package/lib/print.d.ts.map +1 -0
  110. package/lib/print.js +10 -0
  111. package/lib/print.js.map +1 -0
  112. package/lib/resource.d.ts +9 -4
  113. package/lib/resource.d.ts.map +1 -1
  114. package/lib/resource.js +127 -93
  115. package/lib/resource.js.map +1 -1
  116. package/lib/scope.d.ts +3 -0
  117. package/lib/scope.d.ts.map +1 -1
  118. package/lib/scope.js +4 -12
  119. package/lib/scope.js.map +1 -1
  120. package/lib/utils/content-type.d.ts +8 -0
  121. package/lib/utils/content-type.d.ts.map +1 -0
  122. package/lib/utils/content-type.js +41 -0
  123. package/lib/utils/content-type.js.map +1 -0
  124. package/package.json +27 -8
  125. package/src/$.ts +63 -30
  126. package/src/alchemize.ts +12 -0
  127. package/src/apply.ts +6 -6
  128. package/src/aws/index.ts +1 -0
  129. package/src/aws/ses.ts +346 -0
  130. package/src/cloudflare/api.ts +282 -0
  131. package/src/cloudflare/asset-manifest.ts +16 -0
  132. package/src/cloudflare/auth.ts +187 -0
  133. package/src/cloudflare/bindings.ts +297 -0
  134. package/src/cloudflare/durable-object-namespace.ts +43 -0
  135. package/src/cloudflare/generate-asset-manifest.ts +93 -0
  136. package/src/cloudflare/index.ts +6 -0
  137. package/src/cloudflare/kv-namespace.ts +195 -0
  138. package/src/cloudflare/state.ts +138 -0
  139. package/src/cloudflare/static-site-router.ts +150 -0
  140. package/src/cloudflare/static-site.ts +395 -0
  141. package/src/cloudflare/types.ts +71 -0
  142. package/src/cloudflare/upload-asset-manifest.ts +83 -0
  143. package/src/cloudflare/worker-metadata.ts +154 -0
  144. package/src/cloudflare/worker-migration.ts +145 -0
  145. package/src/cloudflare/worker.ts +666 -0
  146. package/src/destroy.ts +2 -2
  147. package/src/esbuild.ts +34 -22
  148. package/src/global.ts +1 -3
  149. package/src/index.ts +1 -1
  150. package/src/main.ts +1 -1
  151. package/src/output.ts +53 -37
  152. package/src/print.ts +18 -0
  153. package/src/resource.ts +163 -116
  154. package/src/scope.ts +7 -12
  155. package/src/utils/content-type.ts +42 -0
  156. package/lib/agent/ai.d.ts +0 -40
  157. package/lib/agent/ai.d.ts.map +0 -1
  158. package/lib/agent/ai.js +0 -132
  159. package/lib/agent/ai.js.map +0 -1
  160. package/lib/agent/anthropic.d.ts +0 -9
  161. package/lib/agent/anthropic.d.ts.map +0 -1
  162. package/lib/agent/anthropic.js +0 -25
  163. package/lib/agent/anthropic.js.map +0 -1
  164. package/lib/agent/dependencies.d.ts +0 -4
  165. package/lib/agent/dependencies.d.ts.map +0 -1
  166. package/lib/agent/dependencies.js +0 -48
  167. package/lib/agent/dependencies.js.map +0 -1
  168. package/lib/agent/file-context.d.ts +0 -13
  169. package/lib/agent/file-context.d.ts.map +0 -1
  170. package/lib/agent/file-context.js +0 -6
  171. package/lib/agent/file-context.js.map +0 -1
  172. package/lib/agent/index.d.ts +0 -10
  173. package/lib/agent/index.d.ts.map +0 -1
  174. package/lib/agent/index.js +0 -10
  175. package/lib/agent/index.js.map +0 -1
  176. package/lib/agent/model.d.ts +0 -8
  177. package/lib/agent/model.d.ts.map +0 -1
  178. package/lib/agent/model.js +0 -29
  179. package/lib/agent/model.js.map +0 -1
  180. package/lib/agent/module.d.ts +0 -81
  181. package/lib/agent/module.d.ts.map +0 -1
  182. package/lib/agent/module.js +0 -309
  183. package/lib/agent/module.js.map +0 -1
  184. package/lib/agent/openai.d.ts +0 -6
  185. package/lib/agent/openai.d.ts.map +0 -1
  186. package/lib/agent/openai.js +0 -41
  187. package/lib/agent/openai.js.map +0 -1
  188. package/lib/agent/program.d.ts +0 -12
  189. package/lib/agent/program.d.ts.map +0 -1
  190. package/lib/agent/program.js +0 -21
  191. package/lib/agent/program.js.map +0 -1
  192. package/lib/agent/prompts.d.ts +0 -4
  193. package/lib/agent/prompts.d.ts.map +0 -1
  194. package/lib/agent/prompts.js +0 -11
  195. package/lib/agent/prompts.js.map +0 -1
  196. package/lib/agent/scrape.d.ts +0 -71
  197. package/lib/agent/scrape.d.ts.map +0 -1
  198. package/lib/agent/scrape.js +0 -45
  199. package/lib/agent/scrape.js.map +0 -1
  200. package/lib/aws/auto/docs.d.ts +0 -11
  201. package/lib/aws/auto/docs.d.ts.map +0 -1
  202. package/lib/aws/auto/docs.js +0 -56
  203. package/lib/aws/auto/docs.js.map +0 -1
  204. package/lib/aws/auto/index.d.ts +0 -5
  205. package/lib/aws/auto/index.d.ts.map +0 -1
  206. package/lib/aws/auto/index.js +0 -5
  207. package/lib/aws/auto/index.js.map +0 -1
  208. package/lib/aws/auto/resource.d.ts +0 -24
  209. package/lib/aws/auto/resource.d.ts.map +0 -1
  210. package/lib/aws/auto/resource.js +0 -194
  211. package/lib/aws/auto/resource.js.map +0 -1
  212. package/lib/aws/auto/service.d.ts +0 -10
  213. package/lib/aws/auto/service.d.ts.map +0 -1
  214. package/lib/aws/auto/service.js +0 -34
  215. package/lib/aws/auto/service.js.map +0 -1
  216. package/lib/aws/auto/spec.d.ts +0 -83
  217. package/lib/aws/auto/spec.d.ts.map +0 -1
  218. package/lib/aws/auto/spec.js +0 -58
  219. package/lib/aws/auto/spec.js.map +0 -1
  220. package/lib/markdown/design.d.ts +0 -17
  221. package/lib/markdown/design.d.ts.map +0 -1
  222. package/lib/markdown/design.js +0 -92
  223. package/lib/markdown/design.js.map +0 -1
  224. package/lib/markdown/extract.d.ts +0 -7
  225. package/lib/markdown/extract.d.ts.map +0 -1
  226. package/lib/markdown/extract.js +0 -10
  227. package/lib/markdown/extract.js.map +0 -1
  228. package/lib/markdown/index.d.ts +0 -4
  229. package/lib/markdown/index.d.ts.map +0 -1
  230. package/lib/markdown/index.js +0 -4
  231. package/lib/markdown/index.js.map +0 -1
  232. package/lib/markdown/requirements.d.ts +0 -79
  233. package/lib/markdown/requirements.d.ts.map +0 -1
  234. package/lib/markdown/requirements.js +0 -105
  235. package/lib/markdown/requirements.js.map +0 -1
  236. package/lib/typescript/check-omission.d.ts +0 -2
  237. package/lib/typescript/check-omission.d.ts.map +0 -1
  238. package/lib/typescript/check-omission.js +0 -43
  239. package/lib/typescript/check-omission.js.map +0 -1
  240. package/lib/typescript/debug-type-errors.d.ts +0 -3
  241. package/lib/typescript/debug-type-errors.d.ts.map +0 -1
  242. package/lib/typescript/debug-type-errors.js +0 -35
  243. package/lib/typescript/debug-type-errors.js.map +0 -1
  244. package/lib/typescript/extract.d.ts +0 -7
  245. package/lib/typescript/extract.d.ts.map +0 -1
  246. package/lib/typescript/extract.js +0 -10
  247. package/lib/typescript/extract.js.map +0 -1
  248. package/lib/typescript/index.d.ts +0 -7
  249. package/lib/typescript/index.d.ts.map +0 -1
  250. package/lib/typescript/index.js +0 -7
  251. package/lib/typescript/index.js.map +0 -1
  252. package/lib/typescript/install-dependencies.d.ts +0 -29
  253. package/lib/typescript/install-dependencies.d.ts.map +0 -1
  254. package/lib/typescript/install-dependencies.js +0 -52
  255. package/lib/typescript/install-dependencies.js.map +0 -1
  256. package/lib/typescript/package.d.ts +0 -157
  257. package/lib/typescript/package.d.ts.map +0 -1
  258. package/lib/typescript/package.js +0 -115
  259. package/lib/typescript/package.js.map +0 -1
  260. package/lib/typescript/repair-omissions.d.ts +0 -3
  261. package/lib/typescript/repair-omissions.d.ts.map +0 -1
  262. package/lib/typescript/repair-omissions.js +0 -23
  263. package/lib/typescript/repair-omissions.js.map +0 -1
  264. package/lib/typescript/repair.d.ts +0 -3
  265. package/lib/typescript/repair.d.ts.map +0 -1
  266. package/lib/typescript/repair.js +0 -34
  267. package/lib/typescript/repair.js.map +0 -1
  268. package/lib/typescript/tsconfig.d.ts +0 -469
  269. package/lib/typescript/tsconfig.d.ts.map +0 -1
  270. package/lib/typescript/tsconfig.js +0 -143
  271. package/lib/typescript/tsconfig.js.map +0 -1
  272. package/lib/typescript/typescript.d.ts +0 -107
  273. package/lib/typescript/typescript.d.ts.map +0 -1
  274. package/lib/typescript/typescript.js +0 -180
  275. package/lib/typescript/typescript.js.map +0 -1
  276. package/lib/typescript/validate.d.ts +0 -10
  277. package/lib/typescript/validate.d.ts.map +0 -1
  278. package/lib/typescript/validate.js +0 -49
  279. package/lib/typescript/validate.js.map +0 -1
  280. package/src/agent/ai.ts +0 -215
  281. package/src/agent/anthropic.ts +0 -31
  282. package/src/agent/dependencies.ts +0 -62
  283. package/src/agent/file-context.ts +0 -8
  284. package/src/agent/index.ts +0 -9
  285. package/src/agent/model.ts +0 -39
  286. package/src/agent/module.ts +0 -418
  287. package/src/agent/openai.ts +0 -50
  288. package/src/agent/program.md +0 -38
  289. package/src/agent/program.ts +0 -37
  290. package/src/agent/prompts.ts +0 -20
  291. package/src/agent/scrape.ts +0 -47
  292. package/src/aws/auto/cfn.json +0 -225310
  293. package/src/aws/auto/docs.ts +0 -73
  294. package/src/aws/auto/index.ts +0 -4
  295. package/src/aws/auto/resource.ts +0 -269
  296. package/src/aws/auto/service.ts +0 -51
  297. package/src/aws/auto/spec.ts +0 -160
  298. package/src/markdown/design.ts +0 -125
  299. package/src/markdown/extract.ts +0 -9
  300. package/src/markdown/index.ts +0 -3
  301. package/src/markdown/requirements.ts +0 -135
  302. package/src/typescript/check-omission.ts +0 -47
  303. package/src/typescript/debug-type-errors.ts +0 -42
  304. package/src/typescript/extract.ts +0 -9
  305. package/src/typescript/index.ts +0 -6
  306. package/src/typescript/install-dependencies.ts +0 -61
  307. package/src/typescript/package.ts +0 -143
  308. package/src/typescript/repair-omissions.ts +0 -31
  309. package/src/typescript/repair.ts +0 -45
  310. package/src/typescript/tsconfig.ts +0 -170
  311. package/src/typescript/typescript.ts +0 -217
  312. package/src/typescript/validate.ts +0 -73
@@ -0,0 +1,395 @@
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 { Input } from "../input";
8
+ import { type Context, Resource } from "../resource";
9
+ import { createCloudflareApi } from "./api";
10
+ import type { WorkerBindingSpec } from "./bindings";
11
+ import { generateAssetManifest } from "./generate-asset-manifest";
12
+ import { KVNamespace } from "./kv-namespace";
13
+ import { uploadAssetManifest } from "./upload-asset-manifest";
14
+ import { Worker } from "./worker";
15
+
16
+ const __dirname = import.meta.dirname;
17
+
18
+ /**
19
+ * Idea of using KV with timeout inspired by SST: https://github.com/sst/sst/blob/dev/platform/src/components/cloudflare/static-site.ts
20
+ */
21
+
22
+ /**
23
+ * Properties for creating or updating a StaticSite
24
+ */
25
+ export interface StaticSiteProps {
26
+ /**
27
+ * Name for the site
28
+ * This is mandatory - must be explicitly specified
29
+ */
30
+ name: string;
31
+
32
+ /**
33
+ * Path to the directory containing static assets
34
+ */
35
+ dir: string;
36
+
37
+ /**
38
+ * Custom Worker script to serve the site
39
+ * If not provided, a default script will be used
40
+ */
41
+ workerScript?: string;
42
+
43
+ /**
44
+ * Worker script format
45
+ * 'esm' - ECMAScript modules (default)
46
+ * 'cjs' - CommonJS modules
47
+ * @default 'esm'
48
+ */
49
+ format?: "esm" | "cjs";
50
+
51
+ /**
52
+ * Custom error page path (relative to directory)
53
+ * @example "404.html"
54
+ */
55
+ errorPage?: string;
56
+
57
+ /**
58
+ * Index page filename
59
+ * @default "index.html"
60
+ */
61
+ indexPage?: string;
62
+
63
+ /**
64
+ * Configure how the static site's assets are uploaded to KV
65
+ */
66
+ assets?: {
67
+ /**
68
+ * File options for configuring caching behavior
69
+ */
70
+ fileOptions?: {
71
+ /**
72
+ * File pattern(s) to match
73
+ * Can be a glob string or array of glob strings
74
+ */
75
+ files: string | string[];
76
+
77
+ /**
78
+ * Files to ignore (glob patterns)
79
+ */
80
+ ignore?: string | string[];
81
+
82
+ /**
83
+ * Cache-Control header to set for matching files
84
+ */
85
+ cacheControl: string;
86
+
87
+ /**
88
+ * Content-Type to set (overrides auto-detection)
89
+ */
90
+ contentType?: string;
91
+ }[];
92
+ };
93
+
94
+ /**
95
+ * Whether the site should be deployed to production
96
+ * @default true
97
+ */
98
+ production?: boolean;
99
+
100
+ /**
101
+ * Custom domain for the site
102
+ */
103
+ domain?:
104
+ | string
105
+ | {
106
+ name: string;
107
+ redirects?: string[];
108
+ };
109
+
110
+ build?: {
111
+ /**
112
+ * Command to run before deploying the site
113
+ * Will be executed in the shell to build the site
114
+ */
115
+ command?: string;
116
+ };
117
+
118
+ /**
119
+ * Bundle options for the worker script
120
+ */
121
+ bundle?: Partial<BundleProps>;
122
+
123
+ /**
124
+ * Additional workers to route requests to.
125
+ */
126
+ routes?: {
127
+ [key: string]: Worker;
128
+ };
129
+ }
130
+
131
+ /**
132
+ * Output returned after StaticSite creation/update
133
+ */
134
+ export interface StaticSiteOutput {
135
+ /**
136
+ * The ID of the site
137
+ */
138
+ id: string;
139
+
140
+ /**
141
+ * The ID of the worker
142
+ */
143
+ workerId: string;
144
+
145
+ /**
146
+ * Name for the site
147
+ */
148
+ name: string;
149
+
150
+ /**
151
+ * Path to the directory containing static assets
152
+ */
153
+ directory: string;
154
+
155
+ /**
156
+ * Worker script format
157
+ */
158
+ format?: "esm" | "cjs";
159
+
160
+ /**
161
+ * Custom error page path
162
+ */
163
+ errorPage?: string;
164
+
165
+ /**
166
+ * Index page filename
167
+ */
168
+ indexPage?: string;
169
+
170
+ /**
171
+ * Time at which the site was created
172
+ */
173
+ createdAt: number;
174
+
175
+ /**
176
+ * Time at which the site was last updated
177
+ */
178
+ updatedAt: number;
179
+
180
+ /**
181
+ * List of uploaded asset files
182
+ */
183
+ assets: string[];
184
+
185
+ /**
186
+ * Custom domain for the site
187
+ */
188
+ domain?:
189
+ | string
190
+ | {
191
+ name: string;
192
+ redirects?: string[];
193
+ };
194
+
195
+ /**
196
+ * Whether the site is deployed to production
197
+ */
198
+ production?: boolean;
199
+
200
+ /**
201
+ * The URL of the deployed site
202
+ */
203
+ url?: string;
204
+
205
+ /**
206
+ * Information about the backend worker if configured
207
+ */
208
+ routes?: Record<string, string>;
209
+ }
210
+
211
+ export class StaticSite extends Resource(
212
+ "cloudflare::StaticSite",
213
+ {
214
+ alwaysUpdate: true,
215
+ },
216
+ async (ctx: Context<StaticSiteOutput>, props: StaticSiteProps) => {
217
+ if (ctx.event === "delete") {
218
+ // For delete operations, we'll rely on the Worker delete to clean up
219
+ // Return empty output for deleted state
220
+ return;
221
+ }
222
+
223
+ // Validate that a name is provided
224
+ if (!props.name) {
225
+ throw new Error(
226
+ "StaticSite name is required - must be explicitly specified",
227
+ );
228
+ }
229
+
230
+ // Validate directory exists
231
+ if (!props.dir) {
232
+ throw new Error("Directory is required for StaticSite");
233
+ }
234
+
235
+ try {
236
+ const dirStat = await fs.stat(props.dir);
237
+ if (!dirStat.isDirectory()) {
238
+ throw new Error(`"${props.dir}" is not a directory`);
239
+ }
240
+ } catch (error: any) {
241
+ throw new Error(
242
+ `Directory "${props.dir}" does not exist: ${error.message}`,
243
+ );
244
+ }
245
+
246
+ // Run build command if provided
247
+ if (props.build?.command) {
248
+ try {
249
+ if (!ctx.quiet) {
250
+ console.log(props.build.command);
251
+ }
252
+ const execAsync = promisify(exec);
253
+ const { stdout, stderr } = await execAsync(props.build.command, {
254
+ cwd: process.cwd(),
255
+ });
256
+
257
+ if (stdout && !ctx.quiet) console.log(stdout);
258
+ } catch (error: any) {
259
+ // Log detailed error information
260
+ console.error(`Build command failed with exit code ${error.code}`);
261
+ if (error.stdout) console.error(`Command stdout: ${error.stdout}`);
262
+ if (error.stderr) console.error(`Command stderr: ${error.stderr}`);
263
+
264
+ // Throw a more descriptive error that includes the exit code and stderr
265
+ throw new Error(
266
+ `Build command "${props.build.command}" failed with exit code ${error.code}:\n${error.stderr || error.message}`,
267
+ );
268
+ }
269
+ }
270
+
271
+ // Use the provided name
272
+ const siteName = props.name;
273
+ const indexPage = props.indexPage || "index.html";
274
+
275
+ // Create Cloudflare API client with automatic account discovery
276
+ const api = await createCloudflareApi();
277
+
278
+ // Step 1: Create or get the KV namespace for assets
279
+ const namespace = new KVNamespace("assets", {
280
+ title: `${siteName}-assets`,
281
+ });
282
+
283
+ const [{ id: kvNamespaceId }, assetManifest] = await Promise.all([
284
+ apply(namespace, {
285
+ quiet: ctx.quiet,
286
+ }),
287
+ generateAssetManifest(props.dir),
288
+ ]);
289
+
290
+ // Step 3: Upload assets to KV
291
+ await uploadAssetManifest(api, kvNamespaceId, assetManifest);
292
+
293
+ // Prepare the bindings for the worker
294
+ const bindings: Input<WorkerBindingSpec>[] = [
295
+ {
296
+ name: "ASSETS",
297
+ type: "kv_namespace",
298
+ namespace_id: kvNamespaceId,
299
+ },
300
+ {
301
+ name: "INDEX_PAGE",
302
+ type: "plain_text",
303
+ text: indexPage,
304
+ },
305
+ ];
306
+
307
+ // Add error page binding if specified
308
+ if (props.errorPage) {
309
+ bindings.push({
310
+ name: "ERROR_PAGE",
311
+ type: "plain_text",
312
+ text: props.errorPage,
313
+ });
314
+ }
315
+
316
+ const routes: Record<string, string> = {};
317
+ // Create backend worker if configured
318
+ if (props.routes) {
319
+ for (const [path, entrypoint] of Object.entries(props.routes)) {
320
+ // @ts-ignore - TODO: need to use Resolved<Worker> to get the string ...
321
+ routes[path] = entrypoint.id;
322
+ bindings.push({
323
+ type: "service",
324
+ name: `ROUTE_${entrypoint.id}`,
325
+ service: entrypoint.id,
326
+ });
327
+ }
328
+ }
329
+
330
+ // Create asset manifest banner for static site router
331
+ const assetManifestBanner = `const __ASSET_MANIFEST__ = ${JSON.stringify(
332
+ Object.fromEntries(assetManifest.map((item) => [item.key, item.hash])),
333
+ )};\n`;
334
+
335
+ const bundleOptions = {
336
+ ...props.bundle,
337
+ options: {
338
+ ...props.bundle?.options,
339
+ banner: {
340
+ js: assetManifestBanner,
341
+ ...props.bundle?.options?.banner,
342
+ },
343
+ },
344
+ };
345
+ const worker = new Worker(
346
+ "worker",
347
+ {
348
+ name: siteName,
349
+ url: true,
350
+ format: props.format || "esm",
351
+ // If a custom worker script is provided, use it, otherwise use the entrypoint from router
352
+ ...(props.workerScript
353
+ ? { script: props.workerScript }
354
+ : {
355
+ entrypoint: path.resolve(__dirname, "static-site-router.ts"),
356
+ bundle: bundleOptions,
357
+ }),
358
+ bindings,
359
+ env: {
360
+ ...Object.fromEntries(
361
+ Object.entries(routes).map(([key, value]) => [
362
+ `__ROUTE_${value}`,
363
+ key,
364
+ ]),
365
+ ),
366
+ },
367
+ },
368
+ // place a dependency on the namespace
369
+ namespace.id,
370
+ );
371
+
372
+ // Get current timestamp
373
+ const now = Date.now();
374
+
375
+ // Construct the output
376
+ const output: Input<StaticSiteOutput> = {
377
+ id: siteName,
378
+ workerId: worker.id,
379
+ name: siteName,
380
+ directory: props.dir,
381
+ format: props.format || "esm",
382
+ errorPage: props.errorPage,
383
+ indexPage,
384
+ assets: assetManifest.map((item) => item.key),
385
+ createdAt: ctx.output?.createdAt || now,
386
+ updatedAt: now,
387
+ domain: props.domain,
388
+ production: props.production !== false,
389
+ url: worker.url,
390
+ routes,
391
+ };
392
+
393
+ return output;
394
+ },
395
+ ) {}
@@ -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
+ }
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Metadata returned by Cloudflare API for a worker script
3
+ */
4
+ export interface WorkerScriptMetadata {
5
+ /**
6
+ * Worker ID
7
+ */
8
+ id: string;
9
+
10
+ /**
11
+ * Default environment information
12
+ */
13
+ default_environment?: WorkerDefaultEnvironment;
14
+
15
+ /**
16
+ * Worker creation timestamp
17
+ */
18
+ created_on: string;
19
+
20
+ /**
21
+ * Worker last modification timestamp
22
+ */
23
+ modified_on: string;
24
+
25
+ /**
26
+ * Worker usage model
27
+ */
28
+ usage_model: string;
29
+
30
+ /**
31
+ * Worker environments
32
+ */
33
+ environments?: WorkerEnvironment[];
34
+ }
35
+
36
+ /**
37
+ * Worker script information
38
+ */
39
+ export interface WorkerScriptInfo {
40
+ /**
41
+ * Script creation timestamp
42
+ */
43
+ created_on: string;
44
+
45
+ /**
46
+ * Script last modification timestamp
47
+ */
48
+ modified_on: string;
49
+
50
+ /**
51
+ * Script ID
52
+ */
53
+ id: string;
54
+
55
+ /**
56
+ * Script tag
57
+ */
58
+ tag: string;
59
+
60
+ /**
61
+ * Script tags
62
+ */
63
+ tags: string[];
64
+
65
+ /**
66
+ * Deployment ID
67
+ */
68
+ deployment_id: string;
69
+
70
+ /**
71
+ * Tail consumers
72
+ */
73
+ tail_consumers: any;
74
+
75
+ /**
76
+ * Whether logpush is enabled
77
+ */
78
+ logpush: boolean;
79
+
80
+ /**
81
+ * Observability settings
82
+ */
83
+ observability: {
84
+ /**
85
+ * Whether observability is enabled
86
+ */
87
+ enabled: boolean;
88
+
89
+ /**
90
+ * Head sampling rate
91
+ */
92
+ head_sampling_rate: number | null;
93
+ };
94
+
95
+ /**
96
+ * Whether the script has assets
97
+ */
98
+ has_assets: boolean;
99
+
100
+ /**
101
+ * Whether the script has modules
102
+ */
103
+ has_modules: boolean;
104
+
105
+ /**
106
+ * Script etag
107
+ */
108
+ etag: string;
109
+
110
+ /**
111
+ * Script handlers
112
+ */
113
+ handlers: string[];
114
+
115
+ /**
116
+ * Where the script was last deployed from
117
+ */
118
+ last_deployed_from: string;
119
+
120
+ /**
121
+ * Script usage model
122
+ */
123
+ usage_model: string;
124
+ }
125
+
126
+ /**
127
+ * Worker environment information
128
+ */
129
+ export interface WorkerEnvironment {
130
+ /**
131
+ * Environment name
132
+ */
133
+ environment: string;
134
+
135
+ /**
136
+ * Environment creation timestamp
137
+ */
138
+ created_on: string;
139
+
140
+ /**
141
+ * Environment last modification timestamp
142
+ */
143
+ modified_on: string;
144
+ }
145
+
146
+ /**
147
+ * Default environment with script information
148
+ */
149
+ export interface WorkerDefaultEnvironment extends WorkerEnvironment {
150
+ /**
151
+ * Script information
152
+ */
153
+ script: WorkerScriptInfo;
154
+ }