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.
Files changed (310) hide show
  1. package/lib/alchemy.d.ts +67 -0
  2. package/lib/alchemy.js +40 -0
  3. package/lib/apply.d.ts +3 -20
  4. package/lib/apply.js +86 -82
  5. package/lib/aws/account-id.d.ts +0 -1
  6. package/lib/aws/account-id.js +0 -1
  7. package/lib/aws/bucket.d.ts +4 -7
  8. package/lib/aws/bucket.js +8 -12
  9. package/lib/aws/function.d.ts +4 -7
  10. package/lib/aws/function.js +9 -30
  11. package/lib/aws/index.d.ts +1 -1
  12. package/lib/aws/index.js +1 -1
  13. package/lib/aws/oidc/github-oidc-provider.d.ts +2 -6
  14. package/lib/aws/oidc/github-oidc-provider.js +10 -15
  15. package/lib/aws/oidc/index.d.ts +0 -1
  16. package/lib/aws/oidc/index.js +0 -1
  17. package/lib/aws/oidc/oidc-provider.d.ts +4 -6
  18. package/lib/aws/oidc/oidc-provider.js +9 -11
  19. package/lib/aws/policy-attachment.d.ts +9 -0
  20. package/lib/aws/policy-attachment.js +20 -0
  21. package/lib/aws/policy.d.ts +4 -16
  22. package/lib/aws/policy.js +9 -40
  23. package/lib/aws/queue.d.ts +4 -34
  24. package/lib/aws/queue.js +10 -20
  25. package/lib/aws/role.d.ts +4 -7
  26. package/lib/aws/role.js +17 -26
  27. package/lib/aws/ses.d.ts +4 -10
  28. package/lib/aws/ses.js +118 -131
  29. package/lib/aws/table.d.ts +4 -7
  30. package/lib/aws/table.js +8 -11
  31. package/lib/cloudflare/api.d.ts +0 -1
  32. package/lib/cloudflare/api.js +0 -1
  33. package/lib/cloudflare/asset-manifest.d.ts +0 -1
  34. package/lib/cloudflare/asset-manifest.js +0 -1
  35. package/lib/cloudflare/auth.d.ts +0 -1
  36. package/lib/cloudflare/auth.js +0 -1
  37. package/lib/cloudflare/bindings.d.ts +1 -1
  38. package/lib/cloudflare/bindings.js +3 -2
  39. package/lib/cloudflare/bound.d.ts +0 -1
  40. package/lib/cloudflare/bound.js +0 -1
  41. package/lib/cloudflare/bucket.d.ts +7 -15
  42. package/lib/cloudflare/bucket.js +12 -19
  43. package/lib/cloudflare/durable-object-namespace.d.ts +0 -3
  44. package/lib/cloudflare/durable-object-namespace.js +0 -4
  45. package/lib/cloudflare/generate-asset-manifest.d.ts +0 -1
  46. package/lib/cloudflare/generate-asset-manifest.js +1 -2
  47. package/lib/cloudflare/index.d.ts +0 -1
  48. package/lib/cloudflare/index.js +0 -1
  49. package/lib/cloudflare/kv-namespace.d.ts +6 -9
  50. package/lib/cloudflare/kv-namespace.js +16 -20
  51. package/lib/cloudflare/state.d.ts +0 -1
  52. package/lib/cloudflare/state.js +0 -1
  53. package/lib/cloudflare/static-site-router.d.ts +0 -1
  54. package/lib/cloudflare/static-site-router.js +0 -4
  55. package/lib/cloudflare/static-site.d.ts +5 -11
  56. package/lib/cloudflare/static-site.js +16 -28
  57. package/lib/cloudflare/types.d.ts +0 -1
  58. package/lib/cloudflare/types.js +0 -1
  59. package/lib/cloudflare/upload-asset-manifest.d.ts +0 -1
  60. package/lib/cloudflare/upload-asset-manifest.js +0 -1
  61. package/lib/cloudflare/worker-metadata.d.ts +0 -1
  62. package/lib/cloudflare/worker-metadata.js +0 -1
  63. package/lib/cloudflare/worker-migration.d.ts +0 -1
  64. package/lib/cloudflare/worker-migration.js +0 -1
  65. package/lib/cloudflare/worker.d.ts +8 -14
  66. package/lib/cloudflare/worker.js +37 -49
  67. package/lib/context.d.ts +58 -0
  68. package/lib/context.js +36 -0
  69. package/lib/destroy.d.ts +10 -13
  70. package/lib/destroy.js +104 -43
  71. package/lib/{esbuild.d.ts → esbuild/bundle.d.ts} +4 -18
  72. package/lib/{esbuild.js → esbuild/bundle.js} +10 -24
  73. package/lib/esbuild/index.d.ts +1 -0
  74. package/lib/esbuild/index.js +1 -0
  75. package/lib/fs/file.d.ts +13 -0
  76. package/lib/fs/file.js +20 -0
  77. package/lib/fs/folder.d.ts +10 -0
  78. package/lib/fs/folder.js +16 -0
  79. package/lib/fs/index.d.ts +2 -0
  80. package/lib/fs/index.js +2 -0
  81. package/lib/github/client.d.ts +0 -1
  82. package/lib/github/client.js +0 -1
  83. package/lib/github/index.d.ts +0 -1
  84. package/lib/github/index.js +0 -1
  85. package/lib/github/secret.d.ts +4 -6
  86. package/lib/github/secret.js +10 -12
  87. package/lib/index.d.ts +6 -10
  88. package/lib/index.js +5 -9
  89. package/lib/resource.d.ts +34 -62
  90. package/lib/resource.js +29 -270
  91. package/lib/scope.d.ts +35 -14
  92. package/lib/scope.js +78 -23
  93. package/lib/secret.d.ts +2 -7
  94. package/lib/secret.js +7 -20
  95. package/lib/state.d.ts +14 -10
  96. package/lib/state.js +15 -14
  97. package/lib/stripe/index.d.ts +0 -1
  98. package/lib/stripe/index.js +0 -1
  99. package/lib/stripe/price.d.ts +4 -5
  100. package/lib/stripe/price.js +10 -20
  101. package/lib/stripe/product.d.ts +4 -5
  102. package/lib/stripe/product.js +10 -20
  103. package/lib/stripe/webhook.d.ts +4 -6
  104. package/lib/stripe/webhook.js +12 -25
  105. package/lib/test/bun.d.ts +19 -0
  106. package/lib/test/bun.js +55 -0
  107. package/lib/{utils → util}/content-type.d.ts +0 -1
  108. package/lib/{utils → util}/content-type.js +0 -1
  109. package/lib/{encrypt.d.ts → util/encrypt.d.ts} +0 -1
  110. package/lib/{encrypt.js → util/encrypt.js} +0 -1
  111. package/lib/{error.d.ts → util/ignore.d.ts} +0 -1
  112. package/lib/{error.js → util/ignore.js} +0 -1
  113. package/lib/{utils → util}/retry.d.ts +0 -1
  114. package/lib/{utils → util}/retry.js +0 -1
  115. package/lib/util/serde.d.ts +3 -0
  116. package/lib/{serde.js → util/serde.js} +19 -10
  117. package/lib/util/slugify.d.ts +1 -0
  118. package/lib/util/slugify.js +3 -0
  119. package/package.json +5 -4
  120. package/src/alchemy.ts +120 -0
  121. package/src/apply.ts +109 -114
  122. package/src/aws/bucket.ts +11 -14
  123. package/src/aws/function.ts +13 -33
  124. package/src/aws/index.ts +1 -0
  125. package/src/aws/oidc/github-oidc-provider.ts +14 -19
  126. package/src/aws/oidc/oidc-provider.ts +19 -12
  127. package/src/aws/policy-attachment.ts +51 -0
  128. package/src/aws/policy.ts +15 -60
  129. package/src/aws/queue.ts +17 -21
  130. package/src/aws/role.ts +25 -28
  131. package/src/aws/ses.ts +150 -164
  132. package/src/aws/table.ts +15 -15
  133. package/src/cloudflare/bindings.ts +8 -0
  134. package/src/cloudflare/bucket.ts +39 -47
  135. package/src/cloudflare/durable-object-namespace.ts +0 -10
  136. package/src/cloudflare/generate-asset-manifest.ts +1 -1
  137. package/src/cloudflare/kv-namespace.ts +35 -33
  138. package/src/cloudflare/static-site-router.ts +0 -3
  139. package/src/cloudflare/static-site.ts +44 -60
  140. package/src/cloudflare/worker.ts +105 -111
  141. package/src/context.ts +122 -0
  142. package/src/destroy.ts +124 -73
  143. package/src/{esbuild.ts → esbuild/bundle.ts} +16 -28
  144. package/src/esbuild/index.ts +1 -0
  145. package/src/fs/file.ts +39 -0
  146. package/src/fs/folder.ts +32 -0
  147. package/src/fs/index.ts +2 -0
  148. package/src/github/secret.ts +19 -16
  149. package/src/index.ts +7 -15
  150. package/src/resource.ts +101 -462
  151. package/src/scope.ts +101 -36
  152. package/src/secret.ts +9 -32
  153. package/src/state.ts +30 -21
  154. package/src/stripe/price.ts +17 -22
  155. package/src/stripe/product.ts +17 -22
  156. package/src/stripe/webhook.ts +21 -27
  157. package/src/test/bun.ts +105 -0
  158. package/src/util/serde.ts +53 -0
  159. package/src/util/slugify.ts +3 -0
  160. package/lib/$.d.ts +0 -12
  161. package/lib/$.d.ts.map +0 -1
  162. package/lib/$.js +0 -42
  163. package/lib/$.js.map +0 -1
  164. package/lib/alchemize.d.ts +0 -47
  165. package/lib/alchemize.d.ts.map +0 -1
  166. package/lib/alchemize.js +0 -116
  167. package/lib/alchemize.js.map +0 -1
  168. package/lib/apply.d.ts.map +0 -1
  169. package/lib/apply.js.map +0 -1
  170. package/lib/aws/account-id.d.ts.map +0 -1
  171. package/lib/aws/account-id.js.map +0 -1
  172. package/lib/aws/bucket.d.ts.map +0 -1
  173. package/lib/aws/bucket.js.map +0 -1
  174. package/lib/aws/function.d.ts.map +0 -1
  175. package/lib/aws/function.js.map +0 -1
  176. package/lib/aws/index.d.ts.map +0 -1
  177. package/lib/aws/index.js.map +0 -1
  178. package/lib/aws/oidc/github-oidc-provider.d.ts.map +0 -1
  179. package/lib/aws/oidc/github-oidc-provider.js.map +0 -1
  180. package/lib/aws/oidc/index.d.ts.map +0 -1
  181. package/lib/aws/oidc/index.js.map +0 -1
  182. package/lib/aws/oidc/oidc-provider.d.ts.map +0 -1
  183. package/lib/aws/oidc/oidc-provider.js.map +0 -1
  184. package/lib/aws/policy.d.ts.map +0 -1
  185. package/lib/aws/policy.js.map +0 -1
  186. package/lib/aws/queue.d.ts.map +0 -1
  187. package/lib/aws/queue.js.map +0 -1
  188. package/lib/aws/role.d.ts.map +0 -1
  189. package/lib/aws/role.js.map +0 -1
  190. package/lib/aws/ses.d.ts.map +0 -1
  191. package/lib/aws/ses.js.map +0 -1
  192. package/lib/aws/table.d.ts.map +0 -1
  193. package/lib/aws/table.js.map +0 -1
  194. package/lib/cloudflare/api.d.ts.map +0 -1
  195. package/lib/cloudflare/api.js.map +0 -1
  196. package/lib/cloudflare/asset-manifest.d.ts.map +0 -1
  197. package/lib/cloudflare/asset-manifest.js.map +0 -1
  198. package/lib/cloudflare/auth.d.ts.map +0 -1
  199. package/lib/cloudflare/auth.js.map +0 -1
  200. package/lib/cloudflare/bindings.d.ts.map +0 -1
  201. package/lib/cloudflare/bindings.js.map +0 -1
  202. package/lib/cloudflare/bound.d.ts.map +0 -1
  203. package/lib/cloudflare/bound.js.map +0 -1
  204. package/lib/cloudflare/bucket.d.ts.map +0 -1
  205. package/lib/cloudflare/bucket.js.map +0 -1
  206. package/lib/cloudflare/durable-object-namespace.d.ts.map +0 -1
  207. package/lib/cloudflare/durable-object-namespace.js.map +0 -1
  208. package/lib/cloudflare/generate-asset-manifest.d.ts.map +0 -1
  209. package/lib/cloudflare/generate-asset-manifest.js.map +0 -1
  210. package/lib/cloudflare/index.d.ts.map +0 -1
  211. package/lib/cloudflare/index.js.map +0 -1
  212. package/lib/cloudflare/kv-namespace.d.ts.map +0 -1
  213. package/lib/cloudflare/kv-namespace.js.map +0 -1
  214. package/lib/cloudflare/state.d.ts.map +0 -1
  215. package/lib/cloudflare/state.js.map +0 -1
  216. package/lib/cloudflare/static-site-router.d.ts.map +0 -1
  217. package/lib/cloudflare/static-site-router.js.map +0 -1
  218. package/lib/cloudflare/static-site.d.ts.map +0 -1
  219. package/lib/cloudflare/static-site.js.map +0 -1
  220. package/lib/cloudflare/types.d.ts.map +0 -1
  221. package/lib/cloudflare/types.js.map +0 -1
  222. package/lib/cloudflare/upload-asset-manifest.d.ts.map +0 -1
  223. package/lib/cloudflare/upload-asset-manifest.js.map +0 -1
  224. package/lib/cloudflare/worker-metadata.d.ts.map +0 -1
  225. package/lib/cloudflare/worker-metadata.js.map +0 -1
  226. package/lib/cloudflare/worker-migration.d.ts.map +0 -1
  227. package/lib/cloudflare/worker-migration.js.map +0 -1
  228. package/lib/cloudflare/worker.d.ts.map +0 -1
  229. package/lib/cloudflare/worker.js.map +0 -1
  230. package/lib/destroy.d.ts.map +0 -1
  231. package/lib/destroy.js.map +0 -1
  232. package/lib/encrypt.d.ts.map +0 -1
  233. package/lib/encrypt.js.map +0 -1
  234. package/lib/error.d.ts.map +0 -1
  235. package/lib/error.js.map +0 -1
  236. package/lib/esbuild.d.ts.map +0 -1
  237. package/lib/esbuild.js.map +0 -1
  238. package/lib/fs.d.ts +0 -12
  239. package/lib/fs.d.ts.map +0 -1
  240. package/lib/fs.js +0 -41
  241. package/lib/fs.js.map +0 -1
  242. package/lib/github/client.d.ts.map +0 -1
  243. package/lib/github/client.js.map +0 -1
  244. package/lib/github/index.d.ts.map +0 -1
  245. package/lib/github/index.js.map +0 -1
  246. package/lib/github/secret.d.ts.map +0 -1
  247. package/lib/github/secret.js.map +0 -1
  248. package/lib/global.d.ts +0 -16
  249. package/lib/global.d.ts.map +0 -1
  250. package/lib/global.js +0 -42
  251. package/lib/global.js.map +0 -1
  252. package/lib/index.d.ts.map +0 -1
  253. package/lib/index.js.map +0 -1
  254. package/lib/input.d.ts +0 -7
  255. package/lib/input.d.ts.map +0 -1
  256. package/lib/input.js +0 -2
  257. package/lib/input.js.map +0 -1
  258. package/lib/main.d.ts +0 -3
  259. package/lib/main.d.ts.map +0 -1
  260. package/lib/main.js +0 -32
  261. package/lib/main.js.map +0 -1
  262. package/lib/output.d.ts +0 -25
  263. package/lib/output.d.ts.map +0 -1
  264. package/lib/output.js +0 -23
  265. package/lib/output.js.map +0 -1
  266. package/lib/print.d.ts +0 -7
  267. package/lib/print.d.ts.map +0 -1
  268. package/lib/print.js +0 -10
  269. package/lib/print.js.map +0 -1
  270. package/lib/resource.d.ts.map +0 -1
  271. package/lib/resource.js.map +0 -1
  272. package/lib/scope.d.ts.map +0 -1
  273. package/lib/scope.js.map +0 -1
  274. package/lib/secret.d.ts.map +0 -1
  275. package/lib/secret.js.map +0 -1
  276. package/lib/serde.d.ts +0 -3
  277. package/lib/serde.d.ts.map +0 -1
  278. package/lib/serde.js.map +0 -1
  279. package/lib/slug.d.ts +0 -2
  280. package/lib/slug.d.ts.map +0 -1
  281. package/lib/slug.js +0 -4
  282. package/lib/slug.js.map +0 -1
  283. package/lib/state.d.ts.map +0 -1
  284. package/lib/state.js.map +0 -1
  285. package/lib/stripe/index.d.ts.map +0 -1
  286. package/lib/stripe/index.js.map +0 -1
  287. package/lib/stripe/price.d.ts.map +0 -1
  288. package/lib/stripe/price.js.map +0 -1
  289. package/lib/stripe/product.d.ts.map +0 -1
  290. package/lib/stripe/product.js.map +0 -1
  291. package/lib/stripe/webhook.d.ts.map +0 -1
  292. package/lib/stripe/webhook.js.map +0 -1
  293. package/lib/utils/content-type.d.ts.map +0 -1
  294. package/lib/utils/content-type.js.map +0 -1
  295. package/lib/utils/retry.d.ts.map +0 -1
  296. package/lib/utils/retry.js.map +0 -1
  297. package/src/$.ts +0 -69
  298. package/src/alchemize.ts +0 -195
  299. package/src/fs.ts +0 -47
  300. package/src/global.ts +0 -63
  301. package/src/input.ts +0 -19
  302. package/src/main.ts +0 -34
  303. package/src/output.ts +0 -75
  304. package/src/print.ts +0 -18
  305. package/src/serde.ts +0 -46
  306. package/src/slug.ts +0 -3
  307. /package/src/{utils → util}/content-type.ts +0 -0
  308. /package/src/{encrypt.ts → util/encrypt.ts} +0 -0
  309. /package/src/{error.ts → util/ignore.ts} +0 -0
  310. /package/src/{utils → util}/retry.ts +0 -0
