alchemy 0.5.2 → 0.7.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 (54) hide show
  1. package/lib/cloudflare/account-api-token.d.ts +6 -1
  2. package/lib/cloudflare/account-api-token.js +5 -1
  3. package/lib/cloudflare/account-id.d.ts +5 -1
  4. package/lib/cloudflare/account-id.js +5 -0
  5. package/lib/cloudflare/api-error.d.ts +32 -0
  6. package/lib/cloudflare/api-error.js +47 -0
  7. package/lib/cloudflare/api.d.ts +16 -49
  8. package/lib/cloudflare/api.js +37 -149
  9. package/lib/cloudflare/auth.d.ts +55 -38
  10. package/lib/cloudflare/auth.js +148 -77
  11. package/lib/cloudflare/bindings.d.ts +19 -7
  12. package/lib/cloudflare/bindings.js +0 -9
  13. package/lib/cloudflare/bound.d.ts +2 -1
  14. package/lib/cloudflare/bucket.d.ts +30 -5
  15. package/lib/cloudflare/bucket.js +12 -11
  16. package/lib/cloudflare/custom-domain.d.ts +2 -1
  17. package/lib/cloudflare/custom-domain.js +3 -2
  18. package/lib/cloudflare/dns-records.d.ts +2 -1
  19. package/lib/cloudflare/dns-records.js +2 -2
  20. package/lib/cloudflare/index.d.ts +1 -0
  21. package/lib/cloudflare/index.js +1 -0
  22. package/lib/cloudflare/kv-namespace.d.ts +7 -1
  23. package/lib/cloudflare/kv-namespace.js +72 -71
  24. package/lib/cloudflare/permission-groups.d.ts +4 -0
  25. package/lib/cloudflare/permission-groups.js +5 -1
  26. package/lib/cloudflare/r2-rest-state-store.d.ts +3 -17
  27. package/lib/cloudflare/r2-rest-state-store.js +4 -12
  28. package/lib/cloudflare/worker.d.ts +2 -6
  29. package/lib/cloudflare/worker.js +58 -90
  30. package/lib/cloudflare/workflow.d.ts +46 -0
  31. package/lib/cloudflare/workflow.js +29 -0
  32. package/lib/cloudflare/zone.d.ts +2 -6
  33. package/lib/cloudflare/zone.js +1 -3
  34. package/lib/internal/docs/providers.js +1 -8
  35. package/package.json +5 -1
  36. package/src/cloudflare/account-api-token.ts +7 -3
  37. package/src/cloudflare/account-id.ts +12 -0
  38. package/src/cloudflare/api-error.ts +58 -0
  39. package/src/cloudflare/api.ts +50 -216
  40. package/src/cloudflare/auth.ts +262 -119
  41. package/src/cloudflare/bindings.ts +21 -16
  42. package/src/cloudflare/bound.ts +4 -1
  43. package/src/cloudflare/bucket.ts +52 -29
  44. package/src/cloudflare/custom-domain.ts +8 -3
  45. package/src/cloudflare/dns-records.ts +7 -3
  46. package/src/cloudflare/durable-object-namespace.ts +1 -1
  47. package/src/cloudflare/index.ts +1 -0
  48. package/src/cloudflare/kv-namespace.ts +117 -105
  49. package/src/cloudflare/permission-groups.ts +5 -1
  50. package/src/cloudflare/r2-rest-state-store.ts +8 -31
  51. package/src/cloudflare/worker.ts +71 -141
  52. package/src/cloudflare/workflow.ts +79 -0
  53. package/src/cloudflare/zone.ts +17 -25
  54. package/src/internal/docs/providers.ts +1 -8
