alchemy 0.1.16 → 0.1.17

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 (220) hide show
  1. package/lib/$.d.ts +12 -0
  2. package/lib/$.d.ts.map +1 -0
  3. package/lib/$.js +42 -0
  4. package/lib/$.js.map +1 -0
  5. package/lib/alchemize.d.ts +43 -0
  6. package/lib/alchemize.d.ts.map +1 -0
  7. package/lib/alchemize.js +112 -0
  8. package/lib/alchemize.js.map +1 -0
  9. package/lib/apply.d.ts +23 -0
  10. package/lib/aws/account-id.d.ts +5 -0
  11. package/lib/aws/account-id.d.ts.map +1 -0
  12. package/lib/aws/account-id.js +10 -0
  13. package/lib/aws/account-id.js.map +1 -0
  14. package/lib/aws/bucket.d.ts +21 -0
  15. package/lib/aws/bucket.d.ts.map +1 -0
  16. package/lib/aws/bucket.js +114 -0
  17. package/lib/aws/bucket.js.map +1 -0
  18. package/lib/aws/function.d.ts +53 -0
  19. package/lib/aws/function.d.ts.map +1 -0
  20. package/lib/aws/function.js +195 -0
  21. package/lib/aws/function.js.map +1 -0
  22. package/lib/aws/index.d.ts +9 -0
  23. package/lib/aws/index.d.ts.map +1 -0
  24. package/lib/aws/index.js +9 -0
  25. package/lib/aws/index.js.map +1 -0
  26. package/lib/aws/oidc/github-oidc-provider.d.ts +11 -0
  27. package/lib/aws/oidc/github-oidc-provider.d.ts.map +1 -0
  28. package/lib/aws/oidc/github-oidc-provider.js +22 -0
  29. package/lib/aws/oidc/github-oidc-provider.js.map +1 -0
  30. package/lib/aws/oidc/index.d.ts +3 -0
  31. package/lib/aws/oidc/index.d.ts.map +1 -0
  32. package/lib/aws/oidc/index.js +3 -0
  33. package/lib/aws/oidc/index.js.map +1 -0
  34. package/lib/aws/oidc/oidc-provider.d.ts +60 -0
  35. package/lib/aws/oidc/oidc-provider.d.ts.map +1 -0
  36. package/lib/aws/oidc/oidc-provider.js +140 -0
  37. package/lib/aws/oidc/oidc-provider.js.map +1 -0
  38. package/lib/aws/policy.d.ts +46 -0
  39. package/lib/aws/policy.d.ts.map +1 -0
  40. package/lib/aws/policy.js +139 -0
  41. package/lib/aws/policy.js.map +1 -0
  42. package/lib/aws/queue.d.ts +62 -0
  43. package/lib/aws/queue.d.ts.map +1 -0
  44. package/lib/aws/queue.js +167 -0
  45. package/lib/aws/queue.js.map +1 -0
  46. package/lib/aws/role.d.ts +27 -0
  47. package/lib/aws/role.d.ts.map +1 -0
  48. package/lib/aws/role.js +197 -0
  49. package/lib/aws/role.js.map +1 -0
  50. package/lib/aws/ses.d.ts +75 -0
  51. package/lib/aws/ses.d.ts.map +1 -0
  52. package/lib/aws/ses.js +189 -0
  53. package/lib/aws/ses.js.map +1 -0
  54. package/lib/aws/table.d.ts +26 -0
  55. package/lib/aws/table.d.ts.map +1 -0
  56. package/lib/aws/table.js +154 -0
  57. package/lib/aws/table.js.map +1 -0
  58. package/lib/cloudflare/api.d.ts +88 -0
  59. package/lib/cloudflare/api.d.ts.map +1 -0
  60. package/lib/cloudflare/api.js +184 -0
  61. package/lib/cloudflare/api.js.map +1 -0
  62. package/lib/cloudflare/asset-manifest.d.ts +15 -0
  63. package/lib/cloudflare/asset-manifest.d.ts.map +1 -0
  64. package/lib/cloudflare/asset-manifest.js +2 -0
  65. package/lib/cloudflare/asset-manifest.js.map +1 -0
  66. package/lib/cloudflare/auth.d.ts +52 -0
  67. package/lib/cloudflare/auth.d.ts.map +1 -0
  68. package/lib/cloudflare/auth.js +114 -0
  69. package/lib/cloudflare/auth.js.map +1 -0
  70. package/lib/cloudflare/bindings.d.ts +260 -0
  71. package/lib/cloudflare/bindings.d.ts.map +1 -0
  72. package/lib/cloudflare/bindings.js +2 -0
  73. package/lib/cloudflare/bindings.js.map +1 -0
  74. package/lib/cloudflare/bucket.d.ts +54 -0
  75. package/lib/cloudflare/bucket.d.ts.map +1 -0
  76. package/lib/cloudflare/bucket.js +120 -0
  77. package/lib/cloudflare/bucket.js.map +1 -0
  78. package/lib/cloudflare/durable-object-namespace.d.ts +20 -0
  79. package/lib/cloudflare/durable-object-namespace.d.ts.map +1 -0
  80. package/lib/cloudflare/durable-object-namespace.js +21 -0
  81. package/lib/cloudflare/durable-object-namespace.js.map +1 -0
  82. package/lib/cloudflare/generate-asset-manifest.d.ts +3 -0
  83. package/lib/cloudflare/generate-asset-manifest.d.ts.map +1 -0
  84. package/lib/cloudflare/generate-asset-manifest.js +69 -0
  85. package/lib/cloudflare/generate-asset-manifest.js.map +1 -0
  86. package/lib/cloudflare/index.d.ts +8 -0
  87. package/lib/cloudflare/index.d.ts.map +1 -0
  88. package/lib/cloudflare/index.js +8 -0
  89. package/lib/cloudflare/index.js.map +1 -0
  90. package/lib/cloudflare/kv-namespace.d.ts +64 -0
  91. package/lib/cloudflare/kv-namespace.d.ts.map +1 -0
  92. package/lib/cloudflare/kv-namespace.js +114 -0
  93. package/lib/cloudflare/kv-namespace.js.map +1 -0
  94. package/lib/cloudflare/state.d.ts +83 -0
  95. package/lib/cloudflare/state.d.ts.map +1 -0
  96. package/lib/cloudflare/state.js +109 -0
  97. package/lib/cloudflare/state.js.map +1 -0
  98. package/lib/cloudflare/static-site-router.d.ts +19 -0
  99. package/lib/cloudflare/static-site-router.d.ts.map +1 -0
  100. package/lib/cloudflare/static-site-router.js +110 -0
  101. package/lib/cloudflare/static-site-router.js.map +1 -0
  102. package/lib/cloudflare/static-site.d.ts +166 -0
  103. package/lib/cloudflare/static-site.d.ts.map +1 -0
  104. package/lib/cloudflare/static-site.js +161 -0
  105. package/lib/cloudflare/static-site.js.map +1 -0
  106. package/lib/cloudflare/types.d.ts +52 -0
  107. package/lib/cloudflare/types.d.ts.map +1 -0
  108. package/lib/cloudflare/types.js +21 -0
  109. package/lib/cloudflare/types.js.map +1 -0
  110. package/lib/cloudflare/upload-asset-manifest.d.ts +12 -0
  111. package/lib/cloudflare/upload-asset-manifest.d.ts.map +1 -0
  112. package/lib/cloudflare/upload-asset-manifest.js +55 -0
  113. package/lib/cloudflare/upload-asset-manifest.js.map +1 -0
  114. package/lib/cloudflare/worker-metadata.d.ts +130 -0
  115. package/lib/cloudflare/worker-metadata.d.ts.map +1 -0
  116. package/lib/cloudflare/worker-metadata.js +2 -0
  117. package/lib/cloudflare/worker-metadata.js.map +1 -0
  118. package/lib/cloudflare/worker-migration.d.ts +110 -0
  119. package/lib/cloudflare/worker-migration.d.ts.map +1 -0
  120. package/lib/cloudflare/worker-migration.js +11 -0
  121. package/lib/cloudflare/worker-migration.js.map +1 -0
  122. package/lib/cloudflare/worker.d.ts +108 -0
  123. package/lib/cloudflare/worker.d.ts.map +1 -0
  124. package/lib/cloudflare/worker.js +407 -0
  125. package/lib/cloudflare/worker.js.map +1 -0
  126. package/lib/destroy.d.ts +19 -0
  127. package/lib/error.d.ts +2 -0
  128. package/lib/error.d.ts.map +1 -0
  129. package/lib/error.js +13 -0
  130. package/lib/error.js.map +1 -0
  131. package/lib/esbuild.d.ts +152 -0
  132. package/lib/esbuild.d.ts.map +1 -0
  133. package/lib/esbuild.js +67 -0
  134. package/lib/esbuild.js.map +1 -0
  135. package/lib/fs.d.ts +12 -0
  136. package/lib/fs.d.ts.map +1 -0
  137. package/lib/fs.js +41 -0
  138. package/lib/fs.js.map +1 -0
  139. package/lib/github/client.d.ts +34 -0
  140. package/lib/github/client.d.ts.map +1 -0
  141. package/lib/github/client.js +91 -0
  142. package/lib/github/client.js.map +1 -0
  143. package/lib/github/index.d.ts +2 -0
  144. package/lib/github/index.d.ts.map +1 -0
  145. package/lib/github/index.js +2 -0
  146. package/lib/github/index.js.map +1 -0
  147. package/lib/github/secret.d.ts +46 -0
  148. package/lib/github/secret.d.ts.map +1 -0
  149. package/lib/github/secret.js +103 -0
  150. package/lib/github/secret.js.map +1 -0
  151. package/lib/global.d.ts +16 -0
  152. package/lib/global.d.ts.map +1 -0
  153. package/lib/global.js +42 -0
  154. package/lib/global.js.map +1 -0
  155. package/lib/index.d.ts +10 -0
  156. package/lib/index.d.ts.map +1 -0
  157. package/lib/index.js +9 -0
  158. package/lib/index.js.map +1 -0
  159. package/lib/input.d.ts +6 -0
  160. package/lib/input.d.ts.map +1 -0
  161. package/lib/input.js +2 -0
  162. package/lib/input.js.map +1 -0
  163. package/lib/main.d.ts +3 -0
  164. package/lib/main.d.ts.map +1 -0
  165. package/lib/main.js +32 -0
  166. package/lib/main.js.map +1 -0
  167. package/lib/output.d.ts +24 -0
  168. package/lib/output.d.ts.map +1 -0
  169. package/lib/output.js +23 -0
  170. package/lib/output.js.map +1 -0
  171. package/lib/print.d.ts +7 -0
  172. package/lib/print.d.ts.map +1 -0
  173. package/lib/print.js +10 -0
  174. package/lib/print.js.map +1 -0
  175. package/lib/resource.d.ts +71 -0
  176. package/lib/resource.d.ts.map +1 -0
  177. package/lib/resource.js +276 -0
  178. package/lib/resource.js.map +1 -0
  179. package/lib/scope.d.ts +18 -0
  180. package/lib/scope.d.ts.map +1 -0
  181. package/lib/scope.js +30 -0
  182. package/lib/scope.js.map +1 -0
  183. package/lib/slug.d.ts +2 -0
  184. package/lib/slug.d.ts.map +1 -0
  185. package/lib/slug.js +4 -0
  186. package/lib/slug.js.map +1 -0
  187. package/lib/state.d.ts +40 -0
  188. package/lib/state.d.ts.map +1 -0
  189. package/lib/state.js +73 -0
  190. package/lib/state.js.map +1 -0
  191. package/lib/stripe/index.d.ts +4 -0
  192. package/lib/stripe/index.d.ts.map +1 -0
  193. package/lib/stripe/index.js +4 -0
  194. package/lib/stripe/index.js.map +1 -0
  195. package/lib/stripe/price.d.ts +109 -0
  196. package/lib/stripe/price.d.ts.map +1 -0
  197. package/lib/stripe/price.js +112 -0
  198. package/lib/stripe/price.js.map +1 -0
  199. package/lib/stripe/product.d.ts +86 -0
  200. package/lib/stripe/product.d.ts.map +1 -0
  201. package/lib/stripe/product.js +90 -0
  202. package/lib/stripe/product.js.map +1 -0
  203. package/lib/stripe/webhook.d.ts +73 -0
  204. package/lib/stripe/webhook.d.ts.map +1 -0
  205. package/lib/stripe/webhook.js +94 -0
  206. package/lib/stripe/webhook.js.map +1 -0
  207. package/lib/utils/content-type.d.ts +8 -0
  208. package/lib/utils/content-type.d.ts.map +1 -0
  209. package/lib/utils/content-type.js +41 -0
  210. package/lib/utils/content-type.js.map +1 -0
  211. package/lib/utils/retry.d.ts +13 -0
  212. package/lib/utils/retry.d.ts.map +1 -0
  213. package/lib/utils/retry.js +32 -0
  214. package/lib/utils/retry.js.map +1 -0
  215. package/package.json +1 -1
  216. package/src/cloudflare/bindings.ts +7 -1
  217. package/src/cloudflare/bucket.ts +240 -0
  218. package/src/cloudflare/index.ts +1 -0
  219. package/src/cloudflare/static-site.ts +13 -1
  220. package/src/cloudflare/worker.ts +7 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-type.js","sourceRoot":"","sources":["../../src/utils/content-type.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,oBAAoB;AACpB,MAAM,SAAS,GAA2B;IACxC,OAAO,EAAE,WAAW;IACpB,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,UAAU;IAClB,KAAK,EAAE,wBAAwB;IAC/B,OAAO,EAAE,kBAAkB;IAC3B,MAAM,EAAE,iBAAiB;IACzB,MAAM,EAAE,YAAY;IACpB,KAAK,EAAE,eAAe;IACtB,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,YAAY;IACpB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,WAAW;IACnB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,eAAe;IACvB,MAAM,EAAE,cAAc;IACtB,MAAM,EAAE,iBAAiB;IACzB,MAAM,EAAE,iBAAiB;IACzB,OAAO,EAAE,WAAW;IACpB,QAAQ,EAAE,YAAY;IACtB,MAAM,EAAE,UAAU;IAClB,MAAM,EAAE,UAAU;IAClB,MAAM,EAAE,+BAA+B;IACvC,MAAM,EAAE,WAAW;IACnB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,YAAY;IACpB,MAAM,EAAE,WAAW;CACpB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;IACvD,OAAO,SAAS,CAAC,SAAS,CAAC,IAAI,0BAA0B,CAAC;AAC5D,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Utility function for exponential backoff retry
