alchemy 0.1.12 → 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.
- package/lib/$.d.ts +12 -0
- package/lib/$.d.ts.map +1 -0
- package/lib/$.js +42 -0
- package/lib/$.js.map +1 -0
- package/lib/alchemize.d.ts.map +1 -1
- package/lib/alchemize.js +7 -0
- package/lib/alchemize.js.map +1 -1
- package/lib/apply.d.ts +2 -2
- package/lib/apply.d.ts.map +1 -1
- package/lib/apply.js +1 -1
- package/lib/apply.js.map +1 -1
- package/lib/cloudflare/api.d.ts +4 -0
- package/lib/cloudflare/api.d.ts.map +1 -1
- package/lib/cloudflare/api.js +6 -0
- package/lib/cloudflare/api.js.map +1 -1
- package/lib/cloudflare/bindings.d.ts +14 -4
- package/lib/cloudflare/bindings.d.ts.map +1 -1
- package/lib/cloudflare/bindings.js +0 -5
- package/lib/cloudflare/bindings.js.map +1 -1
- package/lib/cloudflare/durable-object-namespace.d.ts +23 -0
- package/lib/cloudflare/durable-object-namespace.d.ts.map +1 -0
- package/lib/cloudflare/durable-object-namespace.js +26 -0
- package/lib/cloudflare/durable-object-namespace.js.map +1 -0
- package/lib/cloudflare/index.d.ts +1 -0
- package/lib/cloudflare/index.d.ts.map +1 -1
- package/lib/cloudflare/index.js +1 -0
- package/lib/cloudflare/index.js.map +1 -1
- package/lib/cloudflare/kv-namespace.js +1 -1
- package/lib/cloudflare/kv-namespace.js.map +1 -1
- package/lib/cloudflare/static-site-router.d.ts +11 -2
- package/lib/cloudflare/static-site-router.d.ts.map +1 -1
- package/lib/cloudflare/static-site-router.js +98 -76
- package/lib/cloudflare/static-site-router.js.map +1 -1
- package/lib/cloudflare/static-site.d.ts +15 -15
- package/lib/cloudflare/static-site.d.ts.map +1 -1
- package/lib/cloudflare/static-site.js +41 -25
- package/lib/cloudflare/static-site.js.map +1 -1
- package/lib/cloudflare/worker-metadata.d.ts +130 -0
- package/lib/cloudflare/worker-metadata.d.ts.map +1 -0
- package/lib/cloudflare/worker-metadata.js +2 -0
- package/lib/cloudflare/worker-metadata.js.map +1 -0
- package/lib/cloudflare/worker-migration.d.ts +110 -0
- package/lib/cloudflare/worker-migration.d.ts.map +1 -0
- package/lib/cloudflare/worker-migration.js +11 -0
- package/lib/cloudflare/worker-migration.js.map +1 -0
- package/lib/cloudflare/worker.d.ts +29 -11
- package/lib/cloudflare/worker.d.ts.map +1 -1
- package/lib/cloudflare/worker.js +316 -322
- package/lib/cloudflare/worker.js.map +1 -1
- package/lib/destroy.d.ts +1 -1
- package/lib/destroy.d.ts.map +1 -1
- package/lib/destroy.js +2 -1
- package/lib/destroy.js.map +1 -1
- package/lib/esbuild.d.ts +1 -1
- package/lib/esbuild.d.ts.map +1 -1
- package/lib/esbuild.js +3 -1
- package/lib/esbuild.js.map +1 -1
- package/lib/global.d.ts +0 -2
- package/lib/global.d.ts.map +1 -1
- package/lib/global.js +0 -2
- package/lib/global.js.map +1 -1
- package/lib/index.d.ts +2 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -1
- package/lib/output.d.ts +4 -3
- package/lib/output.d.ts.map +1 -1
- package/lib/output.js +10 -3
- package/lib/output.js.map +1 -1
- package/lib/print.d.ts +7 -0
- package/lib/print.d.ts.map +1 -0
- package/lib/print.js +10 -0
- package/lib/print.js.map +1 -0
- package/lib/resource.d.ts +8 -4
- package/lib/resource.d.ts.map +1 -1
- package/lib/resource.js +125 -91
- package/lib/resource.js.map +1 -1
- package/lib/scope.d.ts +3 -0
- package/lib/scope.d.ts.map +1 -1
- package/lib/scope.js +4 -12
- package/lib/scope.js.map +1 -1
- package/package.json +3 -2
- package/src/$.ts +69 -0
- package/src/alchemize.ts +12 -0
- package/src/apply.ts +4 -4
- package/src/cloudflare/api.ts +6 -0
- package/src/cloudflare/bindings.ts +37 -26
- package/src/cloudflare/durable-object-namespace.ts +43 -0
- package/src/cloudflare/index.ts +1 -0
- package/src/cloudflare/kv-namespace.ts +1 -1
- package/src/cloudflare/static-site-router.ts +124 -82
- package/src/cloudflare/static-site.ts +63 -47
- package/src/cloudflare/worker-metadata.ts +154 -0
- package/src/cloudflare/worker-migration.ts +145 -0
- package/src/cloudflare/worker.ts +526 -428
- package/src/destroy.ts +2 -2
- package/src/esbuild.ts +3 -0
- package/src/global.ts +0 -3
- package/src/index.ts +2 -1
- package/src/output.ts +24 -8
- package/src/print.ts +18 -0
- package/src/resource.ts +156 -115
- package/src/scope.ts +7 -12
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { WorkerBinding } from "./bindings";
|
|
2
|
+
|
|
3
|
+
export interface DurableObjectNamespaceInput {
|
|
4
|
+
bindingName: string;
|
|
5
|
+
className: string;
|
|
6
|
+
scriptName?: string | undefined;
|
|
7
|
+
environment?: string | undefined;
|
|
8
|
+
sqlite?: boolean | undefined;
|
|
9
|
+
namespaceId?: string | undefined;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function isDurableObjectNamespace(
|
|
13
|
+
binding: WorkerBinding,
|
|
14
|
+
): binding is DurableObjectNamespace {
|
|
15
|
+
return (
|
|
16
|
+
binding.type === "durable_object_namespace" &&
|
|
17
|
+
typeof (binding as any).bindingName === "string"
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class DurableObjectNamespace implements DurableObjectNamespaceInput {
|
|
22
|
+
public readonly type = "durable_object_namespace" as const;
|
|
23
|
+
// alias for bindingName to be consistent with other bindings
|
|
24
|
+
public readonly name: string;
|
|
25
|
+
public readonly bindingName: string;
|
|
26
|
+
public readonly className: string;
|
|
27
|
+
public readonly scriptName?: string | undefined;
|
|
28
|
+
public readonly environment?: string | undefined;
|
|
29
|
+
public readonly sqlite?: boolean | undefined;
|
|
30
|
+
public readonly namespaceId?: string | undefined;
|
|
31
|
+
|
|
32
|
+
constructor(
|
|
33
|
+
public readonly id: string,
|
|
34
|
+
input: DurableObjectNamespaceInput,
|
|
35
|
+
) {
|
|
36
|
+
this.bindingName = input.bindingName;
|
|
37
|
+
this.name = this.bindingName;
|
|
38
|
+
this.className = input.className;
|
|
39
|
+
this.scriptName = input.scriptName;
|
|
40
|
+
this.environment = input.environment;
|
|
41
|
+
this.sqlite = input.sqlite;
|
|
42
|
+
}
|
|
43
|
+
}
|
package/src/cloudflare/index.ts
CHANGED
|
@@ -121,7 +121,7 @@ export class KVNamespace extends Resource(
|
|
|
121
121
|
errors: [{ message: createResponse.statusText }],
|
|
122
122
|
}));
|
|
123
123
|
throw new Error(
|
|
124
|
-
`Error creating KV namespace: ${errorData.errors?.[0]?.message || createResponse.statusText}`,
|
|
124
|
+
`Error creating KV namespace '${props.title}': ${errorData.errors?.[0]?.message || createResponse.statusText}`,
|
|
125
125
|
);
|
|
126
126
|
}
|
|
127
127
|
|
|
@@ -1,108 +1,150 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
|
|
1
3
|
// see: https://developers.cloudflare.com/workers/runtime-apis/cache/
|
|
2
|
-
declare var caches:
|
|
4
|
+
declare var caches: {
|
|
5
|
+
default: Cache;
|
|
6
|
+
};
|
|
3
7
|
|
|
4
8
|
// injected by src/cloudflare/static-site.ts
|
|
5
9
|
declare var __ASSET_MANIFEST__: Record<string, string>;
|
|
6
10
|
|
|
7
|
-
export
|
|
11
|
+
export type Env = {
|
|
8
12
|
ASSETS: KVNamespace;
|
|
9
13
|
INDEX_PAGE: string;
|
|
10
14
|
ERROR_PAGE?: string;
|
|
11
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Optional backend worker bound to this static site
|
|
17
|
+
* Used to handle requests that don't match any static files
|
|
18
|
+
*/
|
|
19
|
+
BACKEND_WORKER?: Service;
|
|
20
|
+
} & {
|
|
21
|
+
// the binding to route the fetch call to
|
|
22
|
+
[key in `ROUTE_${string}`]: Service;
|
|
23
|
+
} & {
|
|
24
|
+
// the route to match on, e.g. /api/*
|
|
25
|
+
[key in `__ROUTE_${string}`]: string;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
let isInit = false;
|
|
29
|
+
const app = new Hono<{ Bindings: Env }>();
|
|
12
30
|
|
|
13
31
|
export default {
|
|
14
32
|
async fetch(request: Request, env: Env): Promise<Response> {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
33
|
+
if (!isInit) {
|
|
34
|
+
isInit = true;
|
|
35
|
+
for (const [key, value] of Object.entries(env)) {
|
|
36
|
+
if (key.startsWith("ROUTE_")) {
|
|
37
|
+
console.log(key, value);
|
|
38
|
+
const service = value as Service;
|
|
39
|
+
const patternKey = `__${key}`;
|
|
40
|
+
if (!(patternKey in env)) {
|
|
41
|
+
throw new Error(`Missing pattern key: ${patternKey}`);
|
|
42
|
+
}
|
|
43
|
+
const pattern = (env as any)[`__${key}`];
|
|
44
|
+
console.log("pattern", pattern);
|
|
45
|
+
// TODO(sam): we should support narrowing down METHOD
|
|
46
|
+
app.all(pattern, (ctx) => service.fetch(ctx.req.raw));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
28
49
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
50
|
+
return app.fetch(request, env);
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// fall back to assuming the request is a static file
|
|
55
|
+
app.notFound(async (ctx) => {
|
|
56
|
+
console.log("not found");
|
|
57
|
+
const request = ctx.req;
|
|
58
|
+
const env = ctx.env;
|
|
59
|
+
const url = new URL(request.url);
|
|
60
|
+
const pathname = url.pathname.replace(/^\//, "");
|
|
61
|
+
const filePath = pathname === "" ? env.INDEX_PAGE : pathname;
|
|
62
|
+
|
|
63
|
+
// Return from cache if available
|
|
64
|
+
const cachedResponse = await lookupCache();
|
|
65
|
+
if (cachedResponse) {
|
|
66
|
+
return cachedResponse;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Fetch from KV
|
|
70
|
+
{
|
|
71
|
+
const object = await env.ASSETS.getWithMetadata(filePath);
|
|
72
|
+
if (object.value) {
|
|
73
|
+
return await respond(200, filePath, object);
|
|
34
74
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
75
|
+
}
|
|
76
|
+
{
|
|
77
|
+
const guess = filePath + (filePath.endsWith("/") ? "" : "/") + "index.html";
|
|
78
|
+
const object = await env.ASSETS.getWithMetadata(guess);
|
|
79
|
+
if (object.value) {
|
|
80
|
+
return await respond(200, guess, object);
|
|
39
81
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const object = await env.ASSETS.getWithMetadata(env.INDEX_PAGE);
|
|
47
|
-
if (object.value) return await respond(200, env.INDEX_PAGE, object);
|
|
82
|
+
}
|
|
83
|
+
{
|
|
84
|
+
const guess = filePath + ".html";
|
|
85
|
+
const object = await env.ASSETS.getWithMetadata(guess);
|
|
86
|
+
if (object.value) {
|
|
87
|
+
return await respond(200, guess, object);
|
|
48
88
|
}
|
|
89
|
+
}
|
|
49
90
|
|
|
50
|
-
|
|
51
|
-
|
|
91
|
+
// Handle error page
|
|
92
|
+
if (env.ERROR_PAGE) {
|
|
93
|
+
const object = await env.ASSETS.getWithMetadata(env.ERROR_PAGE);
|
|
94
|
+
if (object.value) {
|
|
95
|
+
return await respond(404, env.ERROR_PAGE, object);
|
|
96
|
+
}
|
|
97
|
+
} else {
|
|
98
|
+
const object = await env.ASSETS.getWithMetadata(env.INDEX_PAGE);
|
|
99
|
+
if (object.value) {
|
|
100
|
+
return await respond(200, env.INDEX_PAGE, object);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
52
103
|
|
|
53
|
-
|
|
54
|
-
const cache = caches.default;
|
|
55
|
-
const r = await cache.match(request);
|
|
104
|
+
return new Response("Page Not Found", { status: 404 });
|
|
56
105
|
|
|
57
|
-
|
|
58
|
-
|
|
106
|
+
async function lookupCache() {
|
|
107
|
+
const cache = caches.default;
|
|
108
|
+
const r = await cache.match(request.url);
|
|
59
109
|
|
|
60
|
-
|
|
61
|
-
|
|
110
|
+
// cache does not exist
|
|
111
|
+
if (!r) return;
|
|
62
112
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
113
|
+
// cache exists but etag does not match
|
|
114
|
+
if (r.headers.get("etag") !== __ASSET_MANIFEST__[filePath]) return;
|
|
66
115
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
116
|
+
// cache exists
|
|
117
|
+
return r;
|
|
118
|
+
}
|
|
71
119
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
) {
|
|
77
|
-
// build response
|
|
78
|
-
const headers = new Headers();
|
|
79
|
-
if (__ASSET_MANIFEST__[filePath]) {
|
|
80
|
-
headers.set("etag", __ASSET_MANIFEST__[filePath]);
|
|
81
|
-
headers.set("content-type", object.metadata.contentType);
|
|
82
|
-
headers.set("cache-control", object.metadata.cacheControl);
|
|
83
|
-
}
|
|
84
|
-
// TODO: do we need base64 encoded here?
|
|
85
|
-
// const response = new Response(base64ToArrayBuffer(object.value), {
|
|
86
|
-
const response = new Response(object.value, {
|
|
87
|
-
status,
|
|
88
|
-
headers,
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
if (request.method === "GET") {
|
|
92
|
-
await saveCache(response);
|
|
93
|
-
}
|
|
120
|
+
async function saveCache(response: Response) {
|
|
121
|
+
const cache = caches.default;
|
|
122
|
+
await cache.put(request.url, response.clone());
|
|
123
|
+
}
|
|
94
124
|
|
|
95
|
-
|
|
125
|
+
async function respond(
|
|
126
|
+
status: number,
|
|
127
|
+
filePath: string,
|
|
128
|
+
object: KVNamespaceGetWithMetadataResult<any, any>,
|
|
129
|
+
) {
|
|
130
|
+
// build response
|
|
131
|
+
const headers = new Headers();
|
|
132
|
+
if (__ASSET_MANIFEST__[filePath]) {
|
|
133
|
+
headers.set("etag", __ASSET_MANIFEST__[filePath]);
|
|
134
|
+
headers.set("content-type", object.metadata.contentType);
|
|
135
|
+
headers.set("cache-control", object.metadata.cacheControl);
|
|
136
|
+
}
|
|
137
|
+
// TODO: do we need base64 encoded here?
|
|
138
|
+
// const response = new Response(base64ToArrayBuffer(object.value), {
|
|
139
|
+
const response = new Response(object.value, {
|
|
140
|
+
status,
|
|
141
|
+
headers,
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
if (request.method === "GET") {
|
|
145
|
+
await saveCache(response);
|
|
96
146
|
}
|
|
97
|
-
},
|
|
98
|
-
};
|
|
99
147
|
|
|
100
|
-
|
|
101
|
-
const binaryString = atob(base64);
|
|
102
|
-
const len = binaryString.length;
|
|
103
|
-
const bytes = new Uint8Array(len);
|
|
104
|
-
for (let i = 0; i < len; i++) {
|
|
105
|
-
bytes[i] = binaryString.charCodeAt(i);
|
|
148
|
+
return response;
|
|
106
149
|
}
|
|
107
|
-
|
|
108
|
-
}
|
|
150
|
+
});
|
|
@@ -4,15 +4,17 @@ import path from "path";
|
|
|
4
4
|
import { promisify } from "util";
|
|
5
5
|
import { apply } from "../apply";
|
|
6
6
|
import type { BundleProps } from "../esbuild";
|
|
7
|
+
import type { Input } from "../input";
|
|
7
8
|
import { type Context, Resource } from "../resource";
|
|
8
9
|
import { createCloudflareApi } from "./api";
|
|
9
|
-
import type {
|
|
10
|
+
import type { WorkerBindingSpec } from "./bindings";
|
|
10
11
|
import { generateAssetManifest } from "./generate-asset-manifest";
|
|
11
12
|
import { KVNamespace } from "./kv-namespace";
|
|
12
13
|
import { uploadAssetManifest } from "./upload-asset-manifest";
|
|
13
|
-
import type { WorkerProps } from "./worker";
|
|
14
14
|
import { Worker } from "./worker";
|
|
15
15
|
|
|
16
|
+
const __dirname = import.meta.dirname;
|
|
17
|
+
|
|
16
18
|
/**
|
|
17
19
|
* Idea of using KV with timeout inspired by SST: https://github.com/sst/sst/blob/dev/platform/src/components/cloudflare/static-site.ts
|
|
18
20
|
*/
|
|
@@ -32,12 +34,6 @@ export interface StaticSiteProps {
|
|
|
32
34
|
*/
|
|
33
35
|
dir: string;
|
|
34
36
|
|
|
35
|
-
/**
|
|
36
|
-
* Routes to associate with this site
|
|
37
|
-
* Format: example.com/* or *.example.com/*
|
|
38
|
-
*/
|
|
39
|
-
routes?: string[];
|
|
40
|
-
|
|
41
37
|
/**
|
|
42
38
|
* Custom Worker script to serve the site
|
|
43
39
|
* If not provided, a default script will be used
|
|
@@ -95,11 +91,6 @@ export interface StaticSiteProps {
|
|
|
95
91
|
}[];
|
|
96
92
|
};
|
|
97
93
|
|
|
98
|
-
/**
|
|
99
|
-
* Additional Worker bindings to include
|
|
100
|
-
*/
|
|
101
|
-
additionalBindings?: WorkerProps["bindings"];
|
|
102
|
-
|
|
103
94
|
/**
|
|
104
95
|
* Whether the site should be deployed to production
|
|
105
96
|
* @default true
|
|
@@ -124,7 +115,17 @@ export interface StaticSiteProps {
|
|
|
124
115
|
command?: string;
|
|
125
116
|
};
|
|
126
117
|
|
|
118
|
+
/**
|
|
119
|
+
* Bundle options for the worker script
|
|
120
|
+
*/
|
|
127
121
|
bundle?: Partial<BundleProps>;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Additional workers to route requests to.
|
|
125
|
+
*/
|
|
126
|
+
routes?: {
|
|
127
|
+
[key: string]: Worker;
|
|
128
|
+
};
|
|
128
129
|
}
|
|
129
130
|
|
|
130
131
|
/**
|
|
@@ -151,11 +152,6 @@ export interface StaticSiteOutput {
|
|
|
151
152
|
*/
|
|
152
153
|
directory: string;
|
|
153
154
|
|
|
154
|
-
/**
|
|
155
|
-
* Routes to associate with this site
|
|
156
|
-
*/
|
|
157
|
-
routes?: string[];
|
|
158
|
-
|
|
159
155
|
/**
|
|
160
156
|
* Worker script format
|
|
161
157
|
*/
|
|
@@ -205,6 +201,11 @@ export interface StaticSiteOutput {
|
|
|
205
201
|
* The URL of the deployed site
|
|
206
202
|
*/
|
|
207
203
|
url?: string;
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Information about the backend worker if configured
|
|
207
|
+
*/
|
|
208
|
+
routes?: Record<string, string>;
|
|
208
209
|
}
|
|
209
210
|
|
|
210
211
|
export class StaticSite extends Resource(
|
|
@@ -245,13 +246,15 @@ export class StaticSite extends Resource(
|
|
|
245
246
|
// Run build command if provided
|
|
246
247
|
if (props.build?.command) {
|
|
247
248
|
try {
|
|
248
|
-
|
|
249
|
+
if (!ctx.quiet) {
|
|
250
|
+
console.log(props.build.command);
|
|
251
|
+
}
|
|
249
252
|
const execAsync = promisify(exec);
|
|
250
253
|
const { stdout, stderr } = await execAsync(props.build.command, {
|
|
251
254
|
cwd: process.cwd(),
|
|
252
255
|
});
|
|
253
256
|
|
|
254
|
-
if (stdout) console.log(stdout);
|
|
257
|
+
if (stdout && !ctx.quiet) console.log(stdout);
|
|
255
258
|
} catch (error: any) {
|
|
256
259
|
// Log detailed error information
|
|
257
260
|
console.error(`Build command failed with exit code ${error.code}`);
|
|
@@ -278,18 +281,17 @@ export class StaticSite extends Resource(
|
|
|
278
281
|
});
|
|
279
282
|
|
|
280
283
|
const [{ id: kvNamespaceId }, assetManifest] = await Promise.all([
|
|
281
|
-
apply(namespace
|
|
284
|
+
apply(namespace, {
|
|
285
|
+
quiet: ctx.quiet,
|
|
286
|
+
}),
|
|
282
287
|
generateAssetManifest(props.dir),
|
|
283
288
|
]);
|
|
284
289
|
|
|
285
290
|
// Step 3: Upload assets to KV
|
|
286
291
|
await uploadAssetManifest(api, kvNamespaceId, assetManifest);
|
|
287
292
|
|
|
288
|
-
// Define the worker script path
|
|
289
|
-
const routerScriptPath = path.resolve(__dirname, "static-site-router.ts");
|
|
290
|
-
|
|
291
293
|
// Prepare the bindings for the worker
|
|
292
|
-
const bindings:
|
|
294
|
+
const bindings: Input<WorkerBindingSpec>[] = [
|
|
293
295
|
{
|
|
294
296
|
name: "ASSETS",
|
|
295
297
|
type: "kv_namespace",
|
|
@@ -311,9 +313,18 @@ export class StaticSite extends Resource(
|
|
|
311
313
|
});
|
|
312
314
|
}
|
|
313
315
|
|
|
314
|
-
|
|
315
|
-
if
|
|
316
|
-
|
|
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
|
+
}
|
|
317
328
|
}
|
|
318
329
|
|
|
319
330
|
// Create asset manifest banner for static site router
|
|
@@ -321,48 +332,52 @@ export class StaticSite extends Resource(
|
|
|
321
332
|
Object.fromEntries(assetManifest.map((item) => [item.key, item.hash])),
|
|
322
333
|
)};\n`;
|
|
323
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
|
+
};
|
|
324
345
|
const worker = new Worker(
|
|
325
346
|
"worker",
|
|
326
347
|
{
|
|
327
348
|
name: siteName,
|
|
328
349
|
url: true,
|
|
329
350
|
format: props.format || "esm",
|
|
330
|
-
routes: props.routes || [],
|
|
331
351
|
// If a custom worker script is provided, use it, otherwise use the entrypoint from router
|
|
332
352
|
...(props.workerScript
|
|
333
353
|
? { script: props.workerScript }
|
|
334
354
|
: {
|
|
335
|
-
entrypoint:
|
|
336
|
-
|
|
337
|
-
...props.bundle,
|
|
338
|
-
options: {
|
|
339
|
-
...props.bundle?.options,
|
|
340
|
-
banner: {
|
|
341
|
-
js: assetManifestBanner,
|
|
342
|
-
...props.bundle?.options?.banner,
|
|
343
|
-
},
|
|
344
|
-
},
|
|
345
|
-
},
|
|
355
|
+
entrypoint: path.resolve(__dirname, "static-site-router.ts"),
|
|
356
|
+
bundle: bundleOptions,
|
|
346
357
|
}),
|
|
347
358
|
bindings,
|
|
359
|
+
env: {
|
|
360
|
+
...Object.fromEntries(
|
|
361
|
+
Object.entries(routes).map(([key, value]) => [
|
|
362
|
+
`__ROUTE_${value}`,
|
|
363
|
+
key,
|
|
364
|
+
]),
|
|
365
|
+
),
|
|
366
|
+
},
|
|
348
367
|
},
|
|
349
368
|
// place a dependency on the namespace
|
|
350
369
|
namespace.id,
|
|
351
370
|
);
|
|
352
371
|
|
|
353
|
-
// Step 4: Create or update the worker
|
|
354
|
-
const { id: workerId, url } = await apply(worker);
|
|
355
|
-
|
|
356
372
|
// Get current timestamp
|
|
357
373
|
const now = Date.now();
|
|
358
374
|
|
|
359
375
|
// Construct the output
|
|
360
|
-
const output: StaticSiteOutput = {
|
|
376
|
+
const output: Input<StaticSiteOutput> = {
|
|
361
377
|
id: siteName,
|
|
362
|
-
workerId,
|
|
378
|
+
workerId: worker.id,
|
|
363
379
|
name: siteName,
|
|
364
380
|
directory: props.dir,
|
|
365
|
-
routes: props.routes || [],
|
|
366
381
|
format: props.format || "esm",
|
|
367
382
|
errorPage: props.errorPage,
|
|
368
383
|
indexPage,
|
|
@@ -371,7 +386,8 @@ export class StaticSite extends Resource(
|
|
|
371
386
|
updatedAt: now,
|
|
372
387
|
domain: props.domain,
|
|
373
388
|
production: props.production !== false,
|
|
374
|
-
url,
|
|
389
|
+
url: worker.url,
|
|
390
|
+
routes,
|
|
375
391
|
};
|
|
376
392
|
|
|
377
393
|
return output;
|
|
@@ -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
|
+
}
|