alchemy 0.12.21 → 0.14.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/ai/client.d.ts.map +1 -1
- package/lib/ai/client.js +3 -5
- package/lib/ai/client.js.map +1 -1
- package/lib/alchemy.d.ts +2 -1
- package/lib/alchemy.d.ts.map +1 -1
- package/lib/alchemy.js +87 -92
- package/lib/alchemy.js.map +1 -1
- package/lib/apply.d.ts.map +1 -1
- package/lib/apply.js +6 -1
- package/lib/apply.js.map +1 -1
- package/lib/aws/bucket.d.ts.map +1 -1
- package/lib/aws/bucket.js +55 -57
- package/lib/aws/bucket.js.map +1 -1
- package/lib/aws/function.d.ts.map +1 -1
- package/lib/aws/function.js +250 -252
- package/lib/aws/function.js.map +1 -1
- package/lib/aws/policy-attachment.d.ts.map +1 -1
- package/lib/aws/policy-attachment.js +4 -6
- package/lib/aws/policy-attachment.js.map +1 -1
- package/lib/aws/policy.d.ts.map +1 -1
- package/lib/aws/policy.js +63 -65
- package/lib/aws/policy.js.map +1 -1
- package/lib/aws/queue.js +88 -90
- package/lib/aws/queue.js.map +1 -1
- package/lib/aws/table.d.ts.map +1 -1
- package/lib/aws/table.js +95 -99
- package/lib/aws/table.js.map +1 -1
- package/lib/cloudflare/account-api-token.d.ts +1 -1
- package/lib/cloudflare/account-api-token.d.ts.map +1 -1
- package/lib/cloudflare/account-api-token.js +0 -1
- package/lib/cloudflare/account-api-token.js.map +1 -1
- package/lib/cloudflare/ai-gateway.js.map +1 -1
- package/lib/cloudflare/ai.d.ts +1 -1
- package/lib/cloudflare/ai.d.ts.map +1 -1
- package/lib/cloudflare/ai.js.map +1 -1
- package/lib/cloudflare/api.d.ts +5 -5
- package/lib/cloudflare/api.d.ts.map +1 -1
- package/lib/cloudflare/api.js +52 -15
- package/lib/cloudflare/api.js.map +1 -1
- package/lib/cloudflare/auth.d.ts +24 -55
- package/lib/cloudflare/auth.d.ts.map +1 -1
- package/lib/cloudflare/auth.js +15 -72
- package/lib/cloudflare/auth.js.map +1 -1
- package/lib/cloudflare/bucket.d.ts +2 -2
- package/lib/cloudflare/bucket.d.ts.map +1 -1
- package/lib/cloudflare/bucket.js +22 -24
- package/lib/cloudflare/bucket.js.map +1 -1
- package/lib/cloudflare/bundle/alias-plugin.d.ts +6 -0
- package/lib/cloudflare/bundle/alias-plugin.d.ts.map +1 -0
- package/lib/cloudflare/bundle/alias-plugin.js +36 -0
- package/lib/cloudflare/bundle/alias-plugin.js.map +1 -0
- package/lib/cloudflare/bundle/build-failures.d.ts +12 -0
- package/lib/cloudflare/bundle/build-failures.d.ts.map +1 -0
- package/lib/cloudflare/bundle/build-failures.js +45 -0
- package/lib/cloudflare/bundle/build-failures.js.map +1 -0
- package/lib/cloudflare/bundle/bundle-worker.d.ts +7 -0
- package/lib/cloudflare/bundle/bundle-worker.d.ts.map +1 -0
- package/lib/cloudflare/bundle/bundle-worker.js +69 -0
- package/lib/cloudflare/bundle/bundle-worker.js.map +1 -0
- package/lib/cloudflare/bundle/external.d.ts +1 -0
- package/lib/cloudflare/bundle/external.d.ts.map +1 -1
- package/lib/cloudflare/bundle/external.js +8 -1
- package/lib/cloudflare/bundle/external.js.map +1 -1
- package/lib/cloudflare/bundle/local-dev-cloudflare-shim.d.ts +1 -1
- package/lib/cloudflare/bundle/local-dev-cloudflare-shim.d.ts.map +1 -1
- package/lib/cloudflare/bundle/local-dev-cloudflare-shim.js +6 -6
- package/lib/cloudflare/bundle/local-dev-cloudflare-shim.js.map +1 -1
- package/lib/cloudflare/bundle/nodejs-compat-mode.d.ts +17 -0
- package/lib/cloudflare/bundle/nodejs-compat-mode.d.ts.map +1 -0
- package/lib/cloudflare/bundle/nodejs-compat-mode.js +27 -0
- package/lib/cloudflare/bundle/nodejs-compat-mode.js.map +1 -0
- package/lib/cloudflare/bundle/{hybrid-nodejs-compat.d.ts → nodejs-compat.d.ts} +2 -2
- package/lib/cloudflare/bundle/nodejs-compat.d.ts.map +1 -0
- package/lib/cloudflare/bundle/{hybrid-nodejs-compat.js → nodejs-compat.js} +2 -2
- package/lib/cloudflare/bundle/nodejs-compat.js.map +1 -0
- package/lib/cloudflare/custom-domain.d.ts.map +1 -1
- package/lib/cloudflare/custom-domain.js +3 -5
- package/lib/cloudflare/custom-domain.js.map +1 -1
- package/lib/cloudflare/d1-database.d.ts +1 -1
- package/lib/cloudflare/d1-database.d.ts.map +1 -1
- package/lib/cloudflare/d1-database.js +70 -72
- package/lib/cloudflare/d1-database.js.map +1 -1
- package/lib/cloudflare/d1-migrations.d.ts +1 -1
- package/lib/cloudflare/d1-migrations.d.ts.map +1 -1
- package/lib/cloudflare/d1-migrations.js +2 -3
- package/lib/cloudflare/d1-migrations.js.map +1 -1
- package/lib/cloudflare/dns-records.d.ts.map +1 -1
- package/lib/cloudflare/dns-records.js +2 -4
- package/lib/cloudflare/dns-records.js.map +1 -1
- package/lib/cloudflare/kv-namespace.d.ts +1 -1
- package/lib/cloudflare/kv-namespace.d.ts.map +1 -1
- package/lib/cloudflare/kv-namespace.js +24 -27
- package/lib/cloudflare/kv-namespace.js.map +1 -1
- package/lib/cloudflare/pipeline.d.ts +1 -1
- package/lib/cloudflare/pipeline.d.ts.map +1 -1
- package/lib/cloudflare/pipeline.js +32 -34
- package/lib/cloudflare/pipeline.js.map +1 -1
- package/lib/cloudflare/queue-consumer.d.ts +1 -1
- package/lib/cloudflare/queue-consumer.d.ts.map +1 -1
- package/lib/cloudflare/queue-consumer.js +27 -33
- package/lib/cloudflare/queue-consumer.js.map +1 -1
- package/lib/cloudflare/queue.d.ts +1 -1
- package/lib/cloudflare/queue.d.ts.map +1 -1
- package/lib/cloudflare/queue.js +36 -38
- package/lib/cloudflare/queue.js.map +1 -1
- package/lib/cloudflare/r2-rest-state-store.js +4 -8
- package/lib/cloudflare/r2-rest-state-store.js.map +1 -1
- package/lib/cloudflare/types.d.ts.map +1 -1
- package/lib/cloudflare/types.js +1 -3
- package/lib/cloudflare/types.js.map +1 -1
- package/lib/cloudflare/user.d.ts +51 -0
- package/lib/cloudflare/user.d.ts.map +1 -0
- package/lib/cloudflare/user.js +62 -0
- package/lib/cloudflare/user.js.map +1 -0
- package/lib/cloudflare/vectorize-index.d.ts.map +1 -1
- package/lib/cloudflare/vectorize-index.js +37 -39
- package/lib/cloudflare/vectorize-index.js.map +1 -1
- package/lib/cloudflare/vectorize-metadata-index.d.ts +1 -1
- package/lib/cloudflare/vectorize-metadata-index.d.ts.map +1 -1
- package/lib/cloudflare/vectorize-metadata-index.js +10 -13
- package/lib/cloudflare/vectorize-metadata-index.js.map +1 -1
- package/lib/cloudflare/worker.d.ts +18 -3
- package/lib/cloudflare/worker.d.ts.map +1 -1
- package/lib/cloudflare/worker.js +11 -54
- package/lib/cloudflare/worker.js.map +1 -1
- package/lib/cloudflare/workflow.d.ts +1 -1
- package/lib/cloudflare/workflow.d.ts.map +1 -1
- package/lib/cloudflare/workflow.js.map +1 -1
- package/lib/cloudflare/zone.d.ts.map +1 -1
- package/lib/cloudflare/zone.js +48 -50
- package/lib/cloudflare/zone.js.map +1 -1
- package/lib/dns/godaddy.js +1 -1
- package/lib/dns/import-dns.js +1 -1
- package/lib/dns/import-dns.js.map +1 -1
- package/lib/env.js +7 -9
- package/lib/env.js.map +1 -1
- package/lib/esbuild/bundle.d.ts.map +1 -1
- package/lib/esbuild/bundle.js +8 -11
- package/lib/esbuild/bundle.js.map +1 -1
- package/lib/fs/copy-file.d.ts.map +1 -1
- package/lib/fs/copy-file.js +27 -29
- package/lib/fs/copy-file.js.map +1 -1
- package/lib/fs/file.d.ts +1 -1
- package/lib/fs/file.d.ts.map +1 -1
- package/lib/fs/file.js +1 -1
- package/lib/fs/file.js.map +1 -1
- package/lib/fs/folder.d.ts.map +1 -1
- package/lib/fs/folder.js +1 -3
- package/lib/fs/folder.js.map +1 -1
- package/lib/github/client.d.ts.map +1 -1
- package/lib/github/client.js +3 -5
- package/lib/github/client.js.map +1 -1
- package/lib/github/repository-environment.d.ts.map +1 -1
- package/lib/github/repository-environment.js +173 -176
- package/lib/github/repository-environment.js.map +1 -1
- package/lib/github/secret.d.ts.map +1 -1
- package/lib/github/secret.js +97 -99
- package/lib/github/secret.js.map +1 -1
- package/lib/internal/docs/providers.d.ts.map +1 -1
- package/lib/internal/docs/providers.js +5 -7
- package/lib/internal/docs/providers.js.map +1 -1
- package/lib/neon/api.js +1 -2
- package/lib/neon/api.js.map +1 -1
- package/lib/neon/project.js +2 -2
- package/lib/neon/project.js.map +1 -1
- package/lib/os/exec.d.ts +5 -0
- package/lib/os/exec.d.ts.map +1 -1
- package/lib/os/exec.js +88 -56
- package/lib/os/exec.js.map +1 -1
- package/lib/scope.d.ts +3 -0
- package/lib/scope.d.ts.map +1 -1
- package/lib/scope.js +10 -3
- package/lib/scope.js.map +1 -1
- package/lib/secret.d.ts.map +1 -1
- package/lib/secret.js +1 -3
- package/lib/secret.js.map +1 -1
- package/lib/serde.d.ts.map +1 -1
- package/lib/serde.js +13 -15
- package/lib/serde.js.map +1 -1
- package/lib/stripe/price.d.ts.map +1 -1
- package/lib/stripe/price.js +69 -73
- package/lib/stripe/price.js.map +1 -1
- package/lib/stripe/product.d.ts.map +1 -1
- package/lib/stripe/product.js +50 -52
- package/lib/stripe/product.js.map +1 -1
- package/lib/stripe/webhook.d.ts.map +1 -1
- package/lib/stripe/webhook.js +51 -53
- package/lib/stripe/webhook.js.map +1 -1
- package/lib/test/bun.d.ts +1 -1
- package/lib/test/bun.d.ts.map +1 -1
- package/lib/test/bun.js +3 -8
- package/lib/test/bun.js.map +1 -1
- package/lib/test/prune.d.ts.map +1 -1
- package/lib/test/prune.js.map +1 -1
- package/lib/util/dedent.js +4 -4
- package/lib/util/dedent.js.map +1 -1
- package/lib/web/astro.js +1 -1
- package/lib/web/shadcn.js +4 -4
- package/lib/web/shadcn.js.map +1 -1
- package/lib/web/tailwind.d.ts.map +1 -1
- package/lib/web/tailwind.js +0 -1
- package/lib/web/tailwind.js.map +1 -1
- package/lib/web/vite.js +3 -3
- package/lib/web/vitepress/home-page.d.ts.map +1 -1
- package/lib/web/vitepress/home-page.js +6 -8
- package/lib/web/vitepress/home-page.js.map +1 -1
- package/lib/web/vitepress/process-front-matter-files.js +1 -1
- package/lib/web/vitepress/process-front-matter-files.js.map +1 -1
- package/lib/web/vitepress/vitepress.js +2 -2
- package/lib/web/vitepress/vitepress.js.map +1 -1
- package/package.json +4 -1
- package/src/ai/astro-file.ts +4 -4
- package/src/ai/client.ts +4 -5
- package/src/ai/css-file.ts +4 -4
- package/src/ai/document.ts +3 -3
- package/src/ai/html-file.ts +4 -4
- package/src/ai/json-file.ts +1 -1
- package/src/ai/typescript-file.ts +4 -4
- package/src/ai/vue-file.ts +4 -4
- package/src/ai/yaml-file.ts +1 -1
- package/src/alchemy.ts +111 -104
- package/src/apply.ts +13 -6
- package/src/aws/bucket.ts +72 -75
- package/src/aws/function.ts +296 -297
- package/src/aws/oidc/github-oidc-provider.ts +1 -1
- package/src/aws/oidc/oidc-provider.ts +15 -15
- package/src/aws/policy-attachment.ts +10 -11
- package/src/aws/policy.ts +91 -94
- package/src/aws/queue.ts +111 -111
- package/src/aws/role.ts +24 -24
- package/src/aws/ses.ts +17 -17
- package/src/aws/table.ts +114 -115
- package/src/cloudflare/account-api-token.ts +11 -11
- package/src/cloudflare/ai-gateway.ts +4 -4
- package/src/cloudflare/ai.ts +1 -1
- package/src/cloudflare/api-error.ts +1 -1
- package/src/cloudflare/api.ts +70 -25
- package/src/cloudflare/assets.ts +4 -4
- package/src/cloudflare/auth.ts +49 -164
- package/src/cloudflare/bucket.ts +62 -63
- package/src/cloudflare/bundle/alias-plugin.ts +48 -0
- package/src/cloudflare/bundle/build-failures.ts +55 -0
- package/src/cloudflare/bundle/bundle-worker.ts +89 -0
- package/src/cloudflare/bundle/external.ts +9 -1
- package/src/cloudflare/bundle/local-dev-cloudflare-shim.ts +7 -6
- package/src/cloudflare/bundle/nodejs-compat-mode.ts +49 -0
- package/src/cloudflare/bundle/{hybrid-nodejs-compat.ts → nodejs-compat.ts} +10 -10
- package/src/cloudflare/custom-domain.ts +27 -28
- package/src/cloudflare/d1-database.ts +101 -102
- package/src/cloudflare/d1-migrations.ts +10 -10
- package/src/cloudflare/dns-records.ts +23 -24
- package/src/cloudflare/durable-object-namespace.ts +1 -1
- package/src/cloudflare/event-source.ts +1 -1
- package/src/cloudflare/hyperdrive.ts +3 -3
- package/src/cloudflare/kv-namespace.ts +36 -37
- package/src/cloudflare/nuxt.ts +1 -1
- package/src/cloudflare/permission-groups.ts +7 -7
- package/src/cloudflare/pipeline.ts +55 -56
- package/src/cloudflare/queue-consumer.ts +46 -53
- package/src/cloudflare/queue.ts +56 -57
- package/src/cloudflare/r2-rest-state-store.ts +11 -11
- package/src/cloudflare/redwood.ts +1 -1
- package/src/cloudflare/tanstack-start.ts +1 -1
- package/src/cloudflare/types.ts +1 -2
- package/src/cloudflare/user.ts +142 -0
- package/src/cloudflare/vectorize-index.ts +60 -61
- package/src/cloudflare/vectorize-metadata-index.ts +25 -25
- package/src/cloudflare/vite.ts +1 -1
- package/src/cloudflare/website.ts +3 -3
- package/src/cloudflare/worker.ts +83 -108
- package/src/cloudflare/workflow.ts +4 -4
- package/src/cloudflare/wrangler.json.ts +4 -4
- package/src/cloudflare/zone.ts +69 -70
- package/src/destroy.ts +4 -4
- package/src/dns/godaddy.ts +1 -1
- package/src/dns/import-dns.ts +5 -5
- package/src/encrypt.ts +6 -6
- package/src/env.ts +10 -10
- package/src/esbuild/bundle.ts +14 -15
- package/src/fs/copy-file.ts +35 -36
- package/src/fs/file-system-state-store.ts +4 -4
- package/src/fs/file.ts +9 -8
- package/src/fs/folder.ts +6 -7
- package/src/github/client.ts +15 -14
- package/src/github/repository-environment.ts +206 -210
- package/src/github/secret.ts +111 -116
- package/src/internal/docs/providers.ts +16 -17
- package/src/neon/api-error.ts +1 -1
- package/src/neon/api.ts +6 -6
- package/src/neon/project.ts +18 -17
- package/src/os/exec.ts +107 -66
- package/src/resource.ts +3 -3
- package/src/scope.ts +14 -4
- package/src/secret.ts +2 -3
- package/src/serde.ts +30 -22
- package/src/stripe/price.ts +74 -77
- package/src/stripe/product.ts +55 -56
- package/src/stripe/webhook.ts +56 -57
- package/src/test/bun.ts +9 -13
- package/src/test/prune.ts +4 -4
- package/src/util/dedent.ts +4 -4
- package/src/web/astro.ts +10 -10
- package/src/web/shadcn-component.ts +4 -4
- package/src/web/shadcn.ts +10 -10
- package/src/web/tailwind.ts +2 -3
- package/src/web/vite.ts +11 -11
- package/src/web/vitepress/config.ts +2 -2
- package/src/web/vitepress/custom-theme.ts +7 -7
- package/src/web/vitepress/dependencies.ts +4 -4
- package/src/web/vitepress/home-page.ts +8 -9
- package/src/web/vitepress/process-front-matter-files.ts +5 -5
- package/src/web/vitepress/vitepress.ts +7 -7
- package/lib/cloudflare/account-id.d.ts +0 -6
- package/lib/cloudflare/account-id.d.ts.map +0 -1
- package/lib/cloudflare/account-id.js +0 -6
- package/lib/cloudflare/account-id.js.map +0 -1
- package/lib/cloudflare/bundle/hybrid-nodejs-compat.d.ts.map +0 -1
- package/lib/cloudflare/bundle/hybrid-nodejs-compat.js.map +0 -1
- package/src/cloudflare/account-id.ts +0 -12
|
@@ -154,7 +154,7 @@ export const AiGateway = Resource(
|
|
|
154
154
|
async function (
|
|
155
155
|
this: Context<AiGateway>,
|
|
156
156
|
id: string,
|
|
157
|
-
props: AiGatewayProps = {}
|
|
157
|
+
props: AiGatewayProps = {},
|
|
158
158
|
): Promise<AiGateway> {
|
|
159
159
|
const api = await createCloudflareApi(props);
|
|
160
160
|
const gatewayPath = `/accounts/${api.accountId}/ai-gateway/gateways/${id}`;
|
|
@@ -199,7 +199,7 @@ export const AiGateway = Resource(
|
|
|
199
199
|
if (getResponse.status === 200) {
|
|
200
200
|
// Gateway exists, treat as update (PUT)
|
|
201
201
|
console.log(
|
|
202
|
-
`AI Gateway '${id}' already exists. Updating existing resource
|
|
202
|
+
`AI Gateway '${id}' already exists. Updating existing resource.`,
|
|
203
203
|
);
|
|
204
204
|
const requestBody = mapPropsToApi(id, mergedProps, false);
|
|
205
205
|
response = await api.put(gatewayPath, requestBody);
|
|
@@ -248,14 +248,14 @@ export const AiGateway = Resource(
|
|
|
248
248
|
logpushPublicKey: apiResource.logpush_public_key,
|
|
249
249
|
type: "ai_gateway",
|
|
250
250
|
});
|
|
251
|
-
}
|
|
251
|
+
},
|
|
252
252
|
);
|
|
253
253
|
|
|
254
254
|
// Helper function to map props to the API request body format
|
|
255
255
|
function mapPropsToApi(
|
|
256
256
|
id: string,
|
|
257
257
|
props: AiGatewayProps,
|
|
258
|
-
includeIdInBody
|
|
258
|
+
includeIdInBody = false,
|
|
259
259
|
): Record<string, any> {
|
|
260
260
|
const body: Record<string, any> = {};
|
|
261
261
|
if (includeIdInBody) {
|
package/src/cloudflare/ai.ts
CHANGED
package/src/cloudflare/api.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
import { alchemy } from "../alchemy.js";
|
|
1
2
|
import type { Secret } from "../secret.js";
|
|
2
3
|
import { withExponentialBackoff } from "../util/retry.js";
|
|
3
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
getCloudflareAuthHeaders,
|
|
6
|
+
type CloudflareAuthOptions,
|
|
7
|
+
} from "./auth.js";
|
|
8
|
+
import { getCloudflareUserInfo, getUserEmailFromApiKey } from "./user.js";
|
|
4
9
|
|
|
5
10
|
/**
|
|
6
11
|
* Options for Cloudflare API requests
|
|
@@ -29,11 +34,6 @@ export interface CloudflareApiOptions {
|
|
|
29
34
|
*/
|
|
30
35
|
accountId?: string;
|
|
31
36
|
|
|
32
|
-
/**
|
|
33
|
-
* Zone ID to use (overrides CLOUDFLARE_ZONE_ID env var)
|
|
34
|
-
*/
|
|
35
|
-
zoneId?: string;
|
|
36
|
-
|
|
37
37
|
/**
|
|
38
38
|
* Email to use with API Key authentication
|
|
39
39
|
* If not provided, will attempt to discover from Cloudflare API
|
|
@@ -48,16 +48,43 @@ export interface CloudflareApiOptions {
|
|
|
48
48
|
* @returns Promise resolving to a CloudflareApi instance
|
|
49
49
|
*/
|
|
50
50
|
export async function createCloudflareApi(
|
|
51
|
-
options: Partial<CloudflareApiOptions> = {}
|
|
51
|
+
options: Partial<CloudflareApiOptions> = {},
|
|
52
52
|
): Promise<CloudflareApi> {
|
|
53
|
-
const
|
|
53
|
+
const apiKey =
|
|
54
|
+
options.apiKey ??
|
|
55
|
+
(process.env.CLOUDFLARE_API_KEY
|
|
56
|
+
? alchemy.secret(process.env.CLOUDFLARE_API_KEY)
|
|
57
|
+
: undefined);
|
|
58
|
+
const apiToken =
|
|
59
|
+
options.apiToken ??
|
|
60
|
+
(process.env.CLOUDFLARE_API_TOKEN
|
|
61
|
+
? alchemy.secret(process.env.CLOUDFLARE_API_TOKEN)
|
|
62
|
+
: undefined);
|
|
63
|
+
let email = options.email ?? process.env.CLOUDFLARE_EMAIL;
|
|
64
|
+
if (apiKey && !email) {
|
|
65
|
+
email = await getUserEmailFromApiKey(apiKey.unencrypted);
|
|
66
|
+
}
|
|
67
|
+
const accountId =
|
|
68
|
+
options.accountId ??
|
|
69
|
+
process.env.CLOUDFLARE_ACCOUNT_ID ??
|
|
70
|
+
(
|
|
71
|
+
await getCloudflareUserInfo({
|
|
72
|
+
apiKey,
|
|
73
|
+
apiToken,
|
|
74
|
+
email,
|
|
75
|
+
} as CloudflareAuthOptions)
|
|
76
|
+
).accounts[0]?.id;
|
|
77
|
+
if (accountId === undefined) {
|
|
78
|
+
throw new Error(
|
|
79
|
+
"Either accountId or CLOUDFLARE_ACCOUNT_ID must be provided",
|
|
80
|
+
);
|
|
81
|
+
}
|
|
54
82
|
return new CloudflareApi({
|
|
55
83
|
baseUrl: options.baseUrl,
|
|
56
|
-
accountId
|
|
57
|
-
email
|
|
58
|
-
apiKey
|
|
59
|
-
apiToken
|
|
60
|
-
zoneId: options.zoneId,
|
|
84
|
+
accountId,
|
|
85
|
+
email,
|
|
86
|
+
apiKey,
|
|
87
|
+
apiToken,
|
|
61
88
|
});
|
|
62
89
|
}
|
|
63
90
|
|
|
@@ -67,6 +94,11 @@ export async function createCloudflareApi(
|
|
|
67
94
|
export class CloudflareApi {
|
|
68
95
|
public readonly accountId: string;
|
|
69
96
|
public readonly baseUrl: string;
|
|
97
|
+
public readonly apiKey: Secret | undefined;
|
|
98
|
+
public readonly apiToken: Secret | undefined;
|
|
99
|
+
public readonly email: string | undefined;
|
|
100
|
+
public readonly authOptions: CloudflareAuthOptions;
|
|
101
|
+
|
|
70
102
|
/**
|
|
71
103
|
* Create a new Cloudflare API client
|
|
72
104
|
* Use createCloudflareApi factory function instead of direct constructor
|
|
@@ -75,12 +107,29 @@ export class CloudflareApi {
|
|
|
75
107
|
* @param options API options
|
|
76
108
|
*/
|
|
77
109
|
constructor(
|
|
78
|
-
|
|
110
|
+
options: CloudflareApiOptions & {
|
|
79
111
|
accountId: string;
|
|
80
|
-
}
|
|
112
|
+
},
|
|
81
113
|
) {
|
|
82
114
|
this.accountId = options.accountId;
|
|
83
115
|
this.baseUrl = options.baseUrl ?? "https://api.cloudflare.com/client/v4";
|
|
116
|
+
this.apiKey = options.apiKey;
|
|
117
|
+
this.apiToken = options.apiToken;
|
|
118
|
+
this.email = options.email;
|
|
119
|
+
|
|
120
|
+
if (this.apiKey && this.apiToken) {
|
|
121
|
+
throw new Error("'apiKey' and 'apiToken' cannot both be provided");
|
|
122
|
+
} else if (this.apiKey && !this.email) {
|
|
123
|
+
throw new Error("'email' must be provided if 'apiKey' is provided");
|
|
124
|
+
}
|
|
125
|
+
this.authOptions = this.apiKey
|
|
126
|
+
? {
|
|
127
|
+
apiKey: this.apiKey,
|
|
128
|
+
email: this.email!,
|
|
129
|
+
}
|
|
130
|
+
: {
|
|
131
|
+
apiToken: this.apiToken,
|
|
132
|
+
};
|
|
84
133
|
}
|
|
85
134
|
|
|
86
135
|
/**
|
|
@@ -106,7 +155,7 @@ export class CloudflareApi {
|
|
|
106
155
|
headers = init.headers;
|
|
107
156
|
}
|
|
108
157
|
headers = {
|
|
109
|
-
...(await getCloudflareAuthHeaders(this.
|
|
158
|
+
...(await getCloudflareAuthHeaders(this.authOptions)),
|
|
110
159
|
...headers,
|
|
111
160
|
};
|
|
112
161
|
|
|
@@ -130,7 +179,7 @@ export class CloudflareApi {
|
|
|
130
179
|
// transient errors should be retried aggressively
|
|
131
180
|
(error) => error instanceof InternalError,
|
|
132
181
|
5, // Maximum 5 attempts (1 initial + 4 retries)
|
|
133
|
-
1000 // Start with 1s delay, will exponentially increase
|
|
182
|
+
1000, // Start with 1s delay, will exponentially increase
|
|
134
183
|
);
|
|
135
184
|
}
|
|
136
185
|
|
|
@@ -153,7 +202,7 @@ export class CloudflareApi {
|
|
|
153
202
|
async post(
|
|
154
203
|
path: string,
|
|
155
204
|
body: any,
|
|
156
|
-
init: RequestInit = {}
|
|
205
|
+
init: RequestInit = {},
|
|
157
206
|
): Promise<Response> {
|
|
158
207
|
const requestBody =
|
|
159
208
|
body instanceof FormData
|
|
@@ -170,7 +219,7 @@ export class CloudflareApi {
|
|
|
170
219
|
async put(
|
|
171
220
|
path: string,
|
|
172
221
|
body: any,
|
|
173
|
-
init: RequestInit = {}
|
|
222
|
+
init: RequestInit = {},
|
|
174
223
|
): Promise<Response> {
|
|
175
224
|
const requestBody = body instanceof FormData ? body : JSON.stringify(body);
|
|
176
225
|
return this.fetch(path, { ...init, method: "PUT", body: requestBody });
|
|
@@ -182,7 +231,7 @@ export class CloudflareApi {
|
|
|
182
231
|
async patch(
|
|
183
232
|
path: string,
|
|
184
233
|
body: any,
|
|
185
|
-
init: RequestInit = {}
|
|
234
|
+
init: RequestInit = {},
|
|
186
235
|
): Promise<Response> {
|
|
187
236
|
return this.fetch(path, {
|
|
188
237
|
...init,
|
|
@@ -199,8 +248,4 @@ export class CloudflareApi {
|
|
|
199
248
|
}
|
|
200
249
|
}
|
|
201
250
|
|
|
202
|
-
class InternalError extends Error {
|
|
203
|
-
constructor(message: string) {
|
|
204
|
-
super(message);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
251
|
+
class InternalError extends Error {}
|
package/src/cloudflare/assets.ts
CHANGED
|
@@ -92,7 +92,7 @@ export const Assets = Resource(
|
|
|
92
92
|
async function (
|
|
93
93
|
this: Context<Assets>,
|
|
94
94
|
id: string,
|
|
95
|
-
props: AssetsProps
|
|
95
|
+
props: AssetsProps,
|
|
96
96
|
): Promise<Assets> {
|
|
97
97
|
if (this.phase === "delete") {
|
|
98
98
|
return this.destroy();
|
|
@@ -106,7 +106,7 @@ export const Assets = Resource(
|
|
|
106
106
|
}
|
|
107
107
|
} catch (error) {
|
|
108
108
|
throw new Error(
|
|
109
|
-
`Assets directory ${props.path} does not exist or is not accessible
|
|
109
|
+
`Assets directory ${props.path} does not exist or is not accessible`,
|
|
110
110
|
);
|
|
111
111
|
}
|
|
112
112
|
|
|
@@ -137,7 +137,7 @@ export const Assets = Resource(
|
|
|
137
137
|
createdAt: this.output?.createdAt || now,
|
|
138
138
|
updatedAt: now,
|
|
139
139
|
});
|
|
140
|
-
}
|
|
140
|
+
},
|
|
141
141
|
);
|
|
142
142
|
|
|
143
143
|
// Helper functions for file operations
|
|
@@ -151,7 +151,7 @@ async function getFilesRecursively(dir: string): Promise<string[]> {
|
|
|
151
151
|
return getFilesRecursively(path);
|
|
152
152
|
}
|
|
153
153
|
return path;
|
|
154
|
-
})
|
|
154
|
+
}),
|
|
155
155
|
);
|
|
156
156
|
|
|
157
157
|
return allFiles.flat();
|
package/src/cloudflare/auth.ts
CHANGED
|
@@ -2,203 +2,88 @@ import fs from "node:fs/promises";
|
|
|
2
2
|
import os from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import type { Secret } from "../secret.js";
|
|
5
|
-
import type { CloudflareAccountId } from "./account-id.js";
|
|
6
|
-
import { handleApiError } from "./api-error.js";
|
|
7
5
|
/**
|
|
8
6
|
* Authentication options for Cloudflare API
|
|
9
7
|
*/
|
|
10
|
-
export
|
|
8
|
+
export type CloudflareAuthOptions =
|
|
9
|
+
| CloudflareApiKeyAuthOptions
|
|
10
|
+
| CloudflareApiTokenAuthOptions;
|
|
11
|
+
|
|
12
|
+
export type CloudflareApiKeyAuthOptions = {
|
|
11
13
|
/**
|
|
12
14
|
* API Key to use with API Key
|
|
13
15
|
*/
|
|
14
|
-
apiKey
|
|
15
|
-
|
|
16
|
+
apiKey: Secret;
|
|
16
17
|
/**
|
|
17
|
-
*
|
|
18
|
+
* Email to use with API Key
|
|
19
|
+
* If not provided, will attempt to discover from Cloudflare API
|
|
18
20
|
*/
|
|
19
|
-
|
|
21
|
+
email: string;
|
|
20
22
|
|
|
21
23
|
/**
|
|
22
|
-
*
|
|
23
|
-
* If not provided, will attempt to discover from Cloudflare API
|
|
24
|
+
* API Token to use with API Key
|
|
24
25
|
*/
|
|
25
|
-
|
|
26
|
-
}
|
|
26
|
+
apiToken?: undefined;
|
|
27
|
+
};
|
|
27
28
|
|
|
28
|
-
export
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
settings: {
|
|
33
|
-
enforce_twofactor: boolean;
|
|
34
|
-
api_access_enabled: null;
|
|
35
|
-
access_approval_expiry: null;
|
|
36
|
-
abuse_contact_email: null;
|
|
37
|
-
};
|
|
38
|
-
legacy_flags: {
|
|
39
|
-
enterprise_zone_quota: {
|
|
40
|
-
maximum: number;
|
|
41
|
-
current: number;
|
|
42
|
-
available: number;
|
|
43
|
-
};
|
|
44
|
-
};
|
|
29
|
+
export function isCloudflareApiKeyAuthOptions(
|
|
30
|
+
options: CloudflareAuthOptions | undefined,
|
|
31
|
+
): options is CloudflareApiKeyAuthOptions {
|
|
32
|
+
return options !== undefined && options.apiKey !== undefined;
|
|
45
33
|
}
|
|
46
34
|
|
|
47
|
-
export
|
|
35
|
+
export type CloudflareApiTokenAuthOptions = {
|
|
36
|
+
/**
|
|
37
|
+
* API Token to use with API Key
|
|
38
|
+
*/
|
|
48
39
|
apiToken?: Secret;
|
|
49
|
-
apiKey?: Secret;
|
|
50
|
-
email: string;
|
|
51
|
-
username: string;
|
|
52
|
-
accounts: CloudflareAccount[];
|
|
53
|
-
organizations: CloudflareOrganization[];
|
|
54
|
-
tokenPermissions: string[] | undefined;
|
|
55
|
-
first_name: string | null;
|
|
56
|
-
last_name: string | null;
|
|
57
|
-
telephone: string | null;
|
|
58
|
-
country: string | null;
|
|
59
|
-
zipcode: string | null;
|
|
60
|
-
two_factor_authentication_enabled: boolean;
|
|
61
|
-
two_factor_authentication_locked: boolean;
|
|
62
|
-
has_pro_zones: boolean;
|
|
63
|
-
has_business_zones: boolean;
|
|
64
|
-
has_enterprise_zones: boolean;
|
|
65
|
-
suspended: boolean;
|
|
66
|
-
betas: string[];
|
|
67
|
-
}
|
|
68
40
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
permissions: string[];
|
|
74
|
-
roles: string[];
|
|
75
|
-
}
|
|
41
|
+
/**
|
|
42
|
+
* API Key to use with API Token
|
|
43
|
+
*/
|
|
44
|
+
apiKey?: undefined;
|
|
76
45
|
|
|
77
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Email to use with API Token
|
|
48
|
+
*/
|
|
49
|
+
email?: undefined;
|
|
50
|
+
};
|
|
78
51
|
|
|
79
|
-
export
|
|
80
|
-
options: CloudflareAuthOptions
|
|
81
|
-
):
|
|
82
|
-
|
|
83
|
-
apiKey: options.apiKey?.unencrypted,
|
|
84
|
-
apiToken: options.apiToken?.unencrypted,
|
|
85
|
-
email: options.email,
|
|
86
|
-
});
|
|
87
|
-
if (userInfoCache[cacheKey]) {
|
|
88
|
-
return userInfoCache[cacheKey];
|
|
89
|
-
}
|
|
90
|
-
const headers = await getCloudflareAuthHeaders(options);
|
|
91
|
-
const user = await fetch("https://api.cloudflare.com/client/v4/user", {
|
|
92
|
-
headers,
|
|
93
|
-
});
|
|
94
|
-
if (!user.ok) {
|
|
95
|
-
if (user.status === 403) {
|
|
96
|
-
throw new Error(
|
|
97
|
-
"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?"
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
await handleApiError(user, "getting", "user", "user");
|
|
101
|
-
}
|
|
102
|
-
const accounts = await fetch(
|
|
103
|
-
"https://api.cloudflare.com/client/v4/accounts",
|
|
104
|
-
{
|
|
105
|
-
headers,
|
|
106
|
-
}
|
|
107
|
-
);
|
|
108
|
-
const userInfo: CloudflareUserInfo = {
|
|
109
|
-
...((await user.json()) as any).result,
|
|
110
|
-
accounts: ((await accounts.json()) as any).result,
|
|
111
|
-
};
|
|
112
|
-
userInfoCache[cacheKey] = userInfo;
|
|
113
|
-
return userInfo;
|
|
52
|
+
export function isCloudflareApiTokenAuthOptions(
|
|
53
|
+
options: CloudflareAuthOptions | undefined,
|
|
54
|
+
): options is CloudflareApiTokenAuthOptions {
|
|
55
|
+
return options !== undefined && options.apiToken !== undefined;
|
|
114
56
|
}
|
|
115
57
|
|
|
116
58
|
export async function getCloudflareAuthHeaders(
|
|
117
|
-
options: CloudflareAuthOptions
|
|
59
|
+
options: CloudflareAuthOptions | undefined,
|
|
118
60
|
): Promise<Record<string, string>> {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
options.apiToken?.unencrypted ?? process.env.CLOUDFLARE_API_TOKEN;
|
|
122
|
-
if (apiToken) {
|
|
61
|
+
if (isCloudflareApiKeyAuthOptions(options)) {
|
|
62
|
+
// Global API Key
|
|
123
63
|
return {
|
|
124
|
-
|
|
64
|
+
"X-Auth-Key": options.apiKey.unencrypted,
|
|
65
|
+
"X-Auth-Email": options.email,
|
|
125
66
|
};
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Check for API Key
|
|
129
|
-
const apiKey = options.apiKey?.unencrypted ?? process.env.CLOUDFLARE_API_KEY;
|
|
130
|
-
if (apiKey) {
|
|
67
|
+
} else if (isCloudflareApiTokenAuthOptions(options)) {
|
|
68
|
+
// API Token
|
|
131
69
|
return {
|
|
132
|
-
|
|
133
|
-
"X-Auth-Email":
|
|
134
|
-
options.email ??
|
|
135
|
-
process.env.CLOUDFLARE_EMAIL ??
|
|
136
|
-
(await getUserEmailFromApiKey(apiKey)),
|
|
70
|
+
Authorization: `Bearer ${options.apiToken?.unencrypted}`,
|
|
137
71
|
};
|
|
138
72
|
}
|
|
139
|
-
|
|
73
|
+
// Wrangler OAuth Token
|
|
140
74
|
const authConfig = await getRefreshedAuthConfig();
|
|
141
75
|
if (authConfig.oauth_token) {
|
|
142
76
|
return {
|
|
143
77
|
Authorization: `Bearer ${authConfig.oauth_token}`,
|
|
144
78
|
};
|
|
145
79
|
}
|
|
146
|
-
|
|
147
80
|
throw new Error(
|
|
148
|
-
"Cloudflare authentication required. Did you forget to login with `wrangler login` or set CLOUDFLARE_API_TOKEN, CLOUDFLARE_API_KEY
|
|
81
|
+
"Cloudflare authentication required. Did you forget to login with `wrangler login` or set CLOUDFLARE_API_TOKEN, CLOUDFLARE_API_KEY?",
|
|
149
82
|
);
|
|
150
83
|
}
|
|
151
84
|
|
|
152
|
-
const emailCache: Record<string, string> = {};
|
|
153
|
-
|
|
154
|
-
async function getUserEmailFromApiKey(apiKey: string): Promise<string> {
|
|
155
|
-
if (emailCache[apiKey]) {
|
|
156
|
-
return emailCache[apiKey];
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
try {
|
|
160
|
-
const baseUrl = "https://api.cloudflare.com/client/v4";
|
|
161
|
-
|
|
162
|
-
// Call the /user endpoint to get user information
|
|
163
|
-
const response = await fetch(`${baseUrl}/user`, {
|
|
164
|
-
headers: {
|
|
165
|
-
"Content-Type": "application/json",
|
|
166
|
-
"X-Auth-Key": apiKey,
|
|
167
|
-
},
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
if (!response.ok) {
|
|
171
|
-
throw new Error(
|
|
172
|
-
`Failed to get user information: ${response.status} ${response.statusText}`
|
|
173
|
-
);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
const data = (await response.json()) as {
|
|
177
|
-
success: boolean;
|
|
178
|
-
result: {
|
|
179
|
-
id: string;
|
|
180
|
-
email: string;
|
|
181
|
-
name: string;
|
|
182
|
-
[key: string]: any;
|
|
183
|
-
};
|
|
184
|
-
};
|
|
185
|
-
|
|
186
|
-
if (!data.success || !data.result || !data.result.email) {
|
|
187
|
-
throw new Error("Cloudflare API did not return valid user information");
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
emailCache[apiKey] = data.result.email;
|
|
191
|
-
return data.result.email;
|
|
192
|
-
} catch (error) {
|
|
193
|
-
console.error("Error retrieving email from Cloudflare API:", error);
|
|
194
|
-
throw new Error(
|
|
195
|
-
"Failed to automatically discover email for API Key authentication"
|
|
196
|
-
);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
85
|
async function refreshAuthToken(
|
|
201
|
-
options: WranglerConfig
|
|
86
|
+
options: WranglerConfig,
|
|
202
87
|
): Promise<WranglerConfig> {
|
|
203
88
|
const response = await fetch("https://dash.cloudflare.com/oauth2/token", {
|
|
204
89
|
method: "POST",
|
|
@@ -214,7 +99,7 @@ async function refreshAuthToken(
|
|
|
214
99
|
|
|
215
100
|
if (!response.ok) {
|
|
216
101
|
throw new Error(
|
|
217
|
-
`Failed to refresh auth token: ${response.status} ${response.statusText}
|
|
102
|
+
`Failed to refresh auth token: ${response.status} ${response.statusText}`,
|
|
218
103
|
);
|
|
219
104
|
}
|
|
220
105
|
|
|
@@ -226,7 +111,7 @@ async function refreshAuthToken(
|
|
|
226
111
|
options.oauth_token = data.access_token;
|
|
227
112
|
options.refresh_token = data.refresh_token;
|
|
228
113
|
options.expiration_time = new Date(
|
|
229
|
-
Date.now() + data.expires_in * 1000
|
|
114
|
+
Date.now() + data.expires_in * 1000,
|
|
230
115
|
).toISOString();
|
|
231
116
|
options.scopes = data.scope?.split(" ") || [];
|
|
232
117
|
|
|
@@ -280,7 +165,7 @@ async function readWranglerConfig(): Promise<WranglerConfig> {
|
|
|
280
165
|
const configPath = await findWranglerConfig();
|
|
281
166
|
try {
|
|
282
167
|
const config = (authConfigCache[configPath] ??= await parseTOML(
|
|
283
|
-
await fs.readFile(configPath, "utf-8")
|
|
168
|
+
await fs.readFile(configPath, "utf-8"),
|
|
284
169
|
));
|
|
285
170
|
config.path = configPath;
|
|
286
171
|
|
|
@@ -307,7 +192,7 @@ async function findWranglerConfig(): Promise<string> {
|
|
|
307
192
|
const environment = process.env.WRANGLER_API_ENVIRONMENT ?? "production";
|
|
308
193
|
const filePath = path.join(
|
|
309
194
|
"config",
|
|
310
|
-
`${environment === "production" ? "default.toml" : `${environment}.toml`}
|
|
195
|
+
`${environment === "production" ? "default.toml" : `${environment}.toml`}`,
|
|
311
196
|
);
|
|
312
197
|
|
|
313
198
|
const xdgAppPaths = (await import("xdg-app-paths")).default;
|
|
@@ -318,7 +203,7 @@ async function findWranglerConfig(): Promise<string> {
|
|
|
318
203
|
// Check for the .wrangler directory in root if it is not there then use the XDG compliant path.
|
|
319
204
|
wranglerConfigPath = path.join(
|
|
320
205
|
(await isDirectory(legacyConfigDir)) ? legacyConfigDir : configDir,
|
|
321
|
-
filePath
|
|
206
|
+
filePath,
|
|
322
207
|
);
|
|
323
208
|
return wranglerConfigPath;
|
|
324
209
|
}
|