3
+ * Retries an operation with exponential backoff when a retryable error occurs
4
+ *
5
+ * @param operation The async operation to execute and potentially retry
6
+ * @param isRetryable Function to determine if an error should trigger a retry
7
+ * @param maxAttempts Maximum number of attempts before giving up
8
+ * @param initialDelayMs Initial delay in milliseconds before first retry
9
+ * @returns Result of the operation
10
+ * @throws The last error encountered if all retries fail
11
+ */
12
+ export declare function withExponentialBackoff<T>(operation: () => Promise<T>, isRetryable: (error: any) => boolean, maxAttempts?: number, initialDelayMs?: number): Promise<T>;
13
+ //# sourceMappingURL=retry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../src/utils/retry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,wBAAsB,sBAAsB,CAAC,CAAC,EAC5C,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAC3B,WAAW,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,EACpC,WAAW,SAAI,EACf,cAAc,SAAM,GACnB,OAAO,CAAC,CAAC,CAAC,CAoBZ"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Utility function for exponential backoff retry
3
+ * Retries an operation with exponential backoff when a retryable error occurs
4
+ *
5
+ * @param operation The async operation to execute and potentially retry
6
+ * @param isRetryable Function to determine if an error should trigger a retry
7
+ * @param maxAttempts Maximum number of attempts before giving up
8
+ * @param initialDelayMs Initial delay in milliseconds before first retry
9
+ * @returns Result of the operation
10
+ * @throws The last error encountered if all retries fail
11
+ */
12
+ export async function withExponentialBackoff(operation, isRetryable, maxAttempts = 5, initialDelayMs = 100) {
13
+ let attempt = 0;
14
+ let delay = initialDelayMs;
15
+ while (true) {
16
+ try {
17
+ return await operation();
18
+ }
19
+ catch (error) {
20
+ attempt++;
21
+ if (attempt >= maxAttempts || !isRetryable(error)) {
22
+ console.warn("Failed after ", attempt, " attempts");
23
+ throw error;
24
+ }
25
+ // Exponential backoff with jitter
26
+ const jitter = Math.random() * 0.1 * delay;
27
+ await new Promise((resolve) => setTimeout(resolve, delay + jitter));
28
+ delay *= 2; // Double the delay for next attempt
29
+ }
30
+ }
31
+ }
32
+ //# sourceMappingURL=retry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.js","sourceRoot":"","sources":["../../src/utils/retry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,SAA2B,EAC3B,WAAoC,EACpC,WAAW,GAAG,CAAC,EACf,cAAc,GAAG,GAAG;IAEpB,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,IAAI,KAAK,GAAG,cAAc,CAAC;IAE3B,OAAO,IAAI,EAAE,CAAC;QACZ,IAAI,CAAC;YACH,OAAO,MAAM,SAAS,EAAE,CAAC;QAC3B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,EAAE,CAAC;YACV,IAAI,OAAO,IAAI,WAAW,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;gBAClD,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;gBACpD,MAAM,KAAK,CAAC;YACd,CAAC;YAED,kCAAkC;YAClC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,GAAG,KAAK,CAAC;YAC3C,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC;YACpE,KAAK,IAAI,CAAC,CAAC,CAAC,oCAAoC;QAClD,CAAC;IACH,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alchemy",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "type": "module",
5
5
  "module": "./lib/index.js",
