alchemy 0.1.17 → 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 -78
- 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 +4 -3
- package/lib/cloudflare/bindings.js +3 -2
- package/lib/cloudflare/bound.d.ts +7 -0
- package/lib/cloudflare/bound.js +1 -0
- 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 +13 -13
- package/lib/cloudflare/worker.js +43 -43
- 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 +6 -7
- package/lib/github/secret.js +30 -36
- package/lib/index.d.ts +7 -10
- package/lib/index.js +6 -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 +7 -0
- package/lib/secret.js +17 -0
- package/lib/state.d.ts +14 -10
- package/lib/state.js +15 -13
- 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/util/encrypt.d.ts +16 -0
- package/lib/util/encrypt.js +44 -0
- 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/util/serde.js +46 -0
- package/lib/util/slugify.d.ts +1 -0
- package/lib/util/slugify.js +3 -0
- package/package.json +5 -7
- package/src/alchemy.ts +120 -0
- package/src/apply.ts +109 -111
- 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 +12 -2
- package/src/cloudflare/bound.ts +18 -0
- package/src/cloudflare/bucket.ts +40 -48
- 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 +43 -59
- package/src/cloudflare/worker.ts +76 -64
- 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 +53 -49
- package/src/index.ts +8 -15
- package/src/resource.ts +101 -462
- package/src/scope.ts +101 -36
- package/src/secret.ts +18 -0
- package/src/state.ts +30 -20
- 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/encrypt.ts +79 -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 -43
- package/lib/alchemize.d.ts.map +0 -1
- package/lib/alchemize.js +0 -112
- 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/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/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 -6
- 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 -24
- 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/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 -186
- package/src/fs.ts +0 -47
- package/src/global.ts +0 -63
- package/src/input.ts +0 -16
- package/src/main.ts +0 -34
- package/src/output.ts +0 -71
- package/src/print.ts +0 -18
- package/src/slug.ts +0 -3
- /package/src/{utils → util}/content-type.ts +0 -0
- /package/src/{error.ts → util/ignore.ts} +0 -0
- /package/src/{utils → util}/retry.ts +0 -0
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import type { Resolved } from "../output";
|
|
2
|
-
|
|
3
1
|
export interface DurableObjectNamespaceInput {
|
|
4
2
|
className: string;
|
|
5
3
|
scriptName?: string | undefined;
|
|
@@ -8,14 +6,6 @@ export interface DurableObjectNamespaceInput {
|
|
|
8
6
|
namespaceId?: string | undefined;
|
|
9
7
|
}
|
|
10
8
|
|
|
11
|
-
export function isDurableObjectNamespace(
|
|
12
|
-
binding: any,
|
|
13
|
-
): binding is Resolved<DurableObjectNamespace> {
|
|
14
|
-
return (
|
|
15
|
-
typeof binding === "object" && binding.type === "durable_object_namespace"
|
|
16
|
-
);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
9
|
export class DurableObjectNamespace implements DurableObjectNamespaceInput {
|
|
20
10
|
public readonly type = "durable_object_namespace" as const;
|
|
21
11
|
// alias for bindingName to be consistent with other bindings
|
|
@@ -2,7 +2,7 @@ import crypto from "crypto";
|
|
|
2
2
|
import { promises as fs } from "fs";
|
|
3
3
|
import { glob } from "glob";
|
|
4
4
|
import path from "path";
|
|
5
|
-
import { getContentType } from "../
|
|
5
|
+
import { getContentType } from "../util/content-type";
|
|
6
6
|
import type {
|
|
7
7
|
AssetManifest,
|
|
8
8
|
AssetManifestEntry,
|
|
@@ -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
368
|
url: worker.url,
|
|
383
369
|
routes,
|
|
384
|
-
};
|
|
385
|
-
|
|
386
|
-
return output;
|
|
370
|
+
});
|
|
387
371
|
},
|
|
388
|
-
)
|
|
372
|
+
);
|
package/src/cloudflare/worker.ts
CHANGED
|
@@ -1,21 +1,25 @@
|
|
|
1
1
|
import * as fs from "fs/promises";
|
|
2
|
-
import {
|
|
3
|
-
import { Bundle, type BundleProps } from "../esbuild";
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import { withExponentialBackoff } from "../
|
|
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";
|
|
7
8
|
import { type CloudflareApi, createCloudflareApi } from "./api";
|
|
8
|
-
import
|
|
9
|
-
|
|
9
|
+
import {
|
|
10
|
+
type Bindings,
|
|
11
|
+
type WorkerBindingSpec,
|
|
12
|
+
isDurableObjectNamespace,
|
|
13
|
+
} from "./bindings";
|
|
14
|
+
import type { Bound } from "./bound";
|
|
10
15
|
import type { DurableObjectNamespace } from "./durable-object-namespace";
|
|
11
|
-
import { isDurableObjectNamespace } from "./durable-object-namespace";
|
|
12
16
|
import { isKVNamespace } from "./kv-namespace";
|
|
13
17
|
import type { WorkerScriptMetadata } from "./worker-metadata";
|
|
14
18
|
import type { SingleStepMigration } from "./worker-migration";
|
|
15
19
|
/**
|
|
16
20
|
* Properties for creating or updating a Worker
|
|
17
21
|
*/
|
|
18
|
-
export interface WorkerProps {
|
|
22
|
+
export interface WorkerProps<B extends Bindings = Bindings> {
|
|
19
23
|
/**
|
|
20
24
|
* The worker script content (JavaScript or WASM)
|
|
21
25
|
* One of script, entryPoint, or bundle must be provided
|
|
@@ -58,7 +62,7 @@ export interface WorkerProps {
|
|
|
58
62
|
/**
|
|
59
63
|
* Bindings to attach to the worker
|
|
60
64
|
*/
|
|
61
|
-
bindings?:
|
|
65
|
+
bindings?: B;
|
|
62
66
|
|
|
63
67
|
/**
|
|
64
68
|
* Environment variables to attach to the worker
|
|
@@ -97,7 +101,9 @@ export interface WorkerProps {
|
|
|
97
101
|
/**
|
|
98
102
|
* Output returned after Worker creation/update
|
|
99
103
|
*/
|
|
100
|
-
export interface
|
|
104
|
+
export interface Worker<B extends Bindings = Bindings>
|
|
105
|
+
extends Resource<"cloudflare::Worker">,
|
|
106
|
+
Omit<WorkerProps<B>, "url"> {
|
|
101
107
|
type: "service";
|
|
102
108
|
|
|
103
109
|
/**
|
|
@@ -124,19 +130,24 @@ export interface WorkerOutput extends Omit<WorkerProps, "url"> {
|
|
|
124
130
|
/**
|
|
125
131
|
* The bindings that were created
|
|
126
132
|
*/
|
|
127
|
-
bindings:
|
|
128
|
-
}
|
|
133
|
+
bindings: B | undefined;
|
|
129
134
|
|
|
130
|
-
|
|
131
|
-
|
|
135
|
+
// phantom property (for typeof myWorker.Env)
|
|
136
|
+
Env: {
|
|
137
|
+
[bindingName in keyof B]: Bound<B[bindingName]>;
|
|
138
|
+
};
|
|
132
139
|
}
|
|
133
140
|
|
|
134
|
-
export
|
|
141
|
+
export const Worker = Resource(
|
|
135
142
|
"cloudflare::Worker",
|
|
136
143
|
{
|
|
137
144
|
alwaysUpdate: true,
|
|
138
145
|
},
|
|
139
|
-
async
|
|
146
|
+
async function <const B extends Bindings>(
|
|
147
|
+
this: Context<Worker<NoInfer<B>>>,
|
|
148
|
+
id: string,
|
|
149
|
+
props: WorkerProps<B>,
|
|
150
|
+
): Promise<Worker<B>> {
|
|
140
151
|
// Create Cloudflare API client with automatic account discovery
|
|
141
152
|
const api = await createCloudflareApi();
|
|
142
153
|
|
|
@@ -148,32 +159,36 @@ export class Worker extends Resource(
|
|
|
148
159
|
throw new Error("One of script or entryPoint must be provided");
|
|
149
160
|
}
|
|
150
161
|
|
|
151
|
-
if (
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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);
|
|
155
167
|
}
|
|
156
168
|
|
|
157
|
-
const oldBindings = await
|
|
169
|
+
const oldBindings = await this.get<Bindings>("bindings");
|
|
158
170
|
|
|
159
|
-
const scriptMetadata = await prepareWorkerMetadata(
|
|
171
|
+
const scriptMetadata = await prepareWorkerMetadata(
|
|
172
|
+
this,
|
|
173
|
+
oldBindings,
|
|
174
|
+
props,
|
|
175
|
+
);
|
|
160
176
|
|
|
161
177
|
// Get the script content - either from props.script, or by bundling
|
|
162
|
-
const scriptContent =
|
|
163
|
-
props.script ?? (await bundleWorkerScript(ctx, props));
|
|
178
|
+
const scriptContent = props.script ?? (await bundleWorkerScript(props));
|
|
164
179
|
|
|
165
180
|
// Upload the worker script
|
|
166
|
-
await putWorker(
|
|
181
|
+
await putWorker(api, workerName, scriptContent, scriptMetadata);
|
|
167
182
|
|
|
168
183
|
// TODO: it is less than ideal that this can fail, resulting in state problem
|
|
169
|
-
await
|
|
184
|
+
await this.set("bindings", props.bindings);
|
|
170
185
|
|
|
171
186
|
// Handle routes if requested
|
|
172
187
|
await setupRoutes(api, workerName, props.routes || []);
|
|
173
188
|
|
|
174
189
|
// Handle worker URL if requested
|
|
175
190
|
const workerUrl = await configureURL(
|
|
176
|
-
|
|
191
|
+
this,
|
|
177
192
|
api,
|
|
178
193
|
workerName,
|
|
179
194
|
props.url ?? false,
|
|
@@ -183,27 +198,27 @@ export class Worker extends Resource(
|
|
|
183
198
|
const now = Date.now();
|
|
184
199
|
|
|
185
200
|
// Construct the output
|
|
186
|
-
|
|
201
|
+
return this({
|
|
187
202
|
type: "service",
|
|
188
|
-
id
|
|
203
|
+
id,
|
|
189
204
|
name: workerName,
|
|
190
205
|
script: scriptContent,
|
|
191
206
|
format: props.format || "esm", // Include format in the output
|
|
192
207
|
routes: props.routes || [],
|
|
193
|
-
bindings: props.bindings ?? {},
|
|
208
|
+
bindings: props.bindings ?? ({} as B),
|
|
194
209
|
env: props.env,
|
|
195
210
|
observability: scriptMetadata.observability,
|
|
196
211
|
createdAt: now,
|
|
197
212
|
updatedAt: now,
|
|
198
213
|
url: workerUrl,
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
214
|
+
// phantom property
|
|
215
|
+
Env: undefined!,
|
|
216
|
+
});
|
|
202
217
|
},
|
|
203
|
-
)
|
|
218
|
+
);
|
|
204
219
|
|
|
205
|
-
async function deleteWorker(
|
|
206
|
-
ctx: Context<
|
|
220
|
+
async function deleteWorker<B extends Bindings>(
|
|
221
|
+
ctx: Context<Worker<B>>,
|
|
207
222
|
api: CloudflareApi,
|
|
208
223
|
workerName: string,
|
|
209
224
|
) {
|
|
@@ -272,7 +287,6 @@ async function deleteWorker(
|
|
|
272
287
|
}
|
|
273
288
|
|
|
274
289
|
async function putWorker(
|
|
275
|
-
ctx: Context<WorkerOutput>,
|
|
276
290
|
api: CloudflareApi,
|
|
277
291
|
workerName: string,
|
|
278
292
|
scriptContent: string,
|
|
@@ -297,8 +311,6 @@ async function putWorker(
|
|
|
297
311
|
scriptName,
|
|
298
312
|
);
|
|
299
313
|
|
|
300
|
-
// console.log("Script Metadata:", JSON.stringify(scriptMetadata, null, 2));
|
|
301
|
-
|
|
302
314
|
// Add metadata as JSON
|
|
303
315
|
formData.append(
|
|
304
316
|
"metadata",
|
|
@@ -363,8 +375,8 @@ interface WorkerMetadata {
|
|
|
363
375
|
tags?: string[];
|
|
364
376
|
}
|
|
365
377
|
|
|
366
|
-
async function prepareWorkerMetadata(
|
|
367
|
-
ctx: Context<
|
|
378
|
+
async function prepareWorkerMetadata<B extends Bindings>(
|
|
379
|
+
ctx: Context<Worker<B>>,
|
|
368
380
|
oldBindings: Bindings | undefined,
|
|
369
381
|
props: WorkerProps,
|
|
370
382
|
): Promise<WorkerMetadata> {
|
|
@@ -374,7 +386,8 @@ async function prepareWorkerMetadata(
|
|
|
374
386
|
observability: {
|
|
375
387
|
enabled: props.observability?.enabled !== false,
|
|
376
388
|
},
|
|
377
|
-
|
|
389
|
+
// TODO(sam): base64 encode instead? 0 collision risk vs readability.
|
|
390
|
+
tags: [`alchemy:id:${slugify(ctx.fqn)}`],
|
|
378
391
|
migrations: {
|
|
379
392
|
new_classes: props.migrations?.new_classes ?? [],
|
|
380
393
|
deleted_classes: props.migrations?.deleted_classes ?? [],
|
|
@@ -384,7 +397,7 @@ async function prepareWorkerMetadata(
|
|
|
384
397
|
},
|
|
385
398
|
};
|
|
386
399
|
|
|
387
|
-
const bindings = (props.bindings ?? {}) as
|
|
400
|
+
const bindings = (props.bindings ?? {}) as Bindings;
|
|
388
401
|
|
|
389
402
|
// Convert bindings to the format expected by the API
|
|
390
403
|
for (const [bindingName, binding] of Object.entries(bindings)) {
|
|
@@ -394,7 +407,7 @@ async function prepareWorkerMetadata(
|
|
|
394
407
|
meta.bindings.push({
|
|
395
408
|
type: "kv_namespace",
|
|
396
409
|
name: bindingName,
|
|
397
|
-
namespace_id: binding.
|
|
410
|
+
namespace_id: binding.namespaceId,
|
|
398
411
|
});
|
|
399
412
|
} else if (typeof binding === "string") {
|
|
400
413
|
meta.bindings.push({
|
|
@@ -408,7 +421,7 @@ async function prepareWorkerMetadata(
|
|
|
408
421
|
name: bindingName,
|
|
409
422
|
service: binding.id,
|
|
410
423
|
});
|
|
411
|
-
} else if (
|
|
424
|
+
} else if (binding.type === "durable_object_namespace") {
|
|
412
425
|
const stableId = binding.id;
|
|
413
426
|
const className = binding.className;
|
|
414
427
|
|
|
@@ -439,11 +452,17 @@ async function prepareWorkerMetadata(
|
|
|
439
452
|
to: className,
|
|
440
453
|
});
|
|
441
454
|
}
|
|
442
|
-
} else if (
|
|
455
|
+
} else if (binding.type === "r2_bucket") {
|
|
443
456
|
meta.bindings.push({
|
|
444
457
|
type: "r2_bucket",
|
|
445
458
|
name: bindingName,
|
|
446
|
-
bucket_name: binding.name
|
|
459
|
+
bucket_name: binding.name,
|
|
460
|
+
});
|
|
461
|
+
} else if (isSecret(binding)) {
|
|
462
|
+
meta.bindings.push({
|
|
463
|
+
type: "secret_text",
|
|
464
|
+
name: bindingName,
|
|
465
|
+
text: binding.unencrypted,
|
|
447
466
|
});
|
|
448
467
|
} else {
|
|
449
468
|
// @ts-expect-error - we should never reach here
|
|
@@ -476,8 +495,8 @@ async function prepareWorkerMetadata(
|
|
|
476
495
|
return meta;
|
|
477
496
|
}
|
|
478
497
|
|
|
479
|
-
async function assertWorkerDoesNotExist(
|
|
480
|
-
ctx: Context<
|
|
498
|
+
async function assertWorkerDoesNotExist<B extends Bindings>(
|
|
499
|
+
ctx: Context<Worker<B>>,
|
|
481
500
|
api: CloudflareApi,
|
|
482
501
|
workerName: string,
|
|
483
502
|
) {
|
|
@@ -498,7 +517,7 @@ async function assertWorkerDoesNotExist(
|
|
|
498
517
|
|
|
499
518
|
if (
|
|
500
519
|
metadata.default_environment?.script.tags.includes(
|
|
501
|
-
`alchemy:id:${ctx.
|
|
520
|
+
`alchemy:id:${slugify(ctx.fqn)}`,
|
|
502
521
|
)
|
|
503
522
|
) {
|
|
504
523
|
return true;
|
|
@@ -514,10 +533,7 @@ async function assertWorkerDoesNotExist(
|
|
|
514
533
|
}
|
|
515
534
|
}
|
|
516
535
|
|
|
517
|
-
async function bundleWorkerScript(
|
|
518
|
-
ctx: Context<WorkerOutput>,
|
|
519
|
-
props: WorkerProps,
|
|
520
|
-
) {
|
|
536
|
+
async function bundleWorkerScript<B extends Bindings>(props: WorkerProps) {
|
|
521
537
|
// Get the script content - either from props.script, or by bundling
|
|
522
538
|
|
|
523
539
|
// Create and use a Bundle resource with worker-optimized configuration
|
|
@@ -538,18 +554,14 @@ async function bundleWorkerScript(
|
|
|
538
554
|
};
|
|
539
555
|
|
|
540
556
|
// Create the bundle
|
|
541
|
-
const bundle =
|
|
557
|
+
const bundle = await Bundle("bundle", {
|
|
542
558
|
entryPoint: props.entrypoint!,
|
|
543
559
|
...bundleOptions,
|
|
544
560
|
external: [...(bundleOptions.external ?? []), "cloudflare:workers"],
|
|
545
561
|
});
|
|
546
562
|
|
|
547
|
-
// Get the bundled content
|
|
548
|
-
const bundleOutput = await apply(bundle, {
|
|
549
|
-
quiet: ctx.quiet,
|
|
550
|
-
});
|
|
551
563
|
try {
|
|
552
|
-
return await fs.readFile(
|
|
564
|
+
return await fs.readFile(bundle.path, "utf-8");
|
|
553
565
|
} catch (error) {
|
|
554
566
|
console.error("Error reading bundle:", error);
|
|
555
567
|
throw new Error("Error reading bundle");
|
|
@@ -617,8 +629,8 @@ async function setupRoutes(
|
|
|
617
629
|
}
|
|
618
630
|
}
|
|
619
631
|
|
|
620
|
-
async function configureURL(
|
|
621
|
-
ctx: Context<
|
|
632
|
+
async function configureURL<B extends Bindings>(
|
|
633
|
+
ctx: Context<Worker<B>>,
|
|
622
634
|
api: CloudflareApi,
|
|
623
635
|
workerName: string,
|
|
624
636
|
url: boolean,
|
|
@@ -657,7 +669,7 @@ async function configureURL(
|
|
|
657
669
|
// Add a delay when the subdomain is first created.
|
|
658
670
|
// This is to prevent an issue where a negative cache-hit
|
|
659
671
|
// causes the subdomain to be unavailable for 30 seconds.
|
|
660
|
-
if (ctx.
|
|
672
|
+
if (ctx.phase === "create" || !ctx.output?.url) {
|
|
661
673
|
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
662
674
|
}
|
|
663
675
|
}
|