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.
- package/README.md +324 -0
- package/lib/apply.d.ts +2 -2
- package/lib/apply.d.ts.map +1 -1
- package/lib/apply.js +2 -2
- package/lib/apply.js.map +1 -1
- package/lib/aws/index.d.ts +1 -0
- package/lib/aws/index.d.ts.map +1 -1
- package/lib/aws/index.js +1 -0
- package/lib/aws/index.js.map +1 -1
- package/lib/aws/ses.d.ts +75 -0
- package/lib/aws/ses.d.ts.map +1 -0
- package/lib/aws/ses.js +197 -0
- package/lib/aws/ses.js.map +1 -0
- package/lib/cloudflare/api.d.ts +84 -0
- package/lib/cloudflare/api.d.ts.map +1 -0
- package/lib/cloudflare/api.js +178 -0
- package/lib/cloudflare/api.js.map +1 -0
- package/lib/cloudflare/asset-manifest.d.ts +15 -0
- package/lib/cloudflare/asset-manifest.d.ts.map +1 -0
- package/lib/cloudflare/asset-manifest.js +2 -0
- package/lib/cloudflare/asset-manifest.js.map +1 -0
- package/lib/cloudflare/auth.d.ts +52 -0
- package/lib/cloudflare/auth.d.ts.map +1 -0
- package/lib/cloudflare/auth.js +114 -0
- package/lib/cloudflare/auth.js.map +1 -0
- package/lib/cloudflare/bindings.d.ts +244 -0
- package/lib/cloudflare/bindings.d.ts.map +1 -0
- package/lib/cloudflare/bindings.js +7 -0
- package/lib/cloudflare/bindings.js.map +1 -0
- package/lib/cloudflare/generate-asset-manifest.d.ts +3 -0
- package/lib/cloudflare/generate-asset-manifest.d.ts.map +1 -0
- package/lib/cloudflare/generate-asset-manifest.js +69 -0
- package/lib/cloudflare/generate-asset-manifest.js.map +1 -0
- package/lib/cloudflare/index.d.ts +6 -0
- package/lib/cloudflare/index.d.ts.map +1 -0
- package/lib/cloudflare/index.js +6 -0
- package/lib/cloudflare/index.js.map +1 -0
- package/lib/cloudflare/kv-namespace.d.ts +61 -0
- package/lib/cloudflare/kv-namespace.d.ts.map +1 -0
- package/lib/cloudflare/kv-namespace.js +93 -0
- package/lib/cloudflare/kv-namespace.js.map +1 -0
- package/lib/cloudflare/state.d.ts +83 -0
- package/lib/cloudflare/state.d.ts.map +1 -0
- package/lib/cloudflare/state.js +109 -0
- package/lib/cloudflare/state.js.map +1 -0
- package/lib/cloudflare/static-site-router.d.ts +10 -0
- package/lib/cloudflare/static-site-router.d.ts.map +1 -0
- package/lib/cloudflare/static-site-router.js +88 -0
- package/lib/cloudflare/static-site-router.js.map +1 -0
- package/lib/cloudflare/static-site.d.ts +166 -0
- package/lib/cloudflare/static-site.d.ts.map +1 -0
- package/lib/cloudflare/static-site.js +152 -0
- package/lib/cloudflare/static-site.js.map +1 -0
- package/lib/cloudflare/types.d.ts +52 -0
- package/lib/cloudflare/types.d.ts.map +1 -0
- package/lib/cloudflare/types.js +21 -0
- package/lib/cloudflare/types.js.map +1 -0
- package/lib/cloudflare/upload-asset-manifest.d.ts +12 -0
- package/lib/cloudflare/upload-asset-manifest.d.ts.map +1 -0
- package/lib/cloudflare/upload-asset-manifest.js +55 -0
- package/lib/cloudflare/upload-asset-manifest.js.map +1 -0
- package/lib/cloudflare/worker.d.ts +87 -0
- package/lib/cloudflare/worker.d.ts.map +1 -0
- package/lib/cloudflare/worker.js +364 -0
- package/lib/cloudflare/worker.js.map +1 -0
- package/lib/esbuild.d.ts +82 -0
- package/lib/esbuild.d.ts.map +1 -1
- package/lib/esbuild.js +24 -17
- package/lib/esbuild.js.map +1 -1
- package/lib/fs.d.ts +1 -1
- package/lib/global.d.ts.map +1 -1
- package/lib/global.js +3 -1
- package/lib/global.js.map +1 -1
- package/lib/index.d.ts +0 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +0 -1
- package/lib/index.js.map +1 -1
- package/lib/main.js +1 -1
- package/lib/main.js.map +1 -1
- package/lib/output.d.ts +17 -13
- package/lib/output.d.ts.map +1 -1
- package/lib/output.js +2 -2
- package/lib/output.js.map +1 -1
- package/lib/resource.d.ts +3 -2
- package/lib/resource.d.ts.map +1 -1
- package/lib/resource.js +2 -2
- package/lib/resource.js.map +1 -1
- package/lib/utils/content-type.d.ts +8 -0
- package/lib/utils/content-type.d.ts.map +1 -0
- package/lib/utils/content-type.js +41 -0
- package/lib/utils/content-type.js.map +1 -0
- package/package.json +26 -8
- package/src/apply.ts +5 -5
- package/src/aws/index.ts +1 -0
- package/src/aws/ses.ts +346 -0
- package/src/cloudflare/api.ts +276 -0
- package/src/cloudflare/asset-manifest.ts +16 -0
- package/src/cloudflare/auth.ts +187 -0
- package/src/cloudflare/bindings.ts +286 -0
- package/src/cloudflare/generate-asset-manifest.ts +93 -0
- package/src/cloudflare/index.ts +5 -0
- package/src/cloudflare/kv-namespace.ts +195 -0
- package/src/cloudflare/state.ts +138 -0
- package/src/cloudflare/static-site-router.ts +108 -0
- package/src/cloudflare/static-site.ts +379 -0
- package/src/cloudflare/types.ts +71 -0
- package/src/cloudflare/upload-asset-manifest.ts +83 -0
- package/src/cloudflare/worker.ts +568 -0
- package/src/esbuild.ts +31 -22
- package/src/global.ts +1 -0
- package/src/index.ts +0 -1
- package/src/main.ts +1 -1
- package/src/output.ts +32 -32
- package/src/resource.ts +11 -5
- package/src/utils/content-type.ts +42 -0
- package/lib/$.d.ts +0 -7
- package/lib/$.d.ts.map +0 -1
- package/lib/$.js +0 -31
- package/lib/$.js.map +0 -1
- package/lib/agent/ai.d.ts +0 -40
- package/lib/agent/ai.d.ts.map +0 -1
- package/lib/agent/ai.js +0 -132
- package/lib/agent/ai.js.map +0 -1
- package/lib/agent/anthropic.d.ts +0 -9
- package/lib/agent/anthropic.d.ts.map +0 -1
- package/lib/agent/anthropic.js +0 -25
- package/lib/agent/anthropic.js.map +0 -1
- package/lib/agent/dependencies.d.ts +0 -4
- package/lib/agent/dependencies.d.ts.map +0 -1
- package/lib/agent/dependencies.js +0 -48
- package/lib/agent/dependencies.js.map +0 -1
- package/lib/agent/file-context.d.ts +0 -13
- package/lib/agent/file-context.d.ts.map +0 -1
- package/lib/agent/file-context.js +0 -6
- package/lib/agent/file-context.js.map +0 -1
- package/lib/agent/index.d.ts +0 -10
- package/lib/agent/index.d.ts.map +0 -1
- package/lib/agent/index.js +0 -10
- package/lib/agent/index.js.map +0 -1
- package/lib/agent/model.d.ts +0 -8
- package/lib/agent/model.d.ts.map +0 -1
- package/lib/agent/model.js +0 -29
- package/lib/agent/model.js.map +0 -1
- package/lib/agent/module.d.ts +0 -81
- package/lib/agent/module.d.ts.map +0 -1
- package/lib/agent/module.js +0 -309
- package/lib/agent/module.js.map +0 -1
- package/lib/agent/openai.d.ts +0 -6
- package/lib/agent/openai.d.ts.map +0 -1
- package/lib/agent/openai.js +0 -41
- package/lib/agent/openai.js.map +0 -1
- package/lib/agent/program.d.ts +0 -12
- package/lib/agent/program.d.ts.map +0 -1
- package/lib/agent/program.js +0 -21
- package/lib/agent/program.js.map +0 -1
- package/lib/agent/prompts.d.ts +0 -4
- package/lib/agent/prompts.d.ts.map +0 -1
- package/lib/agent/prompts.js +0 -11
- package/lib/agent/prompts.js.map +0 -1
- package/lib/agent/scrape.d.ts +0 -71
- package/lib/agent/scrape.d.ts.map +0 -1
- package/lib/agent/scrape.js +0 -45
- package/lib/agent/scrape.js.map +0 -1
- package/lib/aws/auto/docs.d.ts +0 -11
- package/lib/aws/auto/docs.d.ts.map +0 -1
- package/lib/aws/auto/docs.js +0 -56
- package/lib/aws/auto/docs.js.map +0 -1
- package/lib/aws/auto/index.d.ts +0 -5
- package/lib/aws/auto/index.d.ts.map +0 -1
- package/lib/aws/auto/index.js +0 -5
- package/lib/aws/auto/index.js.map +0 -1
- package/lib/aws/auto/resource.d.ts +0 -24
- package/lib/aws/auto/resource.d.ts.map +0 -1
- package/lib/aws/auto/resource.js +0 -194
- package/lib/aws/auto/resource.js.map +0 -1
- package/lib/aws/auto/service.d.ts +0 -10
- package/lib/aws/auto/service.d.ts.map +0 -1
- package/lib/aws/auto/service.js +0 -34
- package/lib/aws/auto/service.js.map +0 -1
- package/lib/aws/auto/spec.d.ts +0 -83
- package/lib/aws/auto/spec.d.ts.map +0 -1
- package/lib/aws/auto/spec.js +0 -58
- package/lib/aws/auto/spec.js.map +0 -1
- package/lib/markdown/design.d.ts +0 -17
- package/lib/markdown/design.d.ts.map +0 -1
- package/lib/markdown/design.js +0 -92
- package/lib/markdown/design.js.map +0 -1
- package/lib/markdown/extract.d.ts +0 -7
- package/lib/markdown/extract.d.ts.map +0 -1
- package/lib/markdown/extract.js +0 -10
- package/lib/markdown/extract.js.map +0 -1
- package/lib/markdown/index.d.ts +0 -4
- package/lib/markdown/index.d.ts.map +0 -1
- package/lib/markdown/index.js +0 -4
- package/lib/markdown/index.js.map +0 -1
- package/lib/markdown/requirements.d.ts +0 -79
- package/lib/markdown/requirements.d.ts.map +0 -1
- package/lib/markdown/requirements.js +0 -105
- package/lib/markdown/requirements.js.map +0 -1
- package/lib/typescript/check-omission.d.ts +0 -2
- package/lib/typescript/check-omission.d.ts.map +0 -1
- package/lib/typescript/check-omission.js +0 -43
- package/lib/typescript/check-omission.js.map +0 -1
- package/lib/typescript/debug-type-errors.d.ts +0 -3
- package/lib/typescript/debug-type-errors.d.ts.map +0 -1
- package/lib/typescript/debug-type-errors.js +0 -35
- package/lib/typescript/debug-type-errors.js.map +0 -1
- package/lib/typescript/extract.d.ts +0 -7
- package/lib/typescript/extract.d.ts.map +0 -1
- package/lib/typescript/extract.js +0 -10
- package/lib/typescript/extract.js.map +0 -1
- package/lib/typescript/index.d.ts +0 -7
- package/lib/typescript/index.d.ts.map +0 -1
- package/lib/typescript/index.js +0 -7
- package/lib/typescript/index.js.map +0 -1
- package/lib/typescript/install-dependencies.d.ts +0 -29
- package/lib/typescript/install-dependencies.d.ts.map +0 -1
- package/lib/typescript/install-dependencies.js +0 -52
- package/lib/typescript/install-dependencies.js.map +0 -1
- package/lib/typescript/package.d.ts +0 -157
- package/lib/typescript/package.d.ts.map +0 -1
- package/lib/typescript/package.js +0 -115
- package/lib/typescript/package.js.map +0 -1
- package/lib/typescript/repair-omissions.d.ts +0 -3
- package/lib/typescript/repair-omissions.d.ts.map +0 -1
- package/lib/typescript/repair-omissions.js +0 -23
- package/lib/typescript/repair-omissions.js.map +0 -1
- package/lib/typescript/repair.d.ts +0 -3
- package/lib/typescript/repair.d.ts.map +0 -1
- package/lib/typescript/repair.js +0 -34
- package/lib/typescript/repair.js.map +0 -1
- package/lib/typescript/tsconfig.d.ts +0 -469
- package/lib/typescript/tsconfig.d.ts.map +0 -1
- package/lib/typescript/tsconfig.js +0 -143
- package/lib/typescript/tsconfig.js.map +0 -1
- package/lib/typescript/typescript.d.ts +0 -107
- package/lib/typescript/typescript.d.ts.map +0 -1
- package/lib/typescript/typescript.js +0 -180
- package/lib/typescript/typescript.js.map +0 -1
- package/lib/typescript/validate.d.ts +0 -10
- package/lib/typescript/validate.d.ts.map +0 -1
- package/lib/typescript/validate.js +0 -49
- package/lib/typescript/validate.js.map +0 -1
- package/src/$.ts +0 -36
- package/src/agent/ai.ts +0 -215
- package/src/agent/anthropic.ts +0 -31
- package/src/agent/dependencies.ts +0 -62
- package/src/agent/file-context.ts +0 -8
- package/src/agent/index.ts +0 -9
- package/src/agent/model.ts +0 -39
- package/src/agent/module.ts +0 -418
- package/src/agent/openai.ts +0 -50
- package/src/agent/program.md +0 -38
- package/src/agent/program.ts +0 -37
- package/src/agent/prompts.ts +0 -20
- package/src/agent/scrape.ts +0 -47
- package/src/aws/auto/cfn.json +0 -225310
- package/src/aws/auto/docs.ts +0 -73
- package/src/aws/auto/index.ts +0 -4
- package/src/aws/auto/resource.ts +0 -269
- package/src/aws/auto/service.ts +0 -51
- package/src/aws/auto/spec.ts +0 -160
- package/src/markdown/design.ts +0 -125
- package/src/markdown/extract.ts +0 -9
- package/src/markdown/index.ts +0 -3
- package/src/markdown/requirements.ts +0 -135
- package/src/typescript/check-omission.ts +0 -47
- package/src/typescript/debug-type-errors.ts +0 -42
- package/src/typescript/extract.ts +0 -9
- package/src/typescript/index.ts +0 -6
- package/src/typescript/install-dependencies.ts +0 -61
- package/src/typescript/package.ts +0 -143
- package/src/typescript/repair-omissions.ts +0 -31
- package/src/typescript/repair.ts +0 -45
- package/src/typescript/tsconfig.ts +0 -170
- package/src/typescript/typescript.ts +0 -217
- 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
|
+
}
|