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.
- package/lib/cloudflare/account-api-token.d.ts +6 -1
- package/lib/cloudflare/account-api-token.js +5 -1
- package/lib/cloudflare/account-id.d.ts +5 -1
- package/lib/cloudflare/account-id.js +5 -0
- package/lib/cloudflare/api-error.d.ts +32 -0
- package/lib/cloudflare/api-error.js +47 -0
- package/lib/cloudflare/api.d.ts +16 -49
- package/lib/cloudflare/api.js +37 -149
- package/lib/cloudflare/auth.d.ts +55 -38
- package/lib/cloudflare/auth.js +148 -77
- package/lib/cloudflare/bindings.d.ts +19 -7
- package/lib/cloudflare/bindings.js +0 -9
- package/lib/cloudflare/bound.d.ts +2 -1
- package/lib/cloudflare/bucket.d.ts +30 -5
- package/lib/cloudflare/bucket.js +12 -11
- package/lib/cloudflare/custom-domain.d.ts +2 -1
- package/lib/cloudflare/custom-domain.js +3 -2
- package/lib/cloudflare/dns-records.d.ts +2 -1
- package/lib/cloudflare/dns-records.js +2 -2
- package/lib/cloudflare/index.d.ts +1 -0
- package/lib/cloudflare/index.js +1 -0
- package/lib/cloudflare/kv-namespace.d.ts +7 -1
- package/lib/cloudflare/kv-namespace.js +72 -71
- package/lib/cloudflare/permission-groups.d.ts +4 -0
- package/lib/cloudflare/permission-groups.js +5 -1
- package/lib/cloudflare/r2-rest-state-store.d.ts +3 -17
- package/lib/cloudflare/r2-rest-state-store.js +4 -12
- package/lib/cloudflare/worker.d.ts +2 -6
- package/lib/cloudflare/worker.js +58 -90
- package/lib/cloudflare/workflow.d.ts +46 -0
- package/lib/cloudflare/workflow.js +29 -0
- package/lib/cloudflare/zone.d.ts +2 -6
- package/lib/cloudflare/zone.js +1 -3
- package/lib/internal/docs/providers.js +1 -8
- package/package.json +5 -1
- package/src/cloudflare/account-api-token.ts +7 -3
- package/src/cloudflare/account-id.ts +12 -0
- package/src/cloudflare/api-error.ts +58 -0
- package/src/cloudflare/api.ts +50 -216
- package/src/cloudflare/auth.ts +262 -119
- package/src/cloudflare/bindings.ts +21 -16
- package/src/cloudflare/bound.ts +4 -1
- package/src/cloudflare/bucket.ts +52 -29
- package/src/cloudflare/custom-domain.ts +8 -3
- package/src/cloudflare/dns-records.ts +7 -3
- package/src/cloudflare/durable-object-namespace.ts +1 -1
- package/src/cloudflare/index.ts +1 -0
- package/src/cloudflare/kv-namespace.ts +117 -105
- package/src/cloudflare/permission-groups.ts +5 -1
- package/src/cloudflare/r2-rest-state-store.ts +8 -31
- package/src/cloudflare/worker.ts +71 -141
- package/src/cloudflare/workflow.ts +79 -0
- package/src/cloudflare/zone.ts +17 -25
- package/src/internal/docs/providers.ts +1 -8
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Context } from "../context";
|
|
2
2
|
import { Resource } from "../resource";
|
|
3
3
|
import { Secret } from "../secret";
|
|
4
|
+
import { type CloudflareApiOptions } from "./api";
|
|
4
5
|
/**
|
|
5
6
|
* Permission group for a token policy
|
|
6
7
|
*/
|
|
@@ -52,7 +53,7 @@ export interface TokenCondition {
|
|
|
52
53
|
/**
|
|
53
54
|
* Properties for creating or updating an Account API Token
|
|
54
55
|
*/
|
|
55
|
-
export interface AccountApiTokenProps {
|
|
56
|
+
export interface AccountApiTokenProps extends CloudflareApiOptions {
|
|
56
57
|
/**
|
|
57
58
|
* Name of the token
|
|
58
59
|
*/
|
|
@@ -113,6 +114,10 @@ export interface AccountApiToken extends Resource<"cloudflare::AccountApiToken">
|
|
|
113
114
|
/**
|
|
114
115
|
* Creates a Cloudflare Account API Token with specified permissions.
|
|
115
116
|
*
|
|
117
|
+
* Note: Requires a Cloudflare API Key or Token with admin-level account access.
|
|
118
|
+
* The OAuth token from `wrangler login` is NOT sufficient for this operation.
|
|
119
|
+
* You must use an API token with permission to manage account API tokens.
|
|
120
|
+
*
|
|
116
121
|
* @see https://developers.cloudflare.com/api/resources/accounts/subresources/tokens/methods/create/
|
|
117
122
|
*
|
|
118
123
|
* @example
|
|
@@ -6,6 +6,10 @@ import { createCloudflareApi } from "./api";
|
|
|
6
6
|
/**
|
|
7
7
|
* Creates a Cloudflare Account API Token with specified permissions.
|
|
8
8
|
*
|
|
9
|
+
* Note: Requires a Cloudflare API Key or Token with admin-level account access.
|
|
10
|
+
* The OAuth token from `wrangler login` is NOT sufficient for this operation.
|
|
11
|
+
* You must use an API token with permission to manage account API tokens.
|
|
12
|
+
*
|
|
9
13
|
* @see https://developers.cloudflare.com/api/resources/accounts/subresources/tokens/methods/create/
|
|
10
14
|
*
|
|
11
15
|
* @example
|
|
@@ -60,7 +64,7 @@ import { createCloudflareApi } from "./api";
|
|
|
60
64
|
*/
|
|
61
65
|
export const AccountApiToken = Resource("cloudflare::AccountApiToken", async function (id, props) {
|
|
62
66
|
// Create Cloudflare API client with automatic account discovery
|
|
63
|
-
const api = await createCloudflareApi();
|
|
67
|
+
const api = await createCloudflareApi(props);
|
|
64
68
|
if (this.phase === "delete") {
|
|
65
69
|
// Delete token if we have an ID
|
|
66
70
|
if (this.output?.id) {
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom error class for Cloudflare API errors
|
|
3
|
+
* Includes HTTP status information from the Response
|
|
4
|
+
*/
|
|
5
|
+
export declare class CloudflareApiError extends Error {
|
|
6
|
+
/**
|
|
7
|
+
* HTTP status code
|
|
8
|
+
*/
|
|
9
|
+
status: number;
|
|
10
|
+
/**
|
|
11
|
+
* HTTP status text
|
|
12
|
+
*/
|
|
13
|
+
statusText: string;
|
|
14
|
+
/**
|
|
15
|
+
* Raw error data from the API
|
|
16
|
+
*/
|
|
17
|
+
errorData?: any;
|
|
18
|
+
/**
|
|
19
|
+
* Create a new CloudflareApiError
|
|
20
|
+
*/
|
|
21
|
+
constructor(message: string, response: Response, errorData?: any);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Helper function to handle API errors
|
|
25
|
+
*
|
|
26
|
+
* @param response The fetch Response object
|
|
27
|
+
* @param action The action being performed (e.g., "creating", "deleting")
|
|
28
|
+
* @param resourceType The type of resource being acted upon (e.g., "R2 bucket", "Worker")
|
|
29
|
+
* @param resourceName The name/identifier of the specific resource
|
|
30
|
+
* @returns Never returns - always throws an error
|
|
31
|
+
*/
|
|
32
|
+
export declare function handleApiError(response: Response, action: string, resourceType: string, resourceName: string): Promise<never>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom error class for Cloudflare API errors
|
|
3
|
+
* Includes HTTP status information from the Response
|
|
4
|
+
*/
|
|
5
|
+
export class CloudflareApiError extends Error {
|
|
6
|
+
/**
|
|
7
|
+
* HTTP status code
|
|
8
|
+
*/
|
|
9
|
+
status;
|
|
10
|
+
/**
|
|
11
|
+
* HTTP status text
|
|
12
|
+
*/
|
|
13
|
+
statusText;
|
|
14
|
+
/**
|
|
15
|
+
* Raw error data from the API
|
|
16
|
+
*/
|
|
17
|
+
errorData;
|
|
18
|
+
/**
|
|
19
|
+
* Create a new CloudflareApiError
|
|
20
|
+
*/
|
|
21
|
+
constructor(message, response, errorData) {
|
|
22
|
+
super(message);
|
|
23
|
+
this.name = "CloudflareApiError";
|
|
24
|
+
this.status = response.status;
|
|
25
|
+
this.statusText = response.statusText;
|
|
26
|
+
this.errorData = errorData;
|
|
27
|
+
// Ensure instanceof works correctly
|
|
28
|
+
Object.setPrototypeOf(this, CloudflareApiError.prototype);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Helper function to handle API errors
|
|
33
|
+
*
|
|
34
|
+
* @param response The fetch Response object
|
|
35
|
+
* @param action The action being performed (e.g., "creating", "deleting")
|
|
36
|
+
* @param resourceType The type of resource being acted upon (e.g., "R2 bucket", "Worker")
|
|
37
|
+
* @param resourceName The name/identifier of the specific resource
|
|
38
|
+
* @returns Never returns - always throws an error
|
|
39
|
+
*/
|
|
40
|
+
export async function handleApiError(response, action, resourceType, resourceName) {
|
|
41
|
+
const json = await response.json();
|
|
42
|
+
const errors = json.errors || [
|
|
43
|
+
{ message: response.statusText },
|
|
44
|
+
];
|
|
45
|
+
const errorMessage = `Error ${action} ${resourceType} '${resourceName}': ${errors[0]?.message || response.statusText}`;
|
|
46
|
+
throw new CloudflareApiError(errorMessage, response, errors);
|
|
47
|
+
}
|
package/lib/cloudflare/api.d.ts
CHANGED
|
@@ -3,10 +3,20 @@ import type { Secret } from "../secret";
|
|
|
3
3
|
* Options for Cloudflare API requests
|
|
4
4
|
*/
|
|
5
5
|
export interface CloudflareApiOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Base URL for Cloudflare API
|
|
8
|
+
*
|
|
9
|
+
* @default https://api.cloudflare.com/client/v4
|
|
10
|
+
*/
|
|
11
|
+
baseUrl?: string;
|
|
6
12
|
/**
|
|
7
13
|
* API Key to use (overrides CLOUDFLARE_API_KEY env var)
|
|
8
14
|
*/
|
|
9
15
|
apiKey?: Secret;
|
|
16
|
+
/**
|
|
17
|
+
* API Token to use (overrides CLOUDFLARE_API_TOKEN env var)
|
|
18
|
+
*/
|
|
19
|
+
apiToken?: Secret;
|
|
10
20
|
/**
|
|
11
21
|
* Account ID to use (overrides CLOUDFLARE_ACCOUNT_ID env var)
|
|
12
22
|
* If not provided, will be automatically retrieved from the Cloudflare API
|
|
@@ -22,65 +32,20 @@ export interface CloudflareApiOptions {
|
|
|
22
32
|
*/
|
|
23
33
|
email?: string;
|
|
24
34
|
}
|
|
25
|
-
/**
|
|
26
|
-
* Custom error class for Cloudflare API errors
|
|
27
|
-
* Includes HTTP status information from the Response
|
|
28
|
-
*/
|
|
29
|
-
export declare class CloudflareApiError extends Error {
|
|
30
|
-
/**
|
|
31
|
-
* HTTP status code
|
|
32
|
-
*/
|
|
33
|
-
status: number;
|
|
34
|
-
/**
|
|
35
|
-
* HTTP status text
|
|
36
|
-
*/
|
|
37
|
-
statusText: string;
|
|
38
|
-
/**
|
|
39
|
-
* Raw error data from the API
|
|
40
|
-
*/
|
|
41
|
-
errorData?: any;
|
|
42
|
-
/**
|
|
43
|
-
* Create a new CloudflareApiError
|
|
44
|
-
*/
|
|
45
|
-
constructor(message: string, response: Response, errorData?: any);
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Helper function to handle API errors
|
|
49
|
-
*
|
|
50
|
-
* @param response The fetch Response object
|
|
51
|
-
* @param action The action being performed (e.g., "creating", "deleting")
|
|
52
|
-
* @param resourceType The type of resource being acted upon (e.g., "R2 bucket", "Worker")
|
|
53
|
-
* @param resourceName The name/identifier of the specific resource
|
|
54
|
-
* @returns Never returns - always throws an error
|
|
55
|
-
*/
|
|
56
|
-
export declare function handleApiError(response: Response, action: string, resourceType: string, resourceName: string): Promise<never>;
|
|
57
35
|
/**
|
|
58
36
|
* Creates a CloudflareApi instance with automatic account ID discovery if not provided
|
|
59
37
|
*
|
|
60
38
|
* @param options API options
|
|
61
39
|
* @returns Promise resolving to a CloudflareApi instance
|
|
62
40
|
*/
|
|
63
|
-
export declare function createCloudflareApi(options?: CloudflareApiOptions): Promise<CloudflareApi>;
|
|
64
|
-
export type CloudflareAccountId = string & {
|
|
65
|
-
readonly __brand: "CloudflareAccountId";
|
|
66
|
-
};
|
|
67
|
-
export declare function CloudflareAccountId(options?: CloudflareApiOptions): Promise<CloudflareAccountId>;
|
|
41
|
+
export declare function createCloudflareApi(options?: Partial<CloudflareApiOptions>): Promise<CloudflareApi>;
|
|
68
42
|
/**
|
|
69
43
|
* Cloudflare API client using raw fetch
|
|
70
44
|
*/
|
|
71
45
|
export declare class CloudflareApi {
|
|
72
|
-
|
|
73
|
-
readonly baseUrl: string;
|
|
74
|
-
/** Cloudflare API Key */
|
|
75
|
-
readonly apiKey: string;
|
|
76
|
-
/** Cloudflare account ID */
|
|
46
|
+
private readonly options;
|
|
77
47
|
readonly accountId: string;
|
|
78
|
-
|
|
79
|
-
readonly zoneId: string | null;
|
|
80
|
-
/** User email (when using API Key auth) */
|
|
81
|
-
readonly email?: string;
|
|
82
|
-
/** Auth options for making requests */
|
|
83
|
-
private readonly authOptions;
|
|
48
|
+
readonly baseUrl: string;
|
|
84
49
|
/**
|
|
85
50
|
* Create a new Cloudflare API client
|
|
86
51
|
* Use createCloudflareApi factory function instead of direct constructor
|
|
@@ -88,7 +53,9 @@ export declare class CloudflareApi {
|
|
|
88
53
|
*
|
|
89
54
|
* @param options API options
|
|
90
55
|
*/
|
|
91
|
-
constructor(options
|
|
56
|
+
constructor(options: CloudflareApiOptions & {
|
|
57
|
+
accountId: string;
|
|
58
|
+
});
|
|
92
59
|
/**
|
|
93
60
|
* Make a fetch request to the Cloudflare API
|
|
94
61
|
*
|
package/lib/cloudflare/api.js
CHANGED
|
@@ -1,51 +1,5 @@
|
|
|
1
1
|
import { withExponentialBackoff } from "../util/retry";
|
|
2
|
-
import {
|
|
3
|
-
/**
|
|
4
|
-
* Custom error class for Cloudflare API errors
|
|
5
|
-
* Includes HTTP status information from the Response
|
|
6
|
-
*/
|
|
7
|
-
export class CloudflareApiError extends Error {
|
|
8
|
-
/**
|
|
9
|
-
* HTTP status code
|
|
10
|
-
*/
|
|
11
|
-
status;
|
|
12
|
-
/**
|
|
13
|
-
* HTTP status text
|
|
14
|
-
*/
|
|
15
|
-
statusText;
|
|
16
|
-
/**
|
|
17
|
-
* Raw error data from the API
|
|
18
|
-
*/
|
|
19
|
-
errorData;
|
|
20
|
-
/**
|
|
21
|
-
* Create a new CloudflareApiError
|
|
22
|
-
*/
|
|
23
|
-
constructor(message, response, errorData) {
|
|
24
|
-
super(message);
|
|
25
|
-
this.name = "CloudflareApiError";
|
|
26
|
-
this.status = response.status;
|
|
27
|
-
this.statusText = response.statusText;
|
|
28
|
-
this.errorData = errorData;
|
|
29
|
-
// Ensure instanceof works correctly
|
|
30
|
-
Object.setPrototypeOf(this, CloudflareApiError.prototype);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Helper function to handle API errors
|
|
35
|
-
*
|
|
36
|
-
* @param response The fetch Response object
|
|
37
|
-
* @param action The action being performed (e.g., "creating", "deleting")
|
|
38
|
-
* @param resourceType The type of resource being acted upon (e.g., "R2 bucket", "Worker")
|
|
39
|
-
* @param resourceName The name/identifier of the specific resource
|
|
40
|
-
* @returns Never returns - always throws an error
|
|
41
|
-
*/
|
|
42
|
-
export async function handleApiError(response, action, resourceType, resourceName) {
|
|
43
|
-
const json = await response.json();
|
|
44
|
-
console.log(json);
|
|
45
|
-
const errorData = json.errors || [{ message: response.statusText }];
|
|
46
|
-
const errorMessage = `Error ${action} ${resourceType} '${resourceName}': ${errorData.errors?.[0]?.message || response.statusText}`;
|
|
47
|
-
throw new CloudflareApiError(errorMessage, response, errorData);
|
|
48
|
-
}
|
|
2
|
+
import { getCloudflareAuthHeaders, getCloudflareUserInfo } from "./auth";
|
|
49
3
|
/**
|
|
50
4
|
* Creates a CloudflareApi instance with automatic account ID discovery if not provided
|
|
51
5
|
*
|
|
@@ -53,38 +7,23 @@ export async function handleApiError(response, action, resourceType, resourceNam
|
|
|
53
7
|
* @returns Promise resolving to a CloudflareApi instance
|
|
54
8
|
*/
|
|
55
9
|
export async function createCloudflareApi(options = {}) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
export async function CloudflareAccountId(options = {}) {
|
|
68
|
-
return (options.accountId ||
|
|
69
|
-
process.env.CLOUDFLARE_ACCOUNT_ID ||
|
|
70
|
-
(await fetchAccountId()));
|
|
10
|
+
const userInfo = await getCloudflareUserInfo(options);
|
|
11
|
+
return new CloudflareApi({
|
|
12
|
+
baseUrl: options.baseUrl,
|
|
13
|
+
accountId: options.accountId ?? userInfo.accounts[0].id,
|
|
14
|
+
email: userInfo.email,
|
|
15
|
+
apiKey: userInfo.apiKey,
|
|
16
|
+
apiToken: userInfo.apiToken,
|
|
17
|
+
zoneId: options.zoneId,
|
|
18
|
+
});
|
|
71
19
|
}
|
|
72
20
|
/**
|
|
73
21
|
* Cloudflare API client using raw fetch
|
|
74
22
|
*/
|
|
75
23
|
export class CloudflareApi {
|
|
76
|
-
|
|
77
|
-
baseUrl;
|
|
78
|
-
/** Cloudflare API Key */
|
|
79
|
-
apiKey;
|
|
80
|
-
/** Cloudflare account ID */
|
|
24
|
+
options;
|
|
81
25
|
accountId;
|
|
82
|
-
|
|
83
|
-
zoneId;
|
|
84
|
-
/** User email (when using API Key auth) */
|
|
85
|
-
email;
|
|
86
|
-
/** Auth options for making requests */
|
|
87
|
-
authOptions;
|
|
26
|
+
baseUrl;
|
|
88
27
|
/**
|
|
89
28
|
* Create a new Cloudflare API client
|
|
90
29
|
* Use createCloudflareApi factory function instead of direct constructor
|
|
@@ -92,31 +31,10 @@ export class CloudflareApi {
|
|
|
92
31
|
*
|
|
93
32
|
* @param options API options
|
|
94
33
|
*/
|
|
95
|
-
constructor(options
|
|
96
|
-
this.
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
undefined;
|
|
100
|
-
if (!apiKey) {
|
|
101
|
-
throw new Error("No API key provided. Use createCloudflareApi() instead for automatic account discovery.");
|
|
102
|
-
}
|
|
103
|
-
this.apiKey = apiKey;
|
|
104
|
-
this.email = options.email || process.env.CLOUDFLARE_EMAIL;
|
|
105
|
-
if (!this.email) {
|
|
106
|
-
throw new Error("No email provided. Use createCloudflareApi() instead for automatic account discovery.");
|
|
107
|
-
}
|
|
108
|
-
// Get account ID from options or environment
|
|
109
|
-
this.accountId =
|
|
110
|
-
options.accountId || process.env.CLOUDFLARE_ACCOUNT_ID || "";
|
|
111
|
-
if (!this.accountId) {
|
|
112
|
-
throw new Error("No account ID provided. Use createCloudflareApi() instead for automatic account discovery.");
|
|
113
|
-
}
|
|
114
|
-
// Zone ID is optional for some operations
|
|
115
|
-
this.zoneId = options.zoneId || process.env.CLOUDFLARE_ZONE_ID || null;
|
|
116
|
-
// Store auth options for later use
|
|
117
|
-
this.authOptions = {
|
|
118
|
-
email: this.email,
|
|
119
|
-
};
|
|
34
|
+
constructor(options) {
|
|
35
|
+
this.options = options;
|
|
36
|
+
this.accountId = options.accountId;
|
|
37
|
+
this.baseUrl = options.baseUrl ?? "https://api.cloudflare.com/client/v4";
|
|
120
38
|
}
|
|
121
39
|
/**
|
|
122
40
|
* Make a fetch request to the Cloudflare API
|
|
@@ -126,36 +44,34 @@ export class CloudflareApi {
|
|
|
126
44
|
* @returns Raw Response object from fetch
|
|
127
45
|
*/
|
|
128
46
|
async fetch(path, init = {}) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
if (init.headers) {
|
|
132
|
-
const initHeaders = init.headers;
|
|
133
|
-
if (initHeaders["Content-Type"]) {
|
|
134
|
-
contentType = initHeaders["Content-Type"];
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
// Get auth headers (async now)
|
|
138
|
-
const authHeaders = await getCloudflareHeaders(contentType, this.authOptions);
|
|
139
|
-
// Combine all headers
|
|
140
|
-
const combinedHeaders = {
|
|
141
|
-
...authHeaders,
|
|
47
|
+
let headers = {
|
|
48
|
+
"Content-Type": "application/json",
|
|
142
49
|
};
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
Object.keys(initHeadersObj).forEach((key) => {
|
|
147
|
-
combinedHeaders[key] = initHeadersObj[key];
|
|
50
|
+
if (Array.isArray(init.headers)) {
|
|
51
|
+
init.headers.forEach(([key, value]) => {
|
|
52
|
+
headers[key] = value;
|
|
148
53
|
});
|
|
149
54
|
}
|
|
150
|
-
|
|
55
|
+
else if (init.headers instanceof Headers) {
|
|
56
|
+
init.headers.forEach((value, key) => {
|
|
57
|
+
headers[key] = value;
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
else if (init.headers) {
|
|
61
|
+
headers = init.headers;
|
|
62
|
+
}
|
|
63
|
+
headers = {
|
|
64
|
+
...(await getCloudflareAuthHeaders(this.options)),
|
|
65
|
+
...headers,
|
|
66
|
+
};
|
|
67
|
+
// TODO(sam): is this necessary?
|
|
151
68
|
if (init.body instanceof FormData) {
|
|
152
|
-
delete
|
|
69
|
+
delete headers["Content-Type"];
|
|
153
70
|
}
|
|
154
|
-
const url = `${this.baseUrl}${path}`;
|
|
155
71
|
// Use withExponentialBackoff for automatic retry on network errors
|
|
156
|
-
return withExponentialBackoff(() => fetch(
|
|
72
|
+
return withExponentialBackoff(() => fetch(`${this.baseUrl}${path}`, {
|
|
157
73
|
...init,
|
|
158
|
-
headers
|
|
74
|
+
headers,
|
|
159
75
|
}), (error) => {
|
|
160
76
|
// Only retry on network-related errors
|
|
161
77
|
const errorMsg = error.message || "";
|
|
@@ -215,31 +131,3 @@ export class CloudflareApi {
|
|
|
215
131
|
return this.fetch(path, { ...init, method: "DELETE" });
|
|
216
132
|
}
|
|
217
133
|
}
|
|
218
|
-
/**
|
|
219
|
-
* Create a temporary API client for bootstrapping
|
|
220
|
-
* This client can only be used to fetch the account ID
|
|
221
|
-
*/
|
|
222
|
-
async function fetchAccountId() {
|
|
223
|
-
// Create a minimal API client for bootstrapping
|
|
224
|
-
const baseUrl = "https://api.cloudflare.com/client/v4";
|
|
225
|
-
// Get content type and auth headers
|
|
226
|
-
const authHeaders = await getCloudflareHeaders("application/json");
|
|
227
|
-
// Make the request to get accounts
|
|
228
|
-
const response = await fetch(`${baseUrl}/accounts`, {
|
|
229
|
-
method: "GET",
|
|
230
|
-
headers: authHeaders,
|
|
231
|
-
});
|
|
232
|
-
if (!response.ok) {
|
|
233
|
-
const errorData = await response.json().catch(() => ({
|
|
234
|
-
errors: [{ message: response.statusText }],
|
|
235
|
-
}));
|
|
236
|
-
throw new Error(`Error fetching Cloudflare accounts: ${errorData.errors?.[0]?.message || response.statusText}`);
|
|
237
|
-
}
|
|
238
|
-
const data = await response.json();
|
|
239
|
-
const accounts = data.result;
|
|
240
|
-
if (!accounts || accounts.length === 0) {
|
|
241
|
-
throw new Error("No Cloudflare accounts found. Check your API token/key permissions.");
|
|
242
|
-
}
|
|
243
|
-
// Return the first account ID
|
|
244
|
-
return accounts[0].id;
|
|
245
|
-
}
|
package/lib/cloudflare/auth.d.ts
CHANGED
|
@@ -1,51 +1,68 @@
|
|
|
1
|
+
import type { Secret } from "../secret";
|
|
2
|
+
import type { CloudflareAccountId } from "./account-id";
|
|
1
3
|
/**
|
|
2
4
|
* Authentication options for Cloudflare API
|
|
3
5
|
*/
|
|
4
6
|
export interface CloudflareAuthOptions {
|
|
5
7
|
/**
|
|
6
|
-
*
|
|
7
|
-
* @default true
|
|
8
|
+
* API Key to use with API Key
|
|
8
9
|
*/
|
|
9
|
-
|
|
10
|
+
apiKey?: Secret;
|
|
11
|
+
/**
|
|
12
|
+
* API Token to use with API Key
|
|
13
|
+
*/
|
|
14
|
+
apiToken?: Secret;
|
|
10
15
|
/**
|
|
11
16
|
* Email to use with API Key
|
|
12
17
|
* If not provided, will attempt to discover from Cloudflare API
|
|
13
18
|
*/
|
|
14
19
|
email?: string;
|
|
15
20
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
21
|
+
export interface CloudflareAccount {
|
|
22
|
+
name: string;
|
|
23
|
+
id: CloudflareAccountId;
|
|
24
|
+
type: "standard" | "zero_rating" | "full_control";
|
|
25
|
+
settings: {
|
|
26
|
+
enforce_twofactor: boolean;
|
|
27
|
+
api_access_enabled: null;
|
|
28
|
+
access_approval_expiry: null;
|
|
29
|
+
abuse_contact_email: null;
|
|
30
|
+
};
|
|
31
|
+
legacy_flags: {
|
|
32
|
+
enterprise_zone_quota: {
|
|
33
|
+
maximum: number;
|
|
34
|
+
current: number;
|
|
35
|
+
available: number;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
32
38
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
39
|
+
export interface CloudflareUserInfo {
|
|
40
|
+
apiToken?: Secret;
|
|
41
|
+
apiKey?: Secret;
|
|
42
|
+
email: string;
|
|
43
|
+
username: string;
|
|
44
|
+
accounts: CloudflareAccount[];
|
|
45
|
+
organizations: CloudflareOrganization[];
|
|
46
|
+
tokenPermissions: string[] | undefined;
|
|
47
|
+
first_name: string | null;
|
|
48
|
+
last_name: string | null;
|
|
49
|
+
telephone: string | null;
|
|
50
|
+
country: string | null;
|
|
51
|
+
zipcode: string | null;
|
|
52
|
+
two_factor_authentication_enabled: boolean;
|
|
53
|
+
two_factor_authentication_locked: boolean;
|
|
54
|
+
has_pro_zones: boolean;
|
|
55
|
+
has_business_zones: boolean;
|
|
56
|
+
has_enterprise_zones: boolean;
|
|
57
|
+
suspended: boolean;
|
|
58
|
+
betas: string[];
|
|
59
|
+
}
|
|
60
|
+
export interface CloudflareOrganization {
|
|
61
|
+
id: string;
|
|
62
|
+
name: string;
|
|
63
|
+
status: string;
|
|
64
|
+
permissions: string[];
|
|
65
|
+
roles: string[];
|
|
66
|
+
}
|
|
67
|
+
export declare function getCloudflareUserInfo(options: CloudflareAuthOptions): Promise<CloudflareUserInfo>;
|
|
68
|
+
export declare function getCloudflareAuthHeaders(options?: CloudflareAuthOptions): Promise<Record<string, string>>;
|