@@ -1,79 +1,68 @@
1
- /**
2
- * Get authentication headers for Cloudflare API
3
- *
4
- * Priority:
5
- * 1. API Token (CLOUDFLARE_API_TOKEN) - Recommended by Cloudflare
6
- * 2. API Key (CLOUDFLARE_API_KEY) - Will attempt to discover email automatically
7
- *
8
- * @param options Authentication options
9
- * @returns Authentication headers
10
- */
11
- export async function getCloudflareAuth(options = {}) {
12
- const { required = true } = options;
1
+ import fs from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { handleApiError } from "./api-error";
5
+ const userInfoCache = {};
6
+ export async function getCloudflareUserInfo(options) {
7
+ const cacheKey = JSON.stringify({
8
+ apiKey: options.apiKey?.unencrypted,
9
+ apiToken: options.apiToken?.unencrypted,
10
+ email: options.email,
11
+ });
12
+ if (userInfoCache[cacheKey]) {
13
+ return userInfoCache[cacheKey];
14
+ }
15
+ const headers = await getCloudflareAuthHeaders(options);
16
+ const user = await fetch("https://api.cloudflare.com/client/v4/user", {
17
+ headers,
18
+ });
19
+ if (!user.ok) {
20
+ if (user.status === 403) {
21
+ throw new Error("Cloudflare authentication required. Did you forget to login with `wrangler login` or set CLOUDFLARE_API_TOKEN, CLOUDFLARE_API_KEY, or CLOUDFLARE_EMAIL, or CLOUDFLARE_API_KEY?");
22
+ }
23
+ await handleApiError(user, "getting", "user", "user");
24
+ }
25
+ const accounts = await fetch("https://api.cloudflare.com/client/v4/accounts", {
26
+ headers,
27
+ });
28
+ const userInfo = {
29
+ ...(await user.json()).result,
30
+ accounts: (await accounts.json()).result,
31
+ };
32
+ userInfoCache[cacheKey] = userInfo;
33
+ return userInfo;
34
+ }
35
+ export async function getCloudflareAuthHeaders(options = {}) {
13
36
  // Check for API Token (preferred method)
14
- const apiToken = process.env.CLOUDFLARE_API_TOKEN;
37
+ const apiToken = options.apiToken?.unencrypted ?? process.env.CLOUDFLARE_API_TOKEN;
15
38
  if (apiToken) {
16
39
  return {
17
- headers: {
18
- Authorization: `Bearer ${apiToken}`,
19
- },
20
- type: "token",
40
+ Authorization: `Bearer ${apiToken}`,
21
41
  };
22
42
  }
23
43
  // Check for API Key
24
- const apiKey = process.env.CLOUDFLARE_API_KEY;
44
+ const apiKey = options.apiKey?.unencrypted ?? process.env.CLOUDFLARE_API_KEY;
25
45
  if (apiKey) {
26
- // If email is provided directly, use it
27
- const providedEmail = options.email || process.env.CLOUDFLARE_EMAIL;
28
- if (providedEmail) {
29
- return {
30
- headers: {
31
- "X-Auth-Key": apiKey,
32
- "X-Auth-Email": providedEmail,
33
- },
34
- type: "key",
35
- email: providedEmail,
36
- };
37
- }
38
- // Otherwise, try to discover email from Cloudflare API
39
- try {
40
- const email = await getUserEmailFromApiKey(apiKey);
41
- return {
42
- headers: {
43
- "X-Auth-Key": apiKey,
44
- "X-Auth-Email": email,
45
- },
46
- type: "key",
47
- email,
48
- };
49
- }
50
- catch (error) {
51
- console.error("Failed to discover email from API key:", error);
52
- throw new Error("Failed to automatically discover email for API Key authentication.\n" +
53
- "Options:\n" +
54
- "1. Set CLOUDFLARE_EMAIL environment variable\n" +
55
- "2. Use CLOUDFLARE_API_TOKEN instead (recommended by Cloudflare)");
56
- }
46
+ return {
47
+ "X-Auth-Key": apiKey,
48
+ "X-Auth-Email": options.email ??
49
+ process.env.CLOUDFLARE_EMAIL ??
50
+ (await getUserEmailFromApiKey(apiKey)),
51
+ };
57
52
  }
58
- // No authentication found
59
- if (required) {
60
- throw new Error("Cloudflare authentication required. Set either:\n" +
61
- "1. CLOUDFLARE_API_TOKEN (recommended by Cloudflare)\n" +
62
- " Generate a token at: https://dash.cloudflare.com/profile/api-tokens\n" +
63
- "2. CLOUDFLARE_API_KEY environment variable");
53
+ const authConfig = await getRefreshedAuthConfig();
54
+ if (authConfig.oauth_token) {
55
+ return {
56
+ Authorization: `Bearer ${authConfig.oauth_token}`,
57
+ };
64
58
  }
65
- return {
66
- headers: {},
67
- type: "none",
68
- };
59
+ throw new Error("Cloudflare authentication required. Did you forget to login with `wrangler login` or set CLOUDFLARE_API_TOKEN, CLOUDFLARE_API_KEY, or CLOUDFLARE_EMAIL, or CLOUDFLARE_API_KEY?");
69
60
  }
70
- /**
71
- * Fetch the user's email from Cloudflare API using API Key
72
- *
73
- * @param apiKey The Cloudflare API key
74
- * @returns The user's email
75
- */
61
+ const emailCache = {};
76
62
  async function getUserEmailFromApiKey(apiKey) {
63
+ if (emailCache[apiKey]) {
64
+ return emailCache[apiKey];
65
+ }
77
66
  try {
78
67
  const baseUrl = "https://api.cloudflare.com/client/v4";
79
68
  // Call the /user endpoint to get user information
@@ -90,6 +79,7 @@ async function getUserEmailFromApiKey(apiKey) {
90
79
  if (!data.success || !data.result || !data.result.email) {
91
80
  throw new Error("Cloudflare API did not return valid user information");
92
81
  }
82
+ emailCache[apiKey] = data.result.email;
93
83
  return data.result.email;
94
84
  }
95
85
  catch (error) {
@@ -97,17 +87,98 @@ async function getUserEmailFromApiKey(apiKey) {
97
87
  throw new Error("Failed to automatically discover email for API Key authentication");
98
88
  }
99
89
  }
100
- /**
101
- * Get headers for a Cloudflare API request, including content-type
102
- *
103
- * @param contentType Content type for the request
104
- * @param options Authentication options
105
- * @returns Complete headers for the request
106
- */
107
- export async function getCloudflareHeaders(contentType = "application/json", options = {}) {
108
- const auth = await getCloudflareAuth(options);
109
- return {
110
- "Content-Type": contentType,
111
- ...auth.headers,
90
+ async function refreshAuthToken(options) {
91
+ const response = await fetch("https://dash.cloudflare.com/oauth2/token", {
92
+ method: "POST",
93
+ headers: {
94
+ "Content-Type": "application/x-www-form-urlencoded",
95
+ },
96
+ body: new URLSearchParams({
97
+ grant_type: "refresh_token",
98
+ refresh_token: options.refresh_token,
99
+ client_id: "54d11594-84e4-41aa-b438-e81b8fa78ee7",
100
+ }).toString(),
101
+ });
102
+ if (!response.ok) {
103
+ throw new Error(`Failed to refresh auth token: ${response.status} ${response.statusText}`);
104
+ }
105
+ const data = await response.json();
106
+ if (!data.access_token) {
107
+ throw new Error("Failed to refresh auth token - no access token returned");
108
+ }
109
+ options.oauth_token = data.access_token;
110
+ options.refresh_token = data.refresh_token;
111
+ options.expiration_time = new Date(Date.now() + data.expires_in * 1000).toISOString();
112
+ options.scopes = data.scope?.split(" ") || [];
113
+ return options;
114
+ }
115
+ async function getRefreshedAuthConfig() {
116
+ let authConfig = await readWranglerConfig();
117
+ if (authConfig.expiration_time) {
118
+ const expiry = new Date(authConfig.expiration_time);
119
+ // if expiring in 10s
120
+ if (expiry.getTime() < Date.now() + 10 * 1000) {
121
+ authConfig = await refreshAuthToken(authConfig);
122
+ authConfigCache[authConfig.path] = authConfig;
123
+ await writeWranglerConfig(authConfig);
124
+ }
125
+ }
126
+ return authConfig;
127
+ }
128
+ async function writeWranglerConfig(config) {
129
+ const TOML = await import("@iarna/toml");
130
+ const configPath = await findWranglerConfig();
131
+ config = {
132
+ ...config,
112
133
  };
134
+ // @ts-ignore - i put this here
135
+ delete config.path;
136
+ const toml = TOML.stringify(config);
137
+ await fs.writeFile(configPath, toml);
138
+ }
139
+ // cache the file once per process
140
+ const authConfigCache = {};
141
+ async function readWranglerConfig() {
142
+ const configPath = await findWranglerConfig();
143
+ const config = (authConfigCache[configPath] ??= await parseTOML(await fs.readFile(configPath, "utf-8")));
144
+ config.path = configPath;
145
+ return config;
146
+ }
147
+ let wranglerConfigPath;
148
+ async function findWranglerConfig() {
149
+ if (wranglerConfigPath) {
150
+ return wranglerConfigPath;
151
+ }
152
+ const environment = process.env.WRANGLER_API_ENVIRONMENT ?? "production";
153
+ const filePath = path.join("config", `${environment === "production" ? "default.toml" : `${environment}.toml`}`);
154
+ const xdgAppPaths = (await import("xdg-app-paths")).default;
155
+ //TODO: We should implement a custom path --global-config and/or the WRANGLER_HOME type environment variable
156
+ const configDir = xdgAppPaths(".wrangler").config(); // New XDG compliant config path
157
+ const legacyConfigDir = path.join(os.homedir(), ".wrangler"); // Legacy config in user's home directory
158
+ // Check for the .wrangler directory in root if it is not there then use the XDG compliant path.
159
+ wranglerConfigPath = path.join((await isDirectory(legacyConfigDir)) ? legacyConfigDir : configDir, filePath);
160
+ return wranglerConfigPath;
161
+ }
162
+ async function parseTOML(input) {
163
+ const TOML = await import("@iarna/toml");
164
+ try {
165
+ // Normalize CRLF to LF to avoid hitting https://github.com/iarna/iarna-toml/issues/33.
166
+ const normalizedInput = input.replace(/\r\n/g, "\n");
167
+ return TOML.parse(normalizedInput);
168
+ }
169
+ catch (err) {
170
+ const { name } = err;
171
+ if (name !== "TomlError") {
172
+ throw err;
173
+ }
174
+ throw new Error("TOML parse error");
175
+ }
176
+ }
177
+ async function isDirectory(dir) {
178
+ try {
179
+ return (await fs.stat(dir)).isDirectory();
180
+ }
181
+ catch (err) {
182
+ return false;
183
+ }
113
184
  }
@@ -9,22 +9,18 @@ import type { R2Bucket } from "./bucket";
9
9
  import type { DurableObjectNamespace } from "./durable-object-namespace";
10
10
  import type { KVNamespace } from "./kv-namespace";
11
11
  import type { Worker } from "./worker";
12
+ import type { Workflow } from "./workflow";
12
13
  export type Bindings = {
13
14
  [bindingName: string]: Binding;
14
15
  };
15
16
  /**
16
17
  * L2 Binding Resources.
17
18
  */
18
- export type Binding = DurableObjectNamespace | KVNamespace | Worker | R2Bucket | Secret | string | Assets;
19
- export declare function isDurableObjectNamespace(binding: Binding): binding is DurableObjectNamespace;
20
- /**
21
- * Check if a binding is an Assets resource
22
- */
23
- export declare function isAssets(binding: Binding): binding is Assets;
19
+ export type Binding = DurableObjectNamespace | KVNamespace | Worker | Workflow | R2Bucket | Secret | string | Assets;
24
20
  /**
25
21
  * Union type for all Worker binding types (API spec)
26
22
  */
27
- export type WorkerBindingSpec = WorkerBindingAI | WorkerBindingAnalyticsEngine | WorkerBindingAssets | WorkerBindingBrowserRendering | WorkerBindingD1 | WorkerBindingDispatchNamespace | WorkerBindingDurableObjectNamespace | WorkerBindingHyperdrive | WorkerBindingJson | WorkerBindingKVNamespace | WorkerBindingMTLSCertificate | WorkerBindingPlainText | WorkerBindingQueue | WorkerBindingR2Bucket | WorkerBindingSecretText | WorkerBindingService | WorkerBindingStaticContent | WorkerBindingTailConsumer | WorkerBindingVectorize | WorkerBindingVersionMetadata | WorkerBindingWasmModule;
23
+ export type WorkerBindingSpec = WorkerBindingAI | WorkerBindingAnalyticsEngine | WorkerBindingAssets | WorkerBindingBrowserRendering | WorkerBindingD1 | WorkerBindingDispatchNamespace | WorkerBindingDurableObjectNamespace | WorkerBindingHyperdrive | WorkerBindingJson | WorkerBindingKVNamespace | WorkerBindingMTLSCertificate | WorkerBindingPlainText | WorkerBindingQueue | WorkerBindingR2Bucket | WorkerBindingSecretText | WorkerBindingService | WorkerBindingStaticContent | WorkerBindingTailConsumer | WorkerBindingVectorize | WorkerBindingVersionMetadata | WorkerBindingWasmModule | WorkerBindingWorkflow;
28
24
  /**
29
25
  * AI binding type
30
26
  */
@@ -264,3 +260,19 @@ export interface WorkerBindingStaticContent {
264
260
  /** Type identifier for Static Content binding */
265
261
  type: "static_content";
266
262
  }
263
+ export interface WorkerBindingWorkflow {
264
+ /** The name of the binding */
265
+ name: string;
266
+ /** Type identifier for Workflow binding */
267
+ type: "workflow";
268
+ /** Workflow name */
269
+ workflow_name: string;
270
+ /** Workflow class name */
271
+ class_name: string;
272
+ /**
273
+ * Workflow script name
274
+ *
275
+ * @default - the name of the script it is bound to
276
+ */
277
+ script_name?: string;
278
+ }
@@ -1,9 +0,0 @@
1
- export function isDurableObjectNamespace(binding) {
2
- return (typeof binding === "object" && binding.type === "durable_object_namespace");
3
- }
4
- /**
5
- * Check if a binding is an Assets resource
6
- */
7
- export function isAssets(binding) {
8
- return typeof binding === "object" && binding.type === "assets";
9
- }
@@ -5,4 +5,5 @@ import type { R2Bucket as _R2Bucket } from "./bucket";
5
5
  import type { DurableObjectNamespace as _DurableObjectNamespace } from "./durable-object-namespace";
6
6
  import type { KVNamespace as _KVNamespace } from "./kv-namespace";
7
7
  import type { Worker as _Worker } from "./worker";
8
- export type Bound<T extends Binding> = T extends _DurableObjectNamespace ? DurableObjectNamespace : T extends _KVNamespace ? KVNamespace : T extends _Worker ? Worker : T extends _R2Bucket ? R2Bucket : T extends Secret ? string : T extends Assets ? Service : Service;
8
+ import type { Workflow as _Workflow } from "./workflow";
9
+ export type Bound<T extends Binding> = T extends _DurableObjectNamespace ? DurableObjectNamespace : T extends _KVNamespace ? KVNamespace : T extends _Worker ? Worker : T extends _R2Bucket ? R2Bucket : T extends Secret ? string : T extends Assets ? Service : T extends _Workflow<infer P> ? Workflow<P> : Service;
@@ -1,11 +1,12 @@
1
1
  import { AwsClient } from "aws4fetch";
2
2
  import type { Context } from "../context";
3
3
  import { Resource } from "../resource";
4
- import { CloudflareApi, type CloudflareApiOptions } from "./api";
4
+ import type { Secret } from "../secret";
5
+ import { CloudflareApi } from "./api";
5
6
  /**
6
7
  * Properties for creating or updating an R2 Bucket
7
8
  */
8
- export interface BucketProps extends CloudflareApiOptions {
9
+ export interface BucketProps {
9
10
  /**
10
11
  * Name of the bucket
11
12
  * Names can only contain lowercase letters (a-z), numbers (0-9), and hyphens (-)
@@ -39,6 +40,30 @@ export interface BucketProps extends CloudflareApiOptions {
39
40
  * @default false
40
41
  */
41
42
  empty?: boolean;
43
+ /**
44
+ * API Token to use for the bucket
45
+ */
46
+ apiToken?: Secret;
47
+ /**
48
+ * API Key to use for the bucket
49
+ */
50
+ apiKey?: Secret;
51
+ /**
52
+ * Email to use for the bucket
53
+ */
54
+ email?: string;
55
+ /**
56
+ * Account ID to use for the bucket
57
+ */
58
+ accountId?: string;
59
+ /**
60
+ * Access Key to use for the bucket
61
+ */
62
+ accessKey?: Secret;
63
+ /**
64
+ * Secret Access Key to use for the bucket
65
+ */
66
+ secretAccessKey?: Secret;
42
67
  }
43
68
  /**
44
69
  * Output returned after R2 Bucket creation/update
@@ -106,9 +131,9 @@ export declare const R2Bucket: (((this: any, id: string, props?: {}) => never) &
106
131
  * Configuration for R2 client to connect to Cloudflare R2
107
132
  */
108
133
  export interface R2ClientConfig {
109
- accountId?: string;
110
- accessKeyId?: string;
111
- secretAccessKey?: string;
134
+ accountId: string;
135
+ accessKeyId?: Secret;
136
+ secretAccessKey?: Secret;
112
137
  jurisdiction?: string;
113
138
  }
114
139
  type R2Client = AwsClient & {
@@ -1,6 +1,7 @@
1
1
  import { AwsClient } from "aws4fetch";
2
2
  import { Resource } from "../resource";
3
- import { CloudflareAccountId, CloudflareApi, CloudflareApiError, createCloudflareApi, handleApiError, } from "./api";
3
+ import { CloudflareApi, createCloudflareApi } from "./api";
4
+ import { CloudflareApiError, handleApiError } from "./api-error";
4
5
  /**
5
6
  * Creates and manages Cloudflare R2 Buckets for object storage.
6
7
  *
@@ -53,7 +54,10 @@ export const R2Bucket = Resource("cloudflare::R2Bucket", async function (id, pro
53
54
  if (props.delete !== false) {
54
55
  if (props.empty) {
55
56
  console.log("Emptying R2 bucket:", bucketName);
56
- const r2Client = await createR2Client(props);
57
+ const r2Client = await createR2Client({
58
+ ...props,
59
+ accountId: api.accountId,
60
+ });
57
61
  // Empty the bucket first by deleting all objects
58
62
  await emptyBucket(r2Client, bucketName, props.jurisdiction);
59
63
  }
@@ -76,6 +80,7 @@ export const R2Bucket = Resource("cloudflare::R2Bucket", async function (id, pro
76
80
  creationDate: new Date(),
77
81
  jurisdiction: props.jurisdiction || "default",
78
82
  type: "r2_bucket",
83
+ accountId: api.accountId,
79
84
  });
80
85
  }
81
86
  });
@@ -84,10 +89,10 @@ export const R2Bucket = Resource("cloudflare::R2Bucket", async function (id, pro
84
89
  *
85
90
  * @see https://developers.cloudflare.com/r2/examples/aws/aws-sdk-js-v3/
86
91
  */
87
- export async function createR2Client(config = {}) {
88
- const accountId = await CloudflareAccountId(config);
89
- const accessKeyId = config.accessKeyId || process.env.R2_ACCESS_KEY_ID;
90
- const secretAccessKey = config.secretAccessKey || process.env.R2_SECRET_ACCESS_KEY;
92
+ export function createR2Client(config) {
93
+ const accountId = config?.accountId ?? process.env.CLOUDFLARE_ACCOUNT_ID;
94
+ const accessKeyId = config?.accessKeyId?.unencrypted || process.env.R2_ACCESS_KEY_ID;
95
+ const secretAccessKey = config?.secretAccessKey?.unencrypted || process.env.R2_SECRET_ACCESS_KEY;
91
96
  if (!accountId) {
92
97
  throw new Error("CLOUDFLARE_ACCOUNT_ID environment variable is required");
93
98
  }
@@ -140,10 +145,7 @@ export async function createBucket(api, bucketName, props) {
140
145
  const headers = withJurisdiction({}, props);
141
146
  const createResponse = await api.post(`/accounts/${api.accountId}/r2/buckets`, createPayload, { headers });
142
147
  if (!createResponse.ok) {
143
- const errorData = await createResponse.json().catch(() => ({
144
- errors: [{ message: createResponse.statusText }],
145
- }));
146
- throw new CloudflareApiError(`Error creating R2 bucket '${bucketName}': ${errorData.errors?.[0]?.message || createResponse.statusText}`, createResponse);
148
+ return await handleApiError(createResponse, "creating", "R2 bucket", bucketName);
147
149
  }
148
150
  return (await createResponse.json());
149
151
  }
@@ -251,7 +253,6 @@ export async function emptyBucket(r2, bucketName, jurisdiction) {
251
253
  * so we still use the Cloudflare API directly.
252
254
  */
253
255
  export async function updatePublicAccess(api, bucketName, allowPublicAccess, jurisdiction) {
254
- console.log(`/accounts/${api.accountId}/r2/buckets/${bucketName}/domains/managed`);
255
256
  const headers = withJurisdiction({}, jurisdiction);
256
257
  const response = await api.put(`/accounts/${api.accountId}/r2/buckets/${bucketName}/domains/managed`, {
257
258
  enabled: allowPublicAccess,
@@ -1,9 +1,10 @@
1
1
  import type { Context } from "../context";
2
2
  import { Resource } from "../resource";
3
+ import { type CloudflareApiOptions } from "./api";
3
4
  /**
4
5
  * Properties for creating or updating a CustomDomain
5
6
  */
6
- export interface CustomDomainProps {
7
+ export interface CustomDomainProps extends CloudflareApiOptions {
7
8
  /**
8
9
  * The domain name to bind to the worker
9
10
  */
@@ -1,5 +1,6 @@
1
1
  import { Resource } from "../resource";
2
- import { CloudflareApi, createCloudflareApi, handleApiError } from "./api";
2
+ import { CloudflareApi, createCloudflareApi, } from "./api";
3
+ import { handleApiError } from "./api-error";
3
4
  /**
4
5
  * Configure custom domain for a Cloudflare Worker using the Cloudflare Custom Domains API
5
6
  * This attaches a worker to a specific hostname within a zone.
@@ -22,7 +23,7 @@ import { CloudflareApi, createCloudflareApi, handleApiError } from "./api";
22
23
  export const CustomDomain = Resource("cloudflare::CustomDomain", async function (logicalId, // Changed param name from id to logicalId for clarity
23
24
  props) {
24
25
  // Create Cloudflare API client with automatic account discovery
25
- const api = await createCloudflareApi();
26
+ const api = await createCloudflareApi(props);
26
27
  // Validate required properties
27
28
  if (!props.name) {
28
29
  throw new Error("Domain name (props.name) is required");
@@ -1,6 +1,7 @@
1
1
  import type { Context } from "../context";
2
2
  import type { DnsRecord as BaseDnsRecord, DnsRecordType, DnsRecordWithMetadata } from "../dns/record";
3
3
  import { Resource } from "../resource";
4
+ import { type CloudflareApiOptions } from "./api";
4
5
  /**
5
6
  * Properties for a DNS record
6
7
  */
@@ -18,7 +19,7 @@ export interface DnsRecord extends DnsRecordWithMetadata {
18
19
  /**
19
20
  * Properties for managing multiple DNS records
20
21
  */
21
- export interface DnsRecordsProps {
22
+ export interface DnsRecordsProps extends CloudflareApiOptions {
22
23
  /**
23
24
  * Zone ID or domain name where records will be created
24
25
  */
@@ -1,5 +1,5 @@
1
1
  import { Resource } from "../resource";
2
- import { createCloudflareApi } from "./api";
2
+ import { createCloudflareApi, } from "./api";
3
3
  /**
4
4
  * Manages a batch of DNS records in a Cloudflare zone.
5
5
  * Supports creating, updating, and deleting multiple records at once.
@@ -46,7 +46,7 @@ import { createCloudflareApi } from "./api";
46
46
  */
47
47
  export const DnsRecords = Resource("cloudflare::DnsRecords", async function (id, props) {
48
48
  // Create Cloudflare API client
49
- const api = await createCloudflareApi();
49
+ const api = await createCloudflareApi(props);
50
50
  // Get zone ID if domain name was provided
51
51
  const zoneId = props.zoneId;
52
52
  if (this.phase === "delete") {
@@ -10,5 +10,6 @@ export * from "./kv-namespace";
10
10
  export * from "./permission-groups";
11
11
  export * from "./r2-rest-state-store";
12
12
  export * from "./worker";
13
+ export { Workflow } from "./workflow";
13
14
  export * from "./wrangler.json";
14
15
  export * from "./zone";
@@ -10,5 +10,6 @@ export * from "./kv-namespace";
10
10
  export * from "./permission-groups";
11
11
  export * from "./r2-rest-state-store";
12
12
  export * from "./worker";
13
+ export { Workflow } from "./workflow";
13
14
  export * from "./wrangler.json";
14
15
  export * from "./zone";
@@ -1,10 +1,11 @@
1
1
  import type { Context } from "../context";
2
2
  import { Resource } from "../resource";
3
+ import { CloudflareApi, type CloudflareApiOptions } from "./api";
3
4
  export declare function isKVNamespace(resource: any): resource is KVNamespace;
4
5
  /**
5
6
  * Properties for creating or updating a KV Namespace
6
7
  */
7
- export interface KVNamespaceProps {
8
+ export interface KVNamespaceProps extends CloudflareApiOptions {
8
9
  /**
9
10
  * Title of the namespace
10
11
  */
@@ -95,3 +96,8 @@ export interface KVNamespace extends Resource<"cloudflare::KVNamespace">, KVName
95
96
  * });
96
97
  */
97
98
  export declare const KVNamespace: (((this: any, id: string, props?: {}) => never) & (new (_: never) => never)) | ((this: Context<KVNamespace>, id: string, props: KVNamespaceProps) => Promise<KVNamespace>);
99
+ export declare function createKVNamespace(api: CloudflareApi, props: KVNamespaceProps): Promise<{
100
+ id: string;
101
+ }>;
102
+ export declare function deleteKVNamespace(api: CloudflareApi, namespaceId: string): Promise<void>;
103
+ export declare function insertKVRecords(api: CloudflareApi, namespaceId: string, props: KVNamespaceProps): Promise<void>;