6
6
  "scripts": {
@@ -3,6 +3,7 @@
3
3
  * Based on Cloudflare API documentation:
4
4
  * https://developers.cloudflare.com/api/resources/workers/subresources/scripts/methods/update/
5
5
  */
6
+ import type { Bucket } from "./bucket";
6
7
  import type { DurableObjectNamespace } from "./durable-object-namespace";
7
8
  import type { KVNamespace } from "./kv-namespace";
8
9
  import type { Worker } from "./worker";
@@ -14,7 +15,12 @@ export type Bindings = {
14
15
  /**
15
16
  * L2 Binding Resources.
16
17
  */
17
- export type Binding = DurableObjectNamespace | KVNamespace | Worker | string;
18
+ export type Binding =
19
+ | DurableObjectNamespace
20
+ | KVNamespace
21
+ | Worker
22
+ | Bucket
23
+ | string;
18
24
 
19
25
  /**
20
26
  * Union type for all Worker binding types (API spec)
@@ -0,0 +1,240 @@
1
+ import type { Resolved } from "../output";
2
+ import { type Context, Resource } from "../resource";
3
+ import { createCloudflareApi } from "./api";
4
+
5
+ /**
6
+ * Properties for creating or updating an R2 Bucket
7
+ */
8
+ export interface BucketProps {
9
+ /**
10
+ * Name of the bucket
11
+ * Names can only contain lowercase letters (a-z), numbers (0-9), and hyphens (-)
12
+ * Cannot begin or end with a hyphen
13
+ */
14
+ name?: string;
15
+
16
+ /**
17
+ * Optional location hint for the bucket
18
+ * Indicates the primary geographical location data will be accessed from
19
+ */
20
+ locationHint?: string;
21
+
22
+ /**
23
+ * Optional jurisdiction for the bucket
24
+ * Determines the regulatory jurisdiction the bucket data falls under
25
+ */
26
+ jurisdiction?: "default" | "eu" | "fedramp";
27
+
28
+ /**
29
+ * Whether to allow public access through the r2.dev subdomain
30
+ * Only for development purposes - use custom domains for production
31
+ */
32
+ allowPublicAccess?: boolean;
33
+ }
34
+
35
+ /**
36
+ * Output returned after R2 Bucket creation/update
37
+ */
38
+ export interface BucketOutput extends BucketProps {
39
+ /**
40
+ * The ID of the bucket (same as name)
41
+ */
42
+ id: string;
43
+
44
+ /**
45
+ * Location of the bucket
46
+ */
47
+ location: string;
48
+
49
+ /**
50
+ * Time at which the bucket was created (Unix timestamp in seconds)
51
+ */
52
+ creationDate: number;
53
+
54
+ /**
55
+ * Resource type identifier
56
+ */
57
+ type: "r2_bucket";
58
+ }
59
+
60
+ /**
61
+ * Cloudflare R2 bucket API response
62
+ */
63
+ interface CloudflareBucketResponse {
64
+ result: {
65
+ name: string;
66
+ location?: string;
67
+ creation_date: string;
68
+ };
69
+ success: boolean;
70
+ errors: Array<{ code: number; message: string }>;
71
+ messages: string[];
72
+ }
73
+
74
+ export function isBucket(resource: any): resource is Resolved<Bucket> {
75
+ return (
76
+ resource && typeof resource === "object" && resource.id && resource.location
77
+ );
78
+ }
79
+
80
+ export class Bucket extends Resource(
81
+ "cloudflare::Bucket",
82
+ async (ctx: Context<BucketOutput>, props: BucketProps) => {
83
+ // Create Cloudflare API client with automatic account discovery
84
+ const api = await createCloudflareApi();
85
+
86
+ // Resource ID defaults to bucket name if provided
87
+ const bucketName = props.name || ctx.resourceID;
88
+
89
+ if (ctx.event === "delete") {
90
+ if (ctx.output?.id) {
91
+ // Delete R2 bucket
92
+ const headers: Record<string, string> = {};
93
+ if (props.jurisdiction && props.jurisdiction !== "default") {
94
+ headers["cf-r2-jurisdiction"] = props.jurisdiction;
95
+ }
96
+
97
+ const deleteResponse = await api.delete(
98
+ `/accounts/${api.accountId}/r2/buckets/${ctx.output.id}`,
99
+ { headers },
100
+ );
101
+
102
+ if (!deleteResponse.ok && deleteResponse.status !== 404) {
103
+ const errorData: any = await deleteResponse.json().catch(() => ({
104
+ errors: [{ message: deleteResponse.statusText }],
105
+ }));
106
+ throw new Error(
107
+ `Error deleting R2 bucket '${bucketName}': ${errorData.errors?.[0]?.message || deleteResponse.statusText}`,
108
+ );
109
+ }
110
+ }
111
+
112
+ // Return void (a deleted bucket has no content)
113
+ return;
114
+ } else {
115
+ try {
116
+ let bucketOutput: BucketOutput;
117
+
118
+ if (ctx.event === "update" && ctx.output?.id) {
119
+ // Get bucket details to verify it exists
120
+ const headers: Record<string, string> = {};
121
+ if (props.jurisdiction && props.jurisdiction !== "default") {
122
+ headers["cf-r2-jurisdiction"] = props.jurisdiction;
123
+ }
124
+
125
+ const getResponse = await api.get(
126
+ `/accounts/${api.accountId}/r2/buckets/${bucketName}`,
127
+ { headers },
128
+ );
129
+
130
+ if (!getResponse.ok) {
131
+ const errorData: any = await getResponse.json().catch(() => ({
132
+ errors: [{ message: getResponse.statusText }],
133
+ }));
134
+ throw new Error(
135
+ `Error getting R2 bucket '${bucketName}': ${errorData.errors?.[0]?.message || getResponse.statusText}`,
136
+ );
137
+ }
138
+
139
+ const result = (await getResponse.json()) as CloudflareBucketResponse;
140
+ bucketOutput = {
141
+ id: result.result.name,
142
+ name: result.result.name,
143
+ location: result.result.location || "default",
144
+ creationDate: Math.floor(
145
+ new Date(result.result.creation_date).getTime() / 1000,
146
+ ),
147
+ jurisdiction: props.jurisdiction || "default",
148
+ type: "r2_bucket",
149
+ };
150
+
151
+ // Update public access setting if it has changed
152
+ if (props.allowPublicAccess !== undefined) {
153
+ await updatePublicAccess(api, bucketName, props.allowPublicAccess);
154
+ }
155
+ } else {
156
+ // Create new R2 bucket
157
+ const createPayload: any = {
158
+ name: bucketName,
159
+ };
160
+
161
+ if (props.locationHint) {
162
+ createPayload.location_hint = props.locationHint;
163
+ }
164
+
165
+ const headers: Record<string, string> = {};
166
+ if (props.jurisdiction && props.jurisdiction !== "default") {
167
+ headers["cf-r2-jurisdiction"] = props.jurisdiction;
168
+ }
169
+
170
+ const createResponse = await api.post(
171
+ `/accounts/${api.accountId}/r2/buckets`,
172
+ createPayload,
173
+ { headers },
174
+ );
175
+
176
+ if (!createResponse.ok) {
177
+ const errorData: any = await createResponse.json().catch(() => ({
178
+ errors: [{ message: createResponse.statusText }],
179
+ }));
180
+ throw new Error(
181
+ `Error creating R2 bucket '${bucketName}': ${errorData.errors?.[0]?.message || createResponse.statusText}`,
182
+ );
183
+ }
184
+
185
+ const result =
186
+ (await createResponse.json()) as CloudflareBucketResponse;
187
+ bucketOutput = {
188
+ id: result.result.name,
189
+ name: result.result.name,
190
+ location: result.result.location || "default",
191
+ creationDate: Math.floor(
192
+ new Date(result.result.creation_date).getTime() / 1000,
193
+ ),
194
+ jurisdiction: props.jurisdiction || "default",
195
+ type: "r2_bucket",
196
+ };
197
+
198
+ // Set public access if requested
199
+ if (props.allowPublicAccess) {
200
+ await updatePublicAccess(api, bucketName, true);
201
+ }
202
+ }
203
+
204
+ return bucketOutput;
205
+ } catch (error) {
206
+ console.error("Error creating/updating R2 bucket:", error);
207
+ throw error;
208
+ }
209
+ }
210
+ },
211
+ ) {}
212
+
213
+ /**
214
+ * Helper function to update the public access setting for a bucket
215
+ */
216
+ async function updatePublicAccess(
217
+ api: any,
218
+ bucketName: string,
219
+ allowPublicAccess: boolean,
220
+ ): Promise<void> {
221
+ try {
222
+ const response = await api.put(
223
+ `/accounts/${api.accountId}/r2/buckets/${bucketName}/domains/managed`,
224
+ {
225
+ enabled: allowPublicAccess,
226
+ },
227
+ );
228
+
229
+ if (!response.ok) {
230
+ const errorData: any = await response.json().catch(() => ({
231
+ errors: [{ message: response.statusText }],
232
+ }));
233
+ throw new Error(
234
+ `Error updating R2 bucket public access: ${errorData.errors?.[0]?.message || response.statusText}`,
235
+ );
236
+ }
237
+ } catch (error) {
238
+ console.warn("Could not set public access:", error);
239
+ }
240
+ }
@@ -1,4 +1,5 @@
1
1
  export * from "./bindings";
2
+ export * from "./bucket";
2
3
  export * from "./durable-object-namespace";
3
4
  export * from "./kv-namespace";
4
5
  export * from "./state";
@@ -323,6 +323,18 @@ export class StaticSite extends Resource(
323
323
  },
324
324
  },
325
325
  };
