alchemy 0.1.18 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/alchemy.d.ts +67 -0
- package/lib/alchemy.js +40 -0
- package/lib/apply.d.ts +3 -20
- package/lib/apply.js +86 -82
- package/lib/aws/account-id.d.ts +0 -1
- package/lib/aws/account-id.js +0 -1
- package/lib/aws/bucket.d.ts +4 -7
- package/lib/aws/bucket.js +8 -12
- package/lib/aws/function.d.ts +4 -7
- package/lib/aws/function.js +9 -30
- package/lib/aws/index.d.ts +1 -1
- package/lib/aws/index.js +1 -1
- package/lib/aws/oidc/github-oidc-provider.d.ts +2 -6
- package/lib/aws/oidc/github-oidc-provider.js +10 -15
- package/lib/aws/oidc/index.d.ts +0 -1
- package/lib/aws/oidc/index.js +0 -1
- package/lib/aws/oidc/oidc-provider.d.ts +4 -6
- package/lib/aws/oidc/oidc-provider.js +9 -11
- package/lib/aws/policy-attachment.d.ts +9 -0
- package/lib/aws/policy-attachment.js +20 -0
- package/lib/aws/policy.d.ts +4 -16
- package/lib/aws/policy.js +9 -40
- package/lib/aws/queue.d.ts +4 -34
- package/lib/aws/queue.js +10 -20
- package/lib/aws/role.d.ts +4 -7
- package/lib/aws/role.js +17 -26
- package/lib/aws/ses.d.ts +4 -10
- package/lib/aws/ses.js +118 -131
- package/lib/aws/table.d.ts +4 -7
- package/lib/aws/table.js +8 -11
- package/lib/cloudflare/api.d.ts +0 -1
- package/lib/cloudflare/api.js +0 -1
- package/lib/cloudflare/asset-manifest.d.ts +0 -1
- package/lib/cloudflare/asset-manifest.js +0 -1
- package/lib/cloudflare/auth.d.ts +0 -1
- package/lib/cloudflare/auth.js +0 -1
- package/lib/cloudflare/bindings.d.ts +1 -1
- package/lib/cloudflare/bindings.js +3 -2
- package/lib/cloudflare/bound.d.ts +0 -1
- package/lib/cloudflare/bound.js +0 -1
- package/lib/cloudflare/bucket.d.ts +7 -15
- package/lib/cloudflare/bucket.js +12 -19
- package/lib/cloudflare/durable-object-namespace.d.ts +0 -3
- package/lib/cloudflare/durable-object-namespace.js +0 -4
- package/lib/cloudflare/generate-asset-manifest.d.ts +0 -1
- package/lib/cloudflare/generate-asset-manifest.js +1 -2
- package/lib/cloudflare/index.d.ts +0 -1
- package/lib/cloudflare/index.js +0 -1
- package/lib/cloudflare/kv-namespace.d.ts +6 -9
- package/lib/cloudflare/kv-namespace.js +16 -20
- package/lib/cloudflare/state.d.ts +0 -1
- package/lib/cloudflare/state.js +0 -1
- package/lib/cloudflare/static-site-router.d.ts +0 -1
- package/lib/cloudflare/static-site-router.js +0 -4
- package/lib/cloudflare/static-site.d.ts +5 -11
- package/lib/cloudflare/static-site.js +16 -28
- package/lib/cloudflare/types.d.ts +0 -1
- package/lib/cloudflare/types.js +0 -1
- package/lib/cloudflare/upload-asset-manifest.d.ts +0 -1
- package/lib/cloudflare/upload-asset-manifest.js +0 -1
- package/lib/cloudflare/worker-metadata.d.ts +0 -1
- package/lib/cloudflare/worker-metadata.js +0 -1
- package/lib/cloudflare/worker-migration.d.ts +0 -1
- package/lib/cloudflare/worker-migration.js +0 -1
- package/lib/cloudflare/worker.d.ts +8 -14
- package/lib/cloudflare/worker.js +37 -49
- package/lib/context.d.ts +58 -0
- package/lib/context.js +36 -0
- package/lib/destroy.d.ts +10 -13
- package/lib/destroy.js +104 -43
- package/lib/{esbuild.d.ts → esbuild/bundle.d.ts} +4 -18
- package/lib/{esbuild.js → esbuild/bundle.js} +10 -24
- package/lib/esbuild/index.d.ts +1 -0
- package/lib/esbuild/index.js +1 -0
- package/lib/fs/file.d.ts +13 -0
- package/lib/fs/file.js +20 -0
- package/lib/fs/folder.d.ts +10 -0
- package/lib/fs/folder.js +16 -0
- package/lib/fs/index.d.ts +2 -0
- package/lib/fs/index.js +2 -0
- package/lib/github/client.d.ts +0 -1
- package/lib/github/client.js +0 -1
- package/lib/github/index.d.ts +0 -1
- package/lib/github/index.js +0 -1
- package/lib/github/secret.d.ts +4 -6
- package/lib/github/secret.js +10 -12
- package/lib/index.d.ts +6 -10
- package/lib/index.js +5 -9
- package/lib/resource.d.ts +34 -62
- package/lib/resource.js +29 -270
- package/lib/scope.d.ts +35 -14
- package/lib/scope.js +78 -23
- package/lib/secret.d.ts +2 -7
- package/lib/secret.js +7 -20
- package/lib/state.d.ts +14 -10
- package/lib/state.js +15 -14
- package/lib/stripe/index.d.ts +0 -1
- package/lib/stripe/index.js +0 -1
- package/lib/stripe/price.d.ts +4 -5
- package/lib/stripe/price.js +10 -20
- package/lib/stripe/product.d.ts +4 -5
- package/lib/stripe/product.js +10 -20
- package/lib/stripe/webhook.d.ts +4 -6
- package/lib/stripe/webhook.js +12 -25
- package/lib/test/bun.d.ts +19 -0
- package/lib/test/bun.js +55 -0
- package/lib/{utils → util}/content-type.d.ts +0 -1
- package/lib/{utils → util}/content-type.js +0 -1
- package/lib/{encrypt.d.ts → util/encrypt.d.ts} +0 -1
- package/lib/{encrypt.js → util/encrypt.js} +0 -1
- package/lib/{error.d.ts → util/ignore.d.ts} +0 -1
- package/lib/{error.js → util/ignore.js} +0 -1
- package/lib/{utils → util}/retry.d.ts +0 -1
- package/lib/{utils → util}/retry.js +0 -1
- package/lib/util/serde.d.ts +3 -0
- package/lib/{serde.js → util/serde.js} +19 -10
- package/lib/util/slugify.d.ts +1 -0
- package/lib/util/slugify.js +3 -0
- package/package.json +5 -4
- package/src/alchemy.ts +120 -0
- package/src/apply.ts +109 -114
- package/src/aws/bucket.ts +11 -14
- package/src/aws/function.ts +13 -33
- package/src/aws/index.ts +1 -0
- package/src/aws/oidc/github-oidc-provider.ts +14 -19
- package/src/aws/oidc/oidc-provider.ts +19 -12
- package/src/aws/policy-attachment.ts +51 -0
- package/src/aws/policy.ts +15 -60
- package/src/aws/queue.ts +17 -21
- package/src/aws/role.ts +25 -28
- package/src/aws/ses.ts +150 -164
- package/src/aws/table.ts +15 -15
- package/src/cloudflare/bindings.ts +8 -0
- package/src/cloudflare/bucket.ts +39 -47
- package/src/cloudflare/durable-object-namespace.ts +0 -10
- package/src/cloudflare/generate-asset-manifest.ts +1 -1
- package/src/cloudflare/kv-namespace.ts +35 -33
- package/src/cloudflare/static-site-router.ts +0 -3
- package/src/cloudflare/static-site.ts +44 -60
- package/src/cloudflare/worker.ts +105 -111
- package/src/context.ts +122 -0
- package/src/destroy.ts +124 -73
- package/src/{esbuild.ts → esbuild/bundle.ts} +16 -28
- package/src/esbuild/index.ts +1 -0
- package/src/fs/file.ts +39 -0
- package/src/fs/folder.ts +32 -0
- package/src/fs/index.ts +2 -0
- package/src/github/secret.ts +19 -16
- package/src/index.ts +7 -15
- package/src/resource.ts +101 -462
- package/src/scope.ts +101 -36
- package/src/secret.ts +9 -32
- package/src/state.ts +30 -21
- package/src/stripe/price.ts +17 -22
- package/src/stripe/product.ts +17 -22
- package/src/stripe/webhook.ts +21 -27
- package/src/test/bun.ts +105 -0
- package/src/util/serde.ts +53 -0
- package/src/util/slugify.ts +3 -0
- package/lib/$.d.ts +0 -12
- package/lib/$.d.ts.map +0 -1
- package/lib/$.js +0 -42
- package/lib/$.js.map +0 -1
- package/lib/alchemize.d.ts +0 -47
- package/lib/alchemize.d.ts.map +0 -1
- package/lib/alchemize.js +0 -116
- package/lib/alchemize.js.map +0 -1
- package/lib/apply.d.ts.map +0 -1
- package/lib/apply.js.map +0 -1
- package/lib/aws/account-id.d.ts.map +0 -1
- package/lib/aws/account-id.js.map +0 -1
- package/lib/aws/bucket.d.ts.map +0 -1
- package/lib/aws/bucket.js.map +0 -1
- package/lib/aws/function.d.ts.map +0 -1
- package/lib/aws/function.js.map +0 -1
- package/lib/aws/index.d.ts.map +0 -1
- package/lib/aws/index.js.map +0 -1
- package/lib/aws/oidc/github-oidc-provider.d.ts.map +0 -1
- package/lib/aws/oidc/github-oidc-provider.js.map +0 -1
- package/lib/aws/oidc/index.d.ts.map +0 -1
- package/lib/aws/oidc/index.js.map +0 -1
- package/lib/aws/oidc/oidc-provider.d.ts.map +0 -1
- package/lib/aws/oidc/oidc-provider.js.map +0 -1
- package/lib/aws/policy.d.ts.map +0 -1
- package/lib/aws/policy.js.map +0 -1
- package/lib/aws/queue.d.ts.map +0 -1
- package/lib/aws/queue.js.map +0 -1
- package/lib/aws/role.d.ts.map +0 -1
- package/lib/aws/role.js.map +0 -1
- package/lib/aws/ses.d.ts.map +0 -1
- package/lib/aws/ses.js.map +0 -1
- package/lib/aws/table.d.ts.map +0 -1
- package/lib/aws/table.js.map +0 -1
- package/lib/cloudflare/api.d.ts.map +0 -1
- package/lib/cloudflare/api.js.map +0 -1
- package/lib/cloudflare/asset-manifest.d.ts.map +0 -1
- package/lib/cloudflare/asset-manifest.js.map +0 -1
- package/lib/cloudflare/auth.d.ts.map +0 -1
- package/lib/cloudflare/auth.js.map +0 -1
- package/lib/cloudflare/bindings.d.ts.map +0 -1
- package/lib/cloudflare/bindings.js.map +0 -1
- package/lib/cloudflare/bound.d.ts.map +0 -1
- package/lib/cloudflare/bound.js.map +0 -1
- package/lib/cloudflare/bucket.d.ts.map +0 -1
- package/lib/cloudflare/bucket.js.map +0 -1
- package/lib/cloudflare/durable-object-namespace.d.ts.map +0 -1
- package/lib/cloudflare/durable-object-namespace.js.map +0 -1
- package/lib/cloudflare/generate-asset-manifest.d.ts.map +0 -1
- package/lib/cloudflare/generate-asset-manifest.js.map +0 -1
- package/lib/cloudflare/index.d.ts.map +0 -1
- package/lib/cloudflare/index.js.map +0 -1
- package/lib/cloudflare/kv-namespace.d.ts.map +0 -1
- package/lib/cloudflare/kv-namespace.js.map +0 -1
- package/lib/cloudflare/state.d.ts.map +0 -1
- package/lib/cloudflare/state.js.map +0 -1
- package/lib/cloudflare/static-site-router.d.ts.map +0 -1
- package/lib/cloudflare/static-site-router.js.map +0 -1
- package/lib/cloudflare/static-site.d.ts.map +0 -1
- package/lib/cloudflare/static-site.js.map +0 -1
- package/lib/cloudflare/types.d.ts.map +0 -1
- package/lib/cloudflare/types.js.map +0 -1
- package/lib/cloudflare/upload-asset-manifest.d.ts.map +0 -1
- package/lib/cloudflare/upload-asset-manifest.js.map +0 -1
- package/lib/cloudflare/worker-metadata.d.ts.map +0 -1
- package/lib/cloudflare/worker-metadata.js.map +0 -1
- package/lib/cloudflare/worker-migration.d.ts.map +0 -1
- package/lib/cloudflare/worker-migration.js.map +0 -1
- package/lib/cloudflare/worker.d.ts.map +0 -1
- package/lib/cloudflare/worker.js.map +0 -1
- package/lib/destroy.d.ts.map +0 -1
- package/lib/destroy.js.map +0 -1
- package/lib/encrypt.d.ts.map +0 -1
- package/lib/encrypt.js.map +0 -1
- package/lib/error.d.ts.map +0 -1
- package/lib/error.js.map +0 -1
- package/lib/esbuild.d.ts.map +0 -1
- package/lib/esbuild.js.map +0 -1
- package/lib/fs.d.ts +0 -12
- package/lib/fs.d.ts.map +0 -1
- package/lib/fs.js +0 -41
- package/lib/fs.js.map +0 -1
- package/lib/github/client.d.ts.map +0 -1
- package/lib/github/client.js.map +0 -1
- package/lib/github/index.d.ts.map +0 -1
- package/lib/github/index.js.map +0 -1
- package/lib/github/secret.d.ts.map +0 -1
- package/lib/github/secret.js.map +0 -1
- package/lib/global.d.ts +0 -16
- package/lib/global.d.ts.map +0 -1
- package/lib/global.js +0 -42
- package/lib/global.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/input.d.ts +0 -7
- package/lib/input.d.ts.map +0 -1
- package/lib/input.js +0 -2
- package/lib/input.js.map +0 -1
- package/lib/main.d.ts +0 -3
- package/lib/main.d.ts.map +0 -1
- package/lib/main.js +0 -32
- package/lib/main.js.map +0 -1
- package/lib/output.d.ts +0 -25
- package/lib/output.d.ts.map +0 -1
- package/lib/output.js +0 -23
- package/lib/output.js.map +0 -1
- package/lib/print.d.ts +0 -7
- package/lib/print.d.ts.map +0 -1
- package/lib/print.js +0 -10
- package/lib/print.js.map +0 -1
- package/lib/resource.d.ts.map +0 -1
- package/lib/resource.js.map +0 -1
- package/lib/scope.d.ts.map +0 -1
- package/lib/scope.js.map +0 -1
- package/lib/secret.d.ts.map +0 -1
- package/lib/secret.js.map +0 -1
- package/lib/serde.d.ts +0 -3
- package/lib/serde.d.ts.map +0 -1
- package/lib/serde.js.map +0 -1
- package/lib/slug.d.ts +0 -2
- package/lib/slug.d.ts.map +0 -1
- package/lib/slug.js +0 -4
- package/lib/slug.js.map +0 -1
- package/lib/state.d.ts.map +0 -1
- package/lib/state.js.map +0 -1
- package/lib/stripe/index.d.ts.map +0 -1
- package/lib/stripe/index.js.map +0 -1
- package/lib/stripe/price.d.ts.map +0 -1
- package/lib/stripe/price.js.map +0 -1
- package/lib/stripe/product.d.ts.map +0 -1
- package/lib/stripe/product.js.map +0 -1
- package/lib/stripe/webhook.d.ts.map +0 -1
- package/lib/stripe/webhook.js.map +0 -1
- package/lib/utils/content-type.d.ts.map +0 -1
- package/lib/utils/content-type.js.map +0 -1
- package/lib/utils/retry.d.ts.map +0 -1
- package/lib/utils/retry.js.map +0 -1
- package/src/$.ts +0 -69
- package/src/alchemize.ts +0 -195
- package/src/fs.ts +0 -47
- package/src/global.ts +0 -63
- package/src/input.ts +0 -19
- package/src/main.ts +0 -34
- package/src/output.ts +0 -75
- package/src/print.ts +0 -18
- package/src/serde.ts +0 -46
- package/src/slug.ts +0 -3
- /package/src/{utils → util}/content-type.ts +0 -0
- /package/src/{encrypt.ts → util/encrypt.ts} +0 -0
- /package/src/{error.ts → util/ignore.ts} +0 -0
- /package/src/{utils → util}/retry.ts +0 -0
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
3
|
-
import { withExponentialBackoff } from "../
|
|
1
|
+
import type { Context } from "../context";
|
|
2
|
+
import { Resource } from "../resource";
|
|
3
|
+
import { withExponentialBackoff } from "../util/retry";
|
|
4
4
|
import { createCloudflareApi } from "./api";
|
|
5
5
|
|
|
6
|
+
export function isKVNamespace(resource: any): resource is KVNamespace {
|
|
7
|
+
return (
|
|
8
|
+
resource && typeof resource === "object" && resource.type === "kv_namespace"
|
|
9
|
+
);
|
|
10
|
+
}
|
|
11
|
+
|
|
6
12
|
/**
|
|
7
13
|
* Properties for creating or updating a KV Namespace
|
|
8
14
|
*/
|
|
@@ -52,12 +58,14 @@ export interface KVPair {
|
|
|
52
58
|
/**
|
|
53
59
|
* Output returned after KV Namespace creation/update
|
|
54
60
|
*/
|
|
55
|
-
export interface
|
|
61
|
+
export interface KVNamespace
|
|
62
|
+
extends Resource<"cloudflare::KVNamespace">,
|
|
63
|
+
KVNamespaceProps {
|
|
56
64
|
type: "kv_namespace";
|
|
57
65
|
/**
|
|
58
66
|
* The ID of the namespace
|
|
59
67
|
*/
|
|
60
|
-
|
|
68
|
+
namespaceId: string;
|
|
61
69
|
|
|
62
70
|
/**
|
|
63
71
|
* Time at which the namespace was created
|
|
@@ -70,23 +78,19 @@ export interface KVNamespaceOutput extends KVNamespaceProps {
|
|
|
70
78
|
modifiedAt: number;
|
|
71
79
|
}
|
|
72
80
|
|
|
73
|
-
export
|
|
74
|
-
resource: any,
|
|
75
|
-
): resource is Resolved<KVNamespace> {
|
|
76
|
-
return (
|
|
77
|
-
resource && typeof resource === "object" && resource.type === "kv_namespace"
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export class KVNamespace extends Resource(
|
|
81
|
+
export const KVNamespace = Resource(
|
|
82
82
|
"cloudflare::KVNamespace",
|
|
83
|
-
async (
|
|
83
|
+
async function (
|
|
84
|
+
this: Context<KVNamespace>,
|
|
85
|
+
id: string,
|
|
86
|
+
props: KVNamespaceProps,
|
|
87
|
+
) {
|
|
84
88
|
// Create Cloudflare API client with automatic account discovery
|
|
85
89
|
const api = await createCloudflareApi();
|
|
86
90
|
|
|
87
|
-
if (
|
|
91
|
+
if (this.phase === "delete") {
|
|
88
92
|
// For delete operations, we need to check if the namespace ID exists in the output
|
|
89
|
-
const namespaceId =
|
|
93
|
+
const namespaceId = this.output?.namespaceId;
|
|
90
94
|
if (namespaceId) {
|
|
91
95
|
// Delete KV namespace
|
|
92
96
|
const deleteResponse = await api.delete(
|
|
@@ -104,19 +108,22 @@ export class KVNamespace extends Resource(
|
|
|
104
108
|
}
|
|
105
109
|
|
|
106
110
|
// Return minimal output for deleted state
|
|
107
|
-
return;
|
|
111
|
+
return this.destroy();
|
|
108
112
|
} else {
|
|
109
113
|
// For create or update operations
|
|
110
|
-
// If
|
|
111
|
-
let namespaceId =
|
|
114
|
+
// If this.phase is "update", we expect this.output to exist
|
|
115
|
+
let namespaceId =
|
|
116
|
+
this.phase === "update" ? this.output?.namespaceId || "" : "";
|
|
112
117
|
let createdAt =
|
|
113
|
-
|
|
114
|
-
?
|
|
118
|
+
this.phase === "update"
|
|
119
|
+
? this.output?.createdAt || Date.now()
|
|
115
120
|
: Date.now();
|
|
116
121
|
|
|
117
|
-
if (
|
|
122
|
+
if (this.phase === "update" && namespaceId) {
|
|
118
123
|
// Can't update a KV namespace title directly, just work with existing ID
|
|
119
124
|
} else {
|
|
125
|
+
// TODO: if it already exists, then check the tags to see if we own it and continue
|
|
126
|
+
|
|
120
127
|
// Create new KV namespace
|
|
121
128
|
const createResponse = await api.post(
|
|
122
129
|
`/accounts/${api.accountId}/storage/kv/namespaces`,
|
|
@@ -207,19 +214,14 @@ export class KVNamespace extends Resource(
|
|
|
207
214
|
}
|
|
208
215
|
}
|
|
209
216
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
// Construct the output
|
|
213
|
-
const output: KVNamespaceOutput = {
|
|
217
|
+
return this({
|
|
214
218
|
type: "kv_namespace",
|
|
215
|
-
|
|
219
|
+
namespaceId: namespaceId,
|
|
216
220
|
title: props.title,
|
|
217
221
|
values: props.values,
|
|
218
222
|
createdAt: createdAt,
|
|
219
|
-
modifiedAt: now,
|
|
220
|
-
};
|
|
221
|
-
|
|
222
|
-
return output;
|
|
223
|
+
modifiedAt: Date.now(),
|
|
224
|
+
});
|
|
223
225
|
}
|
|
224
226
|
},
|
|
225
|
-
)
|
|
227
|
+
);
|
|
@@ -34,14 +34,12 @@ export default {
|
|
|
34
34
|
isInit = true;
|
|
35
35
|
for (const [key, value] of Object.entries(env)) {
|
|
36
36
|
if (key.startsWith("ROUTE_")) {
|
|
37
|
-
console.log(key, value);
|
|
38
37
|
const service = value as Service;
|
|
39
38
|
const patternKey = `__${key}`;
|
|
40
39
|
if (!(patternKey in env)) {
|
|
41
40
|
throw new Error(`Missing pattern key: ${patternKey}`);
|
|
42
41
|
}
|
|
43
42
|
const pattern = (env as any)[`__${key}`];
|
|
44
|
-
console.log("pattern", pattern);
|
|
45
43
|
// TODO(sam): we should support narrowing down METHOD
|
|
46
44
|
app.all(pattern, (ctx) => service.fetch(ctx.req.raw));
|
|
47
45
|
}
|
|
@@ -53,7 +51,6 @@ export default {
|
|
|
53
51
|
|
|
54
52
|
// fall back to assuming the request is a static file
|
|
55
53
|
app.notFound(async (ctx) => {
|
|
56
|
-
console.log("not found");
|
|
57
54
|
const request = ctx.req;
|
|
58
55
|
const env = ctx.env;
|
|
59
56
|
const url = new URL(request.url);
|
|
@@ -2,10 +2,9 @@ import { exec } from "child_process";
|
|
|
2
2
|
import { promises as fs } from "fs";
|
|
3
3
|
import path from "path";
|
|
4
4
|
import { promisify } from "util";
|
|
5
|
-
import {
|
|
6
|
-
import type { BundleProps } from "../esbuild";
|
|
7
|
-
import
|
|
8
|
-
import { type Context, Resource } from "../resource";
|
|
5
|
+
import type { Context } from "../context";
|
|
6
|
+
import type { BundleProps } from "../esbuild/bundle";
|
|
7
|
+
import { Resource } from "../resource";
|
|
9
8
|
import { createCloudflareApi } from "./api";
|
|
10
9
|
import type { Bindings } from "./bindings";
|
|
11
10
|
import { generateAssetManifest } from "./generate-asset-manifest";
|
|
@@ -131,12 +130,7 @@ export interface StaticSiteProps {
|
|
|
131
130
|
/**
|
|
132
131
|
* Output returned after StaticSite creation/update
|
|
133
132
|
*/
|
|
134
|
-
export interface
|
|
135
|
-
/**
|
|
136
|
-
* The ID of the site
|
|
137
|
-
*/
|
|
138
|
-
id: string;
|
|
139
|
-
|
|
133
|
+
export interface StaticSite extends Resource<"cloudflare::StaticSite"> {
|
|
140
134
|
/**
|
|
141
135
|
* The ID of the worker
|
|
142
136
|
*/
|
|
@@ -208,16 +202,20 @@ export interface StaticSiteOutput {
|
|
|
208
202
|
routes?: Record<string, string>;
|
|
209
203
|
}
|
|
210
204
|
|
|
211
|
-
export
|
|
205
|
+
export const StaticSite = Resource(
|
|
212
206
|
"cloudflare::StaticSite",
|
|
213
207
|
{
|
|
214
208
|
alwaysUpdate: true,
|
|
215
209
|
},
|
|
216
|
-
async (
|
|
217
|
-
|
|
210
|
+
async function (
|
|
211
|
+
this: Context<StaticSite>,
|
|
212
|
+
id: string,
|
|
213
|
+
props: StaticSiteProps,
|
|
214
|
+
) {
|
|
215
|
+
if (this.phase === "delete") {
|
|
218
216
|
// For delete operations, we'll rely on the Worker delete to clean up
|
|
219
217
|
// Return empty output for deleted state
|
|
220
|
-
return;
|
|
218
|
+
return this.destroy();
|
|
221
219
|
}
|
|
222
220
|
|
|
223
221
|
// Validate that a name is provided
|
|
@@ -246,7 +244,7 @@ export class StaticSite extends Resource(
|
|
|
246
244
|
// Run build command if provided
|
|
247
245
|
if (props.build?.command) {
|
|
248
246
|
try {
|
|
249
|
-
if (!
|
|
247
|
+
if (!this.quiet) {
|
|
250
248
|
console.log(props.build.command);
|
|
251
249
|
}
|
|
252
250
|
const execAsync = promisify(exec);
|
|
@@ -254,7 +252,7 @@ export class StaticSite extends Resource(
|
|
|
254
252
|
cwd: process.cwd(),
|
|
255
253
|
});
|
|
256
254
|
|
|
257
|
-
if (stdout && !
|
|
255
|
+
if (stdout && !this.quiet) console.log(stdout);
|
|
258
256
|
} catch (error: any) {
|
|
259
257
|
// Log detailed error information
|
|
260
258
|
console.error(`Build command failed with exit code ${error.code}`);
|
|
@@ -276,22 +274,18 @@ export class StaticSite extends Resource(
|
|
|
276
274
|
const api = await createCloudflareApi();
|
|
277
275
|
|
|
278
276
|
// Step 1: Create or get the KV namespace for assets
|
|
279
|
-
const kv =
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
const [{ id: kvNamespaceId }, assetManifest] = await Promise.all([
|
|
284
|
-
apply(kv, {
|
|
285
|
-
quiet: ctx.quiet,
|
|
277
|
+
const [kv, assetManifest] = await Promise.all([
|
|
278
|
+
KVNamespace("assets", {
|
|
279
|
+
title: `${siteName}-assets`,
|
|
286
280
|
}),
|
|
287
281
|
generateAssetManifest(props.dir),
|
|
288
282
|
]);
|
|
289
283
|
|
|
290
284
|
// Step 3: Upload assets to KV
|
|
291
|
-
await uploadAssetManifest(api,
|
|
285
|
+
await uploadAssetManifest(api, kv.namespaceId, assetManifest);
|
|
292
286
|
|
|
293
287
|
// Prepare the bindings for the worker
|
|
294
|
-
const bindings:
|
|
288
|
+
const bindings: Bindings = {
|
|
295
289
|
ASSETS: kv,
|
|
296
290
|
INDEX_PAGE: indexPage,
|
|
297
291
|
// Add error page binding if specified
|
|
@@ -335,39 +329,31 @@ export class StaticSite extends Resource(
|
|
|
335
329
|
// TypeScript file doesn't exist, use JavaScript (default)
|
|
336
330
|
}
|
|
337
331
|
|
|
338
|
-
const worker =
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
]),
|
|
358
|
-
),
|
|
359
|
-
},
|
|
332
|
+
const worker = await Worker("worker", {
|
|
333
|
+
name: siteName,
|
|
334
|
+
url: true,
|
|
335
|
+
format: props.format || "esm",
|
|
336
|
+
// If a custom worker script is provided, use it, otherwise use the entrypoint from router
|
|
337
|
+
...(props.workerScript
|
|
338
|
+
? { script: props.workerScript }
|
|
339
|
+
: {
|
|
340
|
+
entrypoint: path.resolve(__dirname, entrypointFile),
|
|
341
|
+
bundle: bundleOptions as any,
|
|
342
|
+
}),
|
|
343
|
+
bindings,
|
|
344
|
+
env: {
|
|
345
|
+
...Object.fromEntries(
|
|
346
|
+
Object.entries(routes).map(([key, value]) => [
|
|
347
|
+
`__ROUTE_${value}`,
|
|
348
|
+
key,
|
|
349
|
+
]),
|
|
350
|
+
),
|
|
360
351
|
},
|
|
361
|
-
|
|
362
|
-
kv.id,
|
|
363
|
-
);
|
|
352
|
+
});
|
|
364
353
|
|
|
365
|
-
// Get current timestamp
|
|
366
354
|
const now = Date.now();
|
|
367
355
|
|
|
368
|
-
|
|
369
|
-
const output: Input<StaticSiteOutput> = {
|
|
370
|
-
id: siteName,
|
|
356
|
+
return this({
|
|
371
357
|
workerId: worker.id,
|
|
372
358
|
name: siteName,
|
|
373
359
|
directory: props.dir,
|
|
@@ -375,14 +361,12 @@ export class StaticSite extends Resource(
|
|
|
375
361
|
errorPage: props.errorPage,
|
|
376
362
|
indexPage,
|
|
377
363
|
assets: assetManifest.map((item) => item.key),
|
|
378
|
-
createdAt:
|
|
364
|
+
createdAt: this.output?.createdAt || now,
|
|
379
365
|
updatedAt: now,
|
|
380
366
|
domain: props.domain,
|
|
381
367
|
production: props.production !== false,
|
|
382
|
-
url: worker.url
|
|
368
|
+
url: worker.url,
|
|
383
369
|
routes,
|
|
384
|
-
};
|
|
385
|
-
|
|
386
|
-
return output;
|
|
370
|
+
});
|
|
387
371
|
},
|
|
388
|
-
)
|
|
372
|
+
);
|
package/src/cloudflare/worker.ts
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import * as fs from "fs/promises";
|
|
2
|
-
import {
|
|
3
|
-
import { Bundle, type BundleProps } from "../esbuild";
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { withExponentialBackoff } from "../utils/retry";
|
|
2
|
+
import type { Context } from "../context";
|
|
3
|
+
import { Bundle, type BundleProps } from "../esbuild/bundle";
|
|
4
|
+
import { Resource } from "../resource";
|
|
5
|
+
import { isSecret } from "../secret";
|
|
6
|
+
import { withExponentialBackoff } from "../util/retry";
|
|
7
|
+
import { slugify } from "../util/slugify";
|
|
9
8
|
import { type CloudflareApi, createCloudflareApi } from "./api";
|
|
10
|
-
import
|
|
9
|
+
import {
|
|
10
|
+
type Bindings,
|
|
11
|
+
type WorkerBindingSpec,
|
|
12
|
+
isDurableObjectNamespace,
|
|
13
|
+
} from "./bindings";
|
|
11
14
|
import type { Bound } from "./bound";
|
|
12
|
-
import { isBucket } from "./bucket";
|
|
13
15
|
import type { DurableObjectNamespace } from "./durable-object-namespace";
|
|
14
|
-
import { isDurableObjectNamespace } from "./durable-object-namespace";
|
|
15
16
|
import { isKVNamespace } from "./kv-namespace";
|
|
16
17
|
import type { WorkerScriptMetadata } from "./worker-metadata";
|
|
17
18
|
import type { SingleStepMigration } from "./worker-migration";
|
|
@@ -100,8 +101,9 @@ export interface WorkerProps<B extends Bindings = Bindings> {
|
|
|
100
101
|
/**
|
|
101
102
|
* Output returned after Worker creation/update
|
|
102
103
|
*/
|
|
103
|
-
export interface
|
|
104
|
-
extends
|
|
104
|
+
export interface Worker<B extends Bindings = Bindings>
|
|
105
|
+
extends Resource<"cloudflare::Worker">,
|
|
106
|
+
Omit<WorkerProps<B>, "url"> {
|
|
105
107
|
type: "service";
|
|
106
108
|
|
|
107
109
|
/**
|
|
@@ -128,94 +130,95 @@ export interface WorkerOutput<B extends Bindings = Bindings>
|
|
|
128
130
|
/**
|
|
129
131
|
* The bindings that were created
|
|
130
132
|
*/
|
|
131
|
-
bindings: B;
|
|
132
|
-
}
|
|
133
|
+
bindings: B | undefined;
|
|
133
134
|
|
|
134
|
-
|
|
135
|
-
|
|
135
|
+
// phantom property (for typeof myWorker.Env)
|
|
136
|
+
Env: {
|
|
137
|
+
[bindingName in keyof B]: Bound<B[bindingName]>;
|
|
138
|
+
};
|
|
136
139
|
}
|
|
137
140
|
|
|
138
|
-
export
|
|
141
|
+
export const Worker = Resource(
|
|
139
142
|
"cloudflare::Worker",
|
|
140
143
|
{
|
|
141
144
|
alwaysUpdate: true,
|
|
142
145
|
},
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
const workerName = props.name;
|
|
159
|
-
|
|
160
|
-
// Validate input - we need either script, entryPoint, or bundle
|
|
161
|
-
if (!props.script && !props.entrypoint) {
|
|
162
|
-
throw new Error("One of script or entryPoint must be provided");
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
if (ctx.event === "delete") {
|
|
166
|
-
return deleteWorker(ctx, api, workerName);
|
|
167
|
-
} else if (ctx.event === "create") {
|
|
168
|
-
await assertWorkerDoesNotExist(ctx, api, workerName);
|
|
169
|
-
}
|
|
146
|
+
async function <const B extends Bindings>(
|
|
147
|
+
this: Context<Worker<NoInfer<B>>>,
|
|
148
|
+
id: string,
|
|
149
|
+
props: WorkerProps<B>,
|
|
150
|
+
): Promise<Worker<B>> {
|
|
151
|
+
// Create Cloudflare API client with automatic account discovery
|
|
152
|
+
const api = await createCloudflareApi();
|
|
153
|
+
|
|
154
|
+
// Use the provided name
|
|
155
|
+
const workerName = props.name;
|
|
156
|
+
|
|
157
|
+
// Validate input - we need either script, entryPoint, or bundle
|
|
158
|
+
if (!props.script && !props.entrypoint) {
|
|
159
|
+
throw new Error("One of script or entryPoint must be provided");
|
|
160
|
+
}
|
|
170
161
|
|
|
171
|
-
|
|
162
|
+
if (this.phase === "delete") {
|
|
163
|
+
await deleteWorker(this, api, workerName);
|
|
164
|
+
return this.destroy();
|
|
165
|
+
} else if (this.phase === "create") {
|
|
166
|
+
await assertWorkerDoesNotExist(this, api, workerName);
|
|
167
|
+
}
|
|
172
168
|
|
|
173
|
-
|
|
169
|
+
const oldBindings = await this.get<Bindings>("bindings");
|
|
174
170
|
|
|
175
|
-
|
|
176
|
-
|
|
171
|
+
const scriptMetadata = await prepareWorkerMetadata(
|
|
172
|
+
this,
|
|
173
|
+
oldBindings,
|
|
174
|
+
props,
|
|
175
|
+
);
|
|
177
176
|
|
|
178
|
-
|
|
179
|
-
|
|
177
|
+
// Get the script content - either from props.script, or by bundling
|
|
178
|
+
const scriptContent = props.script ?? (await bundleWorkerScript(props));
|
|
180
179
|
|
|
181
|
-
|
|
182
|
-
|
|
180
|
+
// Upload the worker script
|
|
181
|
+
await putWorker(api, workerName, scriptContent, scriptMetadata);
|
|
183
182
|
|
|
184
|
-
|
|
185
|
-
|
|
183
|
+
// TODO: it is less than ideal that this can fail, resulting in state problem
|
|
184
|
+
await this.set("bindings", props.bindings);
|
|
186
185
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
ctx,
|
|
190
|
-
api,
|
|
191
|
-
workerName,
|
|
192
|
-
props.url ?? false,
|
|
193
|
-
);
|
|
186
|
+
// Handle routes if requested
|
|
187
|
+
await setupRoutes(api, workerName, props.routes || []);
|
|
194
188
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
name: workerName,
|
|
203
|
-
script: scriptContent,
|
|
204
|
-
format: props.format || "esm", // Include format in the output
|
|
205
|
-
routes: props.routes || [],
|
|
206
|
-
bindings: props.bindings ?? {},
|
|
207
|
-
env: props.env,
|
|
208
|
-
observability: scriptMetadata.observability,
|
|
209
|
-
createdAt: now,
|
|
210
|
-
updatedAt: now,
|
|
211
|
-
url: workerUrl,
|
|
212
|
-
};
|
|
189
|
+
// Handle worker URL if requested
|
|
190
|
+
const workerUrl = await configureURL(
|
|
191
|
+
this,
|
|
192
|
+
api,
|
|
193
|
+
workerName,
|
|
194
|
+
props.url ?? false,
|
|
195
|
+
);
|
|
213
196
|
|
|
214
|
-
|
|
215
|
-
|
|
197
|
+
// Get current timestamp
|
|
198
|
+
const now = Date.now();
|
|
199
|
+
|
|
200
|
+
// Construct the output
|
|
201
|
+
return this({
|
|
202
|
+
type: "service",
|
|
203
|
+
id,
|
|
204
|
+
name: workerName,
|
|
205
|
+
script: scriptContent,
|
|
206
|
+
format: props.format || "esm", // Include format in the output
|
|
207
|
+
routes: props.routes || [],
|
|
208
|
+
bindings: props.bindings ?? ({} as B),
|
|
209
|
+
env: props.env,
|
|
210
|
+
observability: scriptMetadata.observability,
|
|
211
|
+
createdAt: now,
|
|
212
|
+
updatedAt: now,
|
|
213
|
+
url: workerUrl,
|
|
214
|
+
// phantom property
|
|
215
|
+
Env: undefined!,
|
|
216
|
+
});
|
|
217
|
+
},
|
|
218
|
+
);
|
|
216
219
|
|
|
217
|
-
async function deleteWorker(
|
|
218
|
-
ctx: Context<
|
|
220
|
+
async function deleteWorker<B extends Bindings>(
|
|
221
|
+
ctx: Context<Worker<B>>,
|
|
219
222
|
api: CloudflareApi,
|
|
220
223
|
workerName: string,
|
|
221
224
|
) {
|
|
@@ -284,7 +287,6 @@ async function deleteWorker(
|
|
|
284
287
|
}
|
|
285
288
|
|
|
286
289
|
async function putWorker(
|
|
287
|
-
ctx: Context<WorkerOutput>,
|
|
288
290
|
api: CloudflareApi,
|
|
289
291
|
workerName: string,
|
|
290
292
|
scriptContent: string,
|
|
@@ -309,8 +311,6 @@ async function putWorker(
|
|
|
309
311
|
scriptName,
|
|
310
312
|
);
|
|
311
313
|
|
|
312
|
-
// console.log("Script Metadata:", JSON.stringify(scriptMetadata, null, 2));
|
|
313
|
-
|
|
314
314
|
// Add metadata as JSON
|
|
315
315
|
formData.append(
|
|
316
316
|
"metadata",
|
|
@@ -375,8 +375,8 @@ interface WorkerMetadata {
|
|
|
375
375
|
tags?: string[];
|
|
376
376
|
}
|
|
377
377
|
|
|
378
|
-
async function prepareWorkerMetadata(
|
|
379
|
-
ctx: Context<
|
|
378
|
+
async function prepareWorkerMetadata<B extends Bindings>(
|
|
379
|
+
ctx: Context<Worker<B>>,
|
|
380
380
|
oldBindings: Bindings | undefined,
|
|
381
381
|
props: WorkerProps,
|
|
382
382
|
): Promise<WorkerMetadata> {
|
|
@@ -386,7 +386,8 @@ async function prepareWorkerMetadata(
|
|
|
386
386
|
observability: {
|
|
387
387
|
enabled: props.observability?.enabled !== false,
|
|
388
388
|
},
|
|
389
|
-
|
|
389
|
+
// TODO(sam): base64 encode instead? 0 collision risk vs readability.
|
|
390
|
+
tags: [`alchemy:id:${slugify(ctx.fqn)}`],
|
|
390
391
|
migrations: {
|
|
391
392
|
new_classes: props.migrations?.new_classes ?? [],
|
|
392
393
|
deleted_classes: props.migrations?.deleted_classes ?? [],
|
|
@@ -396,7 +397,7 @@ async function prepareWorkerMetadata(
|
|
|
396
397
|
},
|
|
397
398
|
};
|
|
398
399
|
|
|
399
|
-
const bindings = (props.bindings ?? {}) as
|
|
400
|
+
const bindings = (props.bindings ?? {}) as Bindings;
|
|
400
401
|
|
|
401
402
|
// Convert bindings to the format expected by the API
|
|
402
403
|
for (const [bindingName, binding] of Object.entries(bindings)) {
|
|
@@ -406,7 +407,7 @@ async function prepareWorkerMetadata(
|
|
|
406
407
|
meta.bindings.push({
|
|
407
408
|
type: "kv_namespace",
|
|
408
409
|
name: bindingName,
|
|
409
|
-
namespace_id: binding.
|
|
410
|
+
namespace_id: binding.namespaceId,
|
|
410
411
|
});
|
|
411
412
|
} else if (typeof binding === "string") {
|
|
412
413
|
meta.bindings.push({
|
|
@@ -420,7 +421,7 @@ async function prepareWorkerMetadata(
|
|
|
420
421
|
name: bindingName,
|
|
421
422
|
service: binding.id,
|
|
422
423
|
});
|
|
423
|
-
} else if (
|
|
424
|
+
} else if (binding.type === "durable_object_namespace") {
|
|
424
425
|
const stableId = binding.id;
|
|
425
426
|
const className = binding.className;
|
|
426
427
|
|
|
@@ -451,13 +452,13 @@ async function prepareWorkerMetadata(
|
|
|
451
452
|
to: className,
|
|
452
453
|
});
|
|
453
454
|
}
|
|
454
|
-
} else if (
|
|
455
|
+
} else if (binding.type === "r2_bucket") {
|
|
455
456
|
meta.bindings.push({
|
|
456
457
|
type: "r2_bucket",
|
|
457
458
|
name: bindingName,
|
|
458
|
-
bucket_name: binding.name
|
|
459
|
+
bucket_name: binding.name,
|
|
459
460
|
});
|
|
460
|
-
} else if (binding
|
|
461
|
+
} else if (isSecret(binding)) {
|
|
461
462
|
meta.bindings.push({
|
|
462
463
|
type: "secret_text",
|
|
463
464
|
name: bindingName,
|
|
@@ -494,8 +495,8 @@ async function prepareWorkerMetadata(
|
|
|
494
495
|
return meta;
|
|
495
496
|
}
|
|
496
497
|
|
|
497
|
-
async function assertWorkerDoesNotExist(
|
|
498
|
-
ctx: Context<
|
|
498
|
+
async function assertWorkerDoesNotExist<B extends Bindings>(
|
|
499
|
+
ctx: Context<Worker<B>>,
|
|
499
500
|
api: CloudflareApi,
|
|
500
501
|
workerName: string,
|
|
501
502
|
) {
|
|
@@ -516,7 +517,7 @@ async function assertWorkerDoesNotExist(
|
|
|
516
517
|
|
|
517
518
|
if (
|
|
518
519
|
metadata.default_environment?.script.tags.includes(
|
|
519
|
-
`alchemy:id:${ctx.
|
|
520
|
+
`alchemy:id:${slugify(ctx.fqn)}`,
|
|
520
521
|
)
|
|
521
522
|
) {
|
|
522
523
|
return true;
|
|
@@ -532,10 +533,7 @@ async function assertWorkerDoesNotExist(
|
|
|
532
533
|
}
|
|
533
534
|
}
|
|
534
535
|
|
|
535
|
-
async function bundleWorkerScript(
|
|
536
|
-
ctx: Context<WorkerOutput>,
|
|
537
|
-
props: WorkerProps,
|
|
538
|
-
) {
|
|
536
|
+
async function bundleWorkerScript<B extends Bindings>(props: WorkerProps) {
|
|
539
537
|
// Get the script content - either from props.script, or by bundling
|
|
540
538
|
|
|
541
539
|
// Create and use a Bundle resource with worker-optimized configuration
|
|
@@ -556,18 +554,14 @@ async function bundleWorkerScript(
|
|
|
556
554
|
};
|
|
557
555
|
|
|
558
556
|
// Create the bundle
|
|
559
|
-
const bundle =
|
|
557
|
+
const bundle = await Bundle("bundle", {
|
|
560
558
|
entryPoint: props.entrypoint!,
|
|
561
559
|
...bundleOptions,
|
|
562
560
|
external: [...(bundleOptions.external ?? []), "cloudflare:workers"],
|
|
563
561
|
});
|
|
564
562
|
|
|
565
|
-
// Get the bundled content
|
|
566
|
-
const bundleOutput = await apply(bundle, {
|
|
567
|
-
quiet: ctx.quiet,
|
|
568
|
-
});
|
|
569
563
|
try {
|
|
570
|
-
return await fs.readFile(
|
|
564
|
+
return await fs.readFile(bundle.path, "utf-8");
|
|
571
565
|
} catch (error) {
|
|
572
566
|
console.error("Error reading bundle:", error);
|
|
573
567
|
throw new Error("Error reading bundle");
|
|
@@ -635,8 +629,8 @@ async function setupRoutes(
|
|
|
635
629
|
}
|
|
636
630
|
}
|
|
637
631
|
|
|
638
|
-
async function configureURL(
|
|
639
|
-
ctx: Context<
|
|
632
|
+
async function configureURL<B extends Bindings>(
|
|
633
|
+
ctx: Context<Worker<B>>,
|
|
640
634
|
api: CloudflareApi,
|
|
641
635
|
workerName: string,
|
|
642
636
|
url: boolean,
|
|
@@ -675,7 +669,7 @@ async function configureURL(
|
|
|
675
669
|
// Add a delay when the subdomain is first created.
|
|
676
670
|
// This is to prevent an issue where a negative cache-hit
|
|
677
671
|
// causes the subdomain to be unavailable for 30 seconds.
|
|
678
|
-
if (ctx.
|
|
672
|
+
if (ctx.phase === "create" || !ctx.output?.url) {
|
|
679
673
|
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
680
674
|
}
|
|
681
675
|
}
|