@@ -1,4 +1,6 @@
1
- import type { Resolved } from "../output";
1
+ import type { Context } from "../context";
2
+ import { Resource } from "../resource";
3
+ export declare function isKVNamespace(resource: any): resource is KVNamespace;
2
4
  /**
3
5
  * Properties for creating or updating a KV Namespace
4
6
  */
@@ -41,12 +43,12 @@ export interface KVPair {
41
43
  /**
42
44
  * Output returned after KV Namespace creation/update
43
45
  */
44
- export interface KVNamespaceOutput extends KVNamespaceProps {
46
+ export interface KVNamespace extends Resource<"cloudflare::KVNamespace">, KVNamespaceProps {
45
47
  type: "kv_namespace";
46
48
  /**
47
49
  * The ID of the namespace
48
50
  */
49
- id: string;
51
+ namespaceId: string;
50
52
  /**
51
53
  * Time at which the namespace was created
52
54
  */
@@ -56,9 +58,4 @@ export interface KVNamespaceOutput extends KVNamespaceProps {
56
58
  */
57
59
  modifiedAt: number;
58
60
  }
59
- export declare function isKVNamespace(resource: any): resource is Resolved<KVNamespace>;
60
- declare const KVNamespace_base: import("../resource").Provider<"cloudflare::KVNamespace", [props: KVNamespaceProps], KVNamespaceOutput>;
61
- export declare class KVNamespace extends KVNamespace_base {
62
- }
63
- export {};
64
- //# sourceMappingURL=kv-namespace.d.ts.map
61
+ export declare const KVNamespace: ((this: Context<KVNamespace>, id: string, props: KVNamespaceProps) => Promise<KVNamespace>) | (((this: any, id: string, props: KVNamespaceProps) => never) & (new (_: never) => never));
@@ -1,15 +1,15 @@
1
1
  import { Resource } from "../resource";
2
- import { withExponentialBackoff } from "../utils/retry";
2
+ import { withExponentialBackoff } from "../util/retry";
3
3
  import { createCloudflareApi } from "./api";
4
4
  export function isKVNamespace(resource) {
5
5
  return (resource && typeof resource === "object" && resource.type === "kv_namespace");
6
6
  }
7
- export class KVNamespace extends Resource("cloudflare::KVNamespace", async (ctx, props) => {
7
+ export const KVNamespace = Resource("cloudflare::KVNamespace", async function (id, props) {
8
8
  // Create Cloudflare API client with automatic account discovery
9
9
  const api = await createCloudflareApi();
10
- if (ctx.event === "delete") {
10
+ if (this.phase === "delete") {
11
11
  // For delete operations, we need to check if the namespace ID exists in the output
12
- const namespaceId = ctx.output?.id;
12
+ const namespaceId = this.output?.namespaceId;
13
13
  if (namespaceId) {
14
14
  // Delete KV namespace
15
15
  const deleteResponse = await api.delete(`/accounts/${api.accountId}/storage/kv/namespaces/${namespaceId}`);
@@ -21,19 +21,20 @@ export class KVNamespace extends Resource("cloudflare::KVNamespace", async (ctx,
21
21
  }
22
22
  }
23
23
  // Return minimal output for deleted state
24
- return;
24
+ return this.destroy();
25
25
  }
26
26
  else {
27
27
  // For create or update operations
28
- // If ctx.event is "update", we expect ctx.output to exist
29
- let namespaceId = ctx.event === "update" ? ctx.output?.id || "" : "";
30
- let createdAt = ctx.event === "update"
31
- ? ctx.output?.createdAt || Date.now()
28
+ // If this.phase is "update", we expect this.output to exist
29
+ let namespaceId = this.phase === "update" ? this.output?.namespaceId || "" : "";
30
+ let createdAt = this.phase === "update"
31
+ ? this.output?.createdAt || Date.now()
32
32
  : Date.now();
33
- if (ctx.event === "update" && namespaceId) {
33
+ if (this.phase === "update" && namespaceId) {
34
34
  // Can't update a KV namespace title directly, just work with existing ID
35
35
  }
36
36
  else {
37
+ // TODO: if it already exists, then check the tags to see if we own it and continue
37
38
  // Create new KV namespace
38
39
  const createResponse = await api.post(`/accounts/${api.accountId}/storage/kv/namespaces`, {
39
40
  title: props.title,
@@ -97,18 +98,13 @@ export class KVNamespace extends Resource("cloudflare::KVNamespace", async (ctx,
97
98
  }
98
99
  }
99
100
  }
100
- const now = Date.now();
101
- // Construct the output
102
- const output = {
101
+ return this({
103
102
  type: "kv_namespace",
104
- id: namespaceId,
103
+ namespaceId: namespaceId,
105
104
  title: props.title,
106
105
  values: props.values,
107
106
  createdAt: createdAt,
108
- modifiedAt: now,
109
- };
110
- return output;
107
+ modifiedAt: Date.now(),
108
+ });
111
109
  }
112
- }) {
113
- }
114
- //# sourceMappingURL=kv-namespace.js.map
110
+ });
@@ -80,4 +80,3 @@ export declare class CloudflareStateStore implements StateStore {
80
80
  */
81
81
  private getNamespacedKey;
82
82
  }
83
- //# sourceMappingURL=state.d.ts.map
@@ -106,4 +106,3 @@ export class CloudflareStateStore {
106
106
  return `${this.prefix}${key}`;
107
107
  }
108
108
  }
109
- //# sourceMappingURL=state.js.map
@@ -16,4 +16,3 @@ declare const _default: {
16
16
  fetch(request: Request, env: Env): Promise<Response>;
17
17
  };
18
18
  export default _default;
19
- //# sourceMappingURL=static-site-router.d.ts.map
@@ -7,14 +7,12 @@ export default {
7
7
  isInit = true;
8
8
  for (const [key, value] of Object.entries(env)) {
9
9
  if (key.startsWith("ROUTE_")) {
10
- console.log(key, value);
11
10
  const service = value;
12
11
  const patternKey = `__${key}`;
13
12
  if (!(patternKey in env)) {
14
13
  throw new Error(`Missing pattern key: ${patternKey}`);
15
14
  }
16
15
  const pattern = env[`__${key}`];
17
- console.log("pattern", pattern);
18
16
  // TODO(sam): we should support narrowing down METHOD
19
17
  app.all(pattern, (ctx) => service.fetch(ctx.req.raw));
20
18
  }
@@ -25,7 +23,6 @@ export default {
25
23
  };
26
24
  // fall back to assuming the request is a static file
27
25
  app.notFound(async (ctx) => {
28
- console.log("not found");
29
26
  const request = ctx.req;
30
27
  const env = ctx.env;
31
28
  const url = new URL(request.url);
@@ -107,4 +104,3 @@ app.notFound(async (ctx) => {
107
104
  return response;
108
105
  }
109
106
  });
110
- //# sourceMappingURL=static-site-router.js.map
@@ -1,4 +1,6 @@
1
- import type { BundleProps } from "../esbuild";
1
+ import type { Context } from "../context";
2
+ import type { BundleProps } from "../esbuild/bundle";
3
+ import { Resource } from "../resource";
2
4
  import { Worker } from "./worker";
3
5
  /**
4
6
  * Idea of using KV with timeout inspired by SST: https://github.com/sst/sst/blob/dev/platform/src/components/cloudflare/static-site.ts
@@ -98,11 +100,7 @@ export interface StaticSiteProps {
98
100
  /**
99
101
  * Output returned after StaticSite creation/update
100
102
  */
101
- export interface StaticSiteOutput {
102
- /**
103
- * The ID of the site
104
- */
105
- id: string;
103
+ export interface StaticSite extends Resource<"cloudflare::StaticSite"> {
106
104
  /**
107
105
  * The ID of the worker
108
106
  */
@@ -159,8 +157,4 @@ export interface StaticSiteOutput {
159
157
  */
160
158
  routes?: Record<string, string>;
161
159
  }
162
- declare const StaticSite_base: import("../resource").Provider<string, [props: StaticSiteProps], StaticSiteOutput>;
163
- export declare class StaticSite extends StaticSite_base {
164
- }
165
- export {};
166
- //# sourceMappingURL=static-site.d.ts.map
160
+ export declare const StaticSite: ((this: Context<StaticSite>, id: string, props: StaticSiteProps) => Promise<StaticSite>) | (((this: any, id: string, props: StaticSiteProps) => never) & (new (_: never) => never));
@@ -2,7 +2,6 @@ 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 { apply } from "../apply";
6
5
  import { Resource } from "../resource";
7
6
  import { createCloudflareApi } from "./api";
8
7
  import { generateAssetManifest } from "./generate-asset-manifest";
@@ -10,13 +9,13 @@ import { KVNamespace } from "./kv-namespace";
10
9
  import { uploadAssetManifest } from "./upload-asset-manifest";
11
10
  import { Worker } from "./worker";
12
11
  const __dirname = import.meta.dirname;
13
- export class StaticSite extends Resource("cloudflare::StaticSite", {
12
+ export const StaticSite = Resource("cloudflare::StaticSite", {
14
13
  alwaysUpdate: true,
15
- }, async (ctx, props) => {
16
- if (ctx.event === "delete") {
14
+ }, async function (id, props) {
15
+ if (this.phase === "delete") {
17
16
  // For delete operations, we'll rely on the Worker delete to clean up
18
17
  // Return empty output for deleted state
19
- return;
18
+ return this.destroy();
20
19
  }
21
20
  // Validate that a name is provided
22
21
  if (!props.name) {
@@ -38,14 +37,14 @@ export class StaticSite extends Resource("cloudflare::StaticSite", {
38
37
  // Run build command if provided
39
38
  if (props.build?.command) {
40
39
  try {
41
- if (!ctx.quiet) {
40
+ if (!this.quiet) {
42
41
  console.log(props.build.command);
43
42
  }
44
43
  const execAsync = promisify(exec);
45
44
  const { stdout, stderr } = await execAsync(props.build.command, {
46
45
  cwd: process.cwd(),
47
46
  });
48
- if (stdout && !ctx.quiet)
47
+ if (stdout && !this.quiet)
49
48
  console.log(stdout);
50
49
  }
51
50
  catch (error) {
@@ -65,17 +64,14 @@ export class StaticSite extends Resource("cloudflare::StaticSite", {
65
64
  // Create Cloudflare API client with automatic account discovery
66
65
  const api = await createCloudflareApi();
67
66
  // Step 1: Create or get the KV namespace for assets
68
- const kv = new KVNamespace("assets", {
69
- title: `${siteName}-assets`,
70
- });
71
- const [{ id: kvNamespaceId }, assetManifest] = await Promise.all([
72
- apply(kv, {
73
- quiet: ctx.quiet,
67
+ const [kv, assetManifest] = await Promise.all([
68
+ KVNamespace("assets", {
69
+ title: `${siteName}-assets`,
74
70
  }),
75
71
  generateAssetManifest(props.dir),
76
72
  ]);
77
73
  // Step 3: Upload assets to KV
78
- await uploadAssetManifest(api, kvNamespaceId, assetManifest);
74
+ await uploadAssetManifest(api, kv.namespaceId, assetManifest);
79
75
  // Prepare the bindings for the worker
80
76
  const bindings = {
81
77
  ASSETS: kv,
@@ -115,7 +111,7 @@ export class StaticSite extends Resource("cloudflare::StaticSite", {
115
111
  catch (error) {
116
112
  // TypeScript file doesn't exist, use JavaScript (default)
117
113
  }
118
- const worker = new Worker("worker", {
114
+ const worker = await Worker("worker", {
119
115
  name: siteName,
120
116
  url: true,
121
117
  format: props.format || "esm",
@@ -133,14 +129,9 @@ export class StaticSite extends Resource("cloudflare::StaticSite", {
133
129
  key,
134
130
  ])),
135
131
  },
136
- },
137
- // place a dependency on the namespace
138
- kv.id);
139
- // Get current timestamp
132
+ });
140
133
  const now = Date.now();
141
- // Construct the output
142
- const output = {
143
- id: siteName,
134
+ return this({
144
135
  workerId: worker.id,
145
136
  name: siteName,
146
137
  directory: props.dir,
@@ -148,14 +139,11 @@ export class StaticSite extends Resource("cloudflare::StaticSite", {
148
139
  errorPage: props.errorPage,
149
140
  indexPage,
150
141
  assets: assetManifest.map((item) => item.key),
151
- createdAt: ctx.output?.createdAt || now,
142
+ createdAt: this.output?.createdAt || now,
152
143
  updatedAt: now,
153
144
  domain: props.domain,
154
145
  production: props.production !== false,
155
146
  url: worker.url,
156
147
  routes,
157
- };
158
- return output;
159
- }) {
160
- }
161
- //# sourceMappingURL=static-site.js.map
148
+ });
149
+ });
@@ -49,4 +49,3 @@ export interface CloudflareApiError {
49
49
  * @returns Formatted error message
50
50
  */
51
51
  export declare function extractCloudflareError(response: Response): Promise<string>;
52
- //# sourceMappingURL=types.d.ts.map
@@ -18,4 +18,3 @@ export async function extractCloudflareError(response) {
18
18
  return `HTTP ${response.status}: ${response.statusText}`;
19
19
  }
20
20
  }
21
- //# sourceMappingURL=types.js.map
@@ -9,4 +9,3 @@ type UploadResult = {
9
9
  };
10
10
  export declare function uploadAssetManifest(api: CloudflareApi, namespaceId: string, manifest: AssetManifest): Promise<UploadResult[]>;
11
11
  export {};
12
- //# sourceMappingURL=upload-asset-manifest.d.ts.map
@@ -52,4 +52,3 @@ export async function uploadAssetManifest(api, namespaceId, manifest) {
52
52
  }
53
53
  }
54
54
  }
55
- //# sourceMappingURL=upload-asset-manifest.js.map
@@ -127,4 +127,3 @@ export interface WorkerDefaultEnvironment extends WorkerEnvironment {
127
127
  */
128
128
  script: WorkerScriptInfo;
129
129
  }
130
- //# sourceMappingURL=worker-metadata.d.ts.map
@@ -1,2 +1 @@
1
1
  export {};
2
- //# sourceMappingURL=worker-metadata.js.map
@@ -107,4 +107,3 @@ export interface MigrationStep {
107
107
  */
108
108
  transferred_classes?: TransferredClass[];
109
109
  }
110
- //# sourceMappingURL=worker-migration.d.ts.map
@@ -8,4 +8,3 @@ export function isSingleStepMigration(migration) {
8
8
  export function isMultiStepMigration(migration) {
9
9
  return "steps" in migration;
10
10
  }
11
- //# sourceMappingURL=worker-migration.js.map
@@ -1,7 +1,7 @@
1
- import { type BundleProps } from "../esbuild";
2
- import type { Input } from "../input";
3
- import type { Resolved } from "../output";
4
- import type { Bindings } from "./bindings";
1
+ import type { Context } from "../context";
2
+ import { type BundleProps } from "../esbuild/bundle";
3
+ import { Resource } from "../resource";
4
+ import { type Bindings } from "./bindings";
5
5
  import type { Bound } from "./bound";
6
6
  import type { SingleStepMigration } from "./worker-migration";
7
7
  /**
@@ -78,7 +78,7 @@ export interface WorkerProps<B extends Bindings = Bindings> {
78
78
  /**
79
79
  * Output returned after Worker creation/update
80
80
  */
81
- export interface WorkerOutput<B extends Bindings = Bindings> extends Omit<WorkerProps<B>, "url"> {
81
+ export interface Worker<B extends Bindings = Bindings> extends Resource<"cloudflare::Worker">, Omit<WorkerProps<B>, "url"> {
82
82
  type: "service";
83
83
  /**
84
84
  * The ID of the worker
@@ -100,15 +100,9 @@ export interface WorkerOutput<B extends Bindings = Bindings> extends Omit<Worker
100
100
  /**
101
101
  * The bindings that were created
102
102
  */
103
- bindings: B;
104
- }
105
- export declare function isWorker(resource: any): resource is Resolved<Worker>;
106
- declare const Worker_base: import("../resource").Provider<string, [props: WorkerProps<Bindings>], WorkerOutput<Bindings>>;
107
- export declare class Worker<B extends Bindings = Bindings> extends Worker_base {
108
- readonly Env: {
103
+ bindings: B | undefined;
104
+ Env: {
109
105
  [bindingName in keyof B]: Bound<B[bindingName]>;
110
106
  };
111
- constructor(id: string, input: Input<WorkerProps<B>>, ...inputs: any[]);
112
107
  }
113
- export {};
114
- //# sourceMappingURL=worker.d.ts.map
108
+ export declare const Worker: (<const B extends Bindings>(this: Context<Worker<NoInfer<B>>>, id: string, props: WorkerProps<B>) => Promise<Worker<B>>) | (((this: any, id: string, props: WorkerProps<Bindings>) => never) & (new (_: never) => never));
@@ -1,24 +1,15 @@
1
1
  import * as fs from "fs/promises";
2
- import { apply } from "../apply";
3
- import { Bundle } from "../esbuild";
2
+ import { Bundle } from "../esbuild/bundle";
4
3
  import { Resource } from "../resource";
5
- import { Secret } from "../secret";
6
- import { withExponentialBackoff } from "../utils/retry";
4
+ import { isSecret } from "../secret";
5
+ import { withExponentialBackoff } from "../util/retry";
6
+ import { slugify } from "../util/slugify";
7
7
  import { createCloudflareApi } from "./api";
8
- import { isBucket } from "./bucket";
9
- import { isDurableObjectNamespace } from "./durable-object-namespace";
8
+ import { isDurableObjectNamespace, } from "./bindings";
10
9
  import { isKVNamespace } from "./kv-namespace";
11
- export function isWorker(resource) {
12
- return resource && typeof resource === "object" && resource.type === "worker";
13
- }
14
- export class Worker extends Resource("cloudflare::Worker", {
10
+ export const Worker = Resource("cloudflare::Worker", {
15
11
  alwaysUpdate: true,
16
- }, applyWorker) {
17
- constructor(id, input, ...inputs) {
18
- super(id, input, ...inputs);
19
- }
20
- }
21
- async function applyWorker(ctx, props) {
12
+ }, async function (id, props) {
22
13
  // Create Cloudflare API client with automatic account discovery
23
14
  const api = await createCloudflareApi();
24
15
  // Use the provided name
@@ -27,30 +18,31 @@ async function applyWorker(ctx, props) {
27
18
  if (!props.script && !props.entrypoint) {
28
19
  throw new Error("One of script or entryPoint must be provided");
29
20
  }
30
- if (ctx.event === "delete") {
31
- return deleteWorker(ctx, api, workerName);
21
+ if (this.phase === "delete") {
22
+ await deleteWorker(this, api, workerName);
23
+ return this.destroy();
32
24
  }
33
- else if (ctx.event === "create") {
34
- await assertWorkerDoesNotExist(ctx, api, workerName);
25
+ else if (this.phase === "create") {
26
+ await assertWorkerDoesNotExist(this, api, workerName);
35
27
  }
36
- const oldBindings = await ctx.get("bindings");
37
- const scriptMetadata = await prepareWorkerMetadata(ctx, oldBindings, props);
28
+ const oldBindings = await this.get("bindings");
29
+ const scriptMetadata = await prepareWorkerMetadata(this, oldBindings, props);
38
30
  // Get the script content - either from props.script, or by bundling
39
- const scriptContent = props.script ?? (await bundleWorkerScript(ctx, props));
31
+ const scriptContent = props.script ?? (await bundleWorkerScript(props));
40
32
  // Upload the worker script
41
- await putWorker(ctx, api, workerName, scriptContent, scriptMetadata);
33
+ await putWorker(api, workerName, scriptContent, scriptMetadata);
42
34
  // TODO: it is less than ideal that this can fail, resulting in state problem
43
- await ctx.set("bindings", props.bindings);
35
+ await this.set("bindings", props.bindings);
44
36
  // Handle routes if requested
45
37
  await setupRoutes(api, workerName, props.routes || []);
46
38
  // Handle worker URL if requested
47
- const workerUrl = await configureURL(ctx, api, workerName, props.url ?? false);
39
+ const workerUrl = await configureURL(this, api, workerName, props.url ?? false);
48
40
  // Get current timestamp
49
41
  const now = Date.now();
50
42
  // Construct the output
51
- const output = {
43
+ return this({
52
44
  type: "service",
53
- id: workerName,
45
+ id,
54
46
  name: workerName,
55
47
  script: scriptContent,
56
48
  format: props.format || "esm", // Include format in the output
@@ -61,9 +53,10 @@ async function applyWorker(ctx, props) {
61
53
  createdAt: now,
62
54
  updatedAt: now,
63
55
  url: workerUrl,
64
- };
65
- return output;
66
- }
56
+ // phantom property
57
+ Env: undefined,
58
+ });
59
+ });
67
60
  async function deleteWorker(ctx, api, workerName) {
68
61
  // Delete worker
69
62
  const deleteResponse = await api.delete(`/accounts/${api.accountId}/workers/scripts/${workerName}`);
@@ -107,7 +100,7 @@ async function deleteWorker(ctx, api, workerName) {
107
100
  // Return minimal output for deleted state
108
101
  return;
109
102
  }
110
- async function putWorker(ctx, api, workerName, scriptContent, scriptMetadata) {
103
+ async function putWorker(api, workerName, scriptContent, scriptMetadata) {
111
104
  return withExponentialBackoff(async () => {
112
105
  const scriptName = scriptMetadata.main_module ?? scriptMetadata.body_part;
113
106
  // Create FormData for the upload
@@ -118,7 +111,6 @@ async function putWorker(ctx, api, workerName, scriptContent, scriptMetadata) {
118
111
  ? "application/javascript+module"
119
112
  : "application/javascript",
120
113
  }), scriptName);
121
- // console.log("Script Metadata:", JSON.stringify(scriptMetadata, null, 2));
122
114
  // Add metadata as JSON
123
115
  formData.append("metadata", new Blob([JSON.stringify(scriptMetadata)], {
124
116
  type: "application/json",
@@ -158,7 +150,8 @@ async function prepareWorkerMetadata(ctx, oldBindings, props) {
158
150
  observability: {
159
151
  enabled: props.observability?.enabled !== false,
160
152
  },
161
- tags: [`alchemy:id:${ctx.resourceFQN}`],
153
+ // TODO(sam): base64 encode instead? 0 collision risk vs readability.
154
+ tags: [`alchemy:id:${slugify(ctx.fqn)}`],
162
155
  migrations: {
163
156
  new_classes: props.migrations?.new_classes ?? [],
164
157
  deleted_classes: props.migrations?.deleted_classes ?? [],
@@ -175,7 +168,7 @@ async function prepareWorkerMetadata(ctx, oldBindings, props) {
175
168
  meta.bindings.push({
176
169
  type: "kv_namespace",
177
170
  name: bindingName,
178
- namespace_id: binding.id,
171
+ namespace_id: binding.namespaceId,
179
172
  });
180
173
  }
181
174
  else if (typeof binding === "string") {
@@ -192,7 +185,7 @@ async function prepareWorkerMetadata(ctx, oldBindings, props) {
192
185
  service: binding.id,
193
186
  });
194
187
  }
195
- else if (isDurableObjectNamespace(binding)) {
188
+ else if (binding.type === "durable_object_namespace") {
196
189
  const stableId = binding.id;
197
190
  const className = binding.className;
198
191
  meta.bindings.push({
@@ -221,14 +214,14 @@ async function prepareWorkerMetadata(ctx, oldBindings, props) {
221
214
  });
222
215
  }
223
216
  }
224
- else if (isBucket(binding)) {
217
+ else if (binding.type === "r2_bucket") {
225
218
  meta.bindings.push({
226
219
  type: "r2_bucket",
227
220
  name: bindingName,
228
- bucket_name: binding.name || binding.id,
221
+ bucket_name: binding.name,
229
222
  });
230
223
  }
231
- else if (binding instanceof Secret) {
224
+ else if (isSecret(binding)) {
232
225
  meta.bindings.push({
233
226
  type: "secret_text",
234
227
  name: bindingName,
@@ -273,7 +266,7 @@ async function assertWorkerDoesNotExist(ctx, api, workerName) {
273
266
  if (!metadata) {
274
267
  throw new Error(`Worker exists but failed to fetch metadata: ${response.status} ${response.statusText}`);
275
268
  }
276
- if (metadata.default_environment?.script.tags.includes(`alchemy:id:${ctx.resourceFQN}`)) {
269
+ if (metadata.default_environment?.script.tags.includes(`alchemy:id:${slugify(ctx.fqn)}`)) {
277
270
  return true;
278
271
  }
279
272
  throw new Error(`Worker with name '${workerName}' already exists. Please use a unique name.`);
@@ -282,7 +275,7 @@ async function assertWorkerDoesNotExist(ctx, api, workerName) {
282
275
  throw new Error(`Error checking if worker exists: ${response.status} ${response.statusText}`);
283
276
  }
284
277
  }
285
- async function bundleWorkerScript(ctx, props) {
278
+ async function bundleWorkerScript(props) {
286
279
  // Get the script content - either from props.script, or by bundling
287
280
  // Create and use a Bundle resource with worker-optimized configuration
288
281
  const defaultBundleOptions = {
@@ -300,17 +293,13 @@ async function bundleWorkerScript(ctx, props) {
300
293
  ...(props.bundle || {}),
301
294
  };
302
295
  // Create the bundle
303
- const bundle = new Bundle("bundle", {
296
+ const bundle = await Bundle("bundle", {
304
297
  entryPoint: props.entrypoint,
305
298
  ...bundleOptions,
306
299
  external: [...(bundleOptions.external ?? []), "cloudflare:workers"],
307
300
  });
308
- // Get the bundled content
309
- const bundleOutput = await apply(bundle, {
310
- quiet: ctx.quiet,
311
- });
312
301
  try {
313
- return await fs.readFile(bundleOutput.path, "utf-8");
302
+ return await fs.readFile(bundle.path, "utf-8");
314
303
  }
315
304
  catch (error) {
316
305
  console.error("Error reading bundle:", error);
@@ -374,7 +363,7 @@ async function configureURL(ctx, api, workerName, url) {
374
363
  // Add a delay when the subdomain is first created.
375
364
  // This is to prevent an issue where a negative cache-hit
376
365
  // causes the subdomain to be unavailable for 30 seconds.
377
- if (ctx.event === "create" || !ctx.output?.url) {
366
+ if (ctx.phase === "create" || !ctx.output?.url) {
378
367
  await new Promise((resolve) => setTimeout(resolve, 3000));
379
368
  }
380
369
  }
@@ -416,4 +405,3 @@ async function getWorkerBindings(api, workerName, environment = "production") {
416
405
  const data = await response.json();
417
406
  return data.result;
418
407
  }
419
- //# sourceMappingURL=worker.js.map
@@ -0,0 +1,58 @@
1
+ import type { Resource, ResourceFQN, ResourceID, ResourceKind, ResourceProps } from "./resource";
2
+ import type { Scope } from "./scope";
3
+ import type { State } from "./state";
4
+ export type Context<Out extends Resource> = CreateContext<Out> | UpdateContext<Out> | DeleteContext<Out>;
5
+ export interface CreateContext<Out extends Resource> extends BaseContext<Out> {
6
+ phase: "create";
7
+ output?: undefined;
8
+ }
9
+ export interface UpdateContext<Out extends Resource> extends BaseContext<Out> {
10
+ phase: "update";
11
+ output: Out;
12
+ }
13
+ export interface DeleteContext<Out extends Resource> extends BaseContext<Out> {
14
+ phase: "delete";
15
+ output: Out;
16
+ }
17
+ export interface BaseContext<Out extends Resource> {
18
+ quiet: boolean;
19
+ stage: string;
20
+ id: ResourceID;
21
+ fqn: ResourceFQN;
22
+ scope: Scope;
23
+ get<T>(key: string): Promise<T | undefined>;
24
+ set<T>(key: string, value: T): Promise<void>;
25
+ delete<T>(key: string): Promise<T | undefined>;
26
+ /**
27
+ * Indicate that this resource is being replaced.
28
+ * This will cause the resource to be deleted at the end of the stack's CREATE phase.
29
+ */
30
+ replace(): void;
31
+ /**
32
+ * Terminate the resource lifecycle handler and destroy the resource.
33
+ *
34
+ * This is the final operation performed during a delete operation.
35
+ *
36
+ * It is so that the resource lifecycle handler can "return never" instead of
37
+ * "return undefined" so that `await MyResource()` always returns a value.
38
+ */
39
+ destroy(): never;
40
+ /**
41
+ * Create the Resource envelope (with Alchemy + User properties)
42
+ */
43
+ create(props: Omit<Out, keyof Resource>): Out;
44
+ /**
45
+ * Create the Resource envelope (with Alchemy + User properties)
46
+ */
47
+ (props: Omit<Out, keyof Resource>): Out;
48
+ }
49
+ export declare function context<Kind extends string, Props extends ResourceProps, Out extends Resource>({ scope, phase, kind, id, fqn, seq, state, replace, }: {
50
+ scope: Scope;
51
+ phase: "create" | "update" | "delete";
52
+ kind: ResourceKind;
53
+ id: ResourceID;
54
+ fqn: ResourceFQN;
55
+ seq: number;
56
+ state: State<Kind, Props, Out>;
57
+ replace: () => void;
58
+ }): Context<Out>;