326
+
327
+ // Determine the entrypoint file - check for .ts first, fallback to .js
328
+ let entrypointFile = "static-site-router.js";
329
+ try {
330
+ const tsFile = path.resolve(__dirname, "static-site-router.ts");
331
+ await fs.access(tsFile);
332
+ // If we reach here, the TypeScript file exists
333
+ entrypointFile = "static-site-router.ts";
334
+ } catch (error) {
335
+ // TypeScript file doesn't exist, use JavaScript (default)
336
+ }
337
+
326
338
  const worker = new Worker(
327
339
  "worker",
328
340
  {
@@ -333,7 +345,7 @@ export class StaticSite extends Resource(
333
345
  ...(props.workerScript
334
346
  ? { script: props.workerScript }
335
347
  : {
336
- entrypoint: path.resolve(__dirname, "static-site-router.ts"),
348
+ entrypoint: path.resolve(__dirname, entrypointFile),
337
349
  bundle: bundleOptions,
338
350
  }),
339
351
  bindings,
@@ -6,6 +6,7 @@ import { type Context, Resource } from "../resource";
6
6
  import { withExponentialBackoff } from "../utils/retry";
7
7
  import { type CloudflareApi, createCloudflareApi } from "./api";
8
8
  import type { Bindings, WorkerBindingSpec } from "./bindings";
9
+ import { isBucket } from "./bucket";
9
10
  import type { DurableObjectNamespace } from "./durable-object-namespace";
10
11
  import { isDurableObjectNamespace } from "./durable-object-namespace";
11
12
  import { isKVNamespace } from "./kv-namespace";
@@ -438,6 +439,12 @@ async function prepareWorkerMetadata(
438
439
  to: className,
439
440
  });
440
441
  }
442
+ } else if (isBucket(binding)) {
443
+ meta.bindings.push({
444
+ type: "r2_bucket",
445
+ name: bindingName,
446
+ bucket_name: binding.name || binding.id,
447
+ });
441
448
  } else {
442
449
  // @ts-expect-error - we should never reach here
443
450
  throw new Error(`Unsupported binding type: ${binding.type}`);