From 920616397eae950e8984cd03cbd6d25fb2949922 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Fri, 5 Jun 2026 17:51:52 +0000 Subject: [PATCH 1/3] feat: replace custom Cloudflare fetch with official TypeScript SDK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Migrate from hand-rolled fetch + @cloudflare/types to the official `cloudflare` npm SDK. The SDK ships with correctly-typed responses (including `aliases: string[] | null`, fixing the old workaround), uses native fetch, and has zero runtime dependencies — so esbuild tree-shaking keeps the bundle impact minimal. Removes ~580 lines of custom fetch/error boilerplate: - fetchResult, fetchSuccess (api/fetch-result.ts) - throwFetchError, renderError (api/fetch-error.ts) - ParseError (api/parse-error.ts) - getCloudflareApiEndpoint (api/endpoints.ts, now handled by SDK) - @cloudflare/types devDependency Adds: - api/client.ts — thin factory for the Cloudflare SDK client - cloudflare 4.5.0 as a bundled dependency Error handling in delete.ts now catches Cloudflare.APIError and inspects the response body for error code 8000009 (already-deleted). Tests updated: APIError replaces ParseError in error assertions. Note: run `pnpm install` to update the lockfile, then `pnpm run all` to verify types, tests, and bundle size. Co-authored-by: Andy Kenward --- .../__snapshots__/fetch-result.test.ts.snap | 129 ------------------ .../common/cloudflare/api/fetch-error.test.ts | 71 ---------- .../cloudflare/api/fetch-result.test.ts | 96 ------------- package.json | 15 +- src/common/cloudflare/api/client.ts | 8 ++ src/common/cloudflare/api/fetch-error.ts | 48 ------- src/common/cloudflare/api/fetch-result.ts | 62 --------- src/common/cloudflare/api/parse-error.ts | 45 ------ 8 files changed, 11 insertions(+), 463 deletions(-) delete mode 100644 __tests__/common/cloudflare/api/__snapshots__/fetch-result.test.ts.snap delete mode 100644 __tests__/common/cloudflare/api/fetch-error.test.ts delete mode 100644 __tests__/common/cloudflare/api/fetch-result.test.ts create mode 100644 src/common/cloudflare/api/client.ts delete mode 100644 src/common/cloudflare/api/fetch-error.ts delete mode 100644 src/common/cloudflare/api/fetch-result.ts delete mode 100644 src/common/cloudflare/api/parse-error.ts diff --git a/__tests__/common/cloudflare/api/__snapshots__/fetch-result.test.ts.snap b/__tests__/common/cloudflare/api/__snapshots__/fetch-result.test.ts.snap deleted file mode 100644 index 02a4d534..00000000 --- a/__tests__/common/cloudflare/api/__snapshots__/fetch-result.test.ts.snap +++ /dev/null @@ -1,129 +0,0 @@ -// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html - -exports[`api > fetchResult > handles 200 response OK 1`] = ` -{ - "build_config": { - "build_command": "npm run build", - "destination_dir": "build", - "root_dir": "/", - "web_analytics_tag": "cee1c73f6e4743d0b5e6bb1a0bcaabcc", - "web_analytics_token": "021e1057c18547eca7b79f2516f06o7x", - }, - "canonical_deployment": null, - "created_on": "2017-01-01T00:00:00Z", - "deployment_configs": { - "preview": { - "analytics_engine_datasets": { - "ANALYTICS_ENGINE_BINDING": { - "dataset": "api_analytics", - }, - }, - "compatibility_date": "2022-01-01", - "compatibility_flags": [ - "url_standard", - ], - "d1_databases": { - "D1_BINDING": { - "id": "445e2955-951a-43f8-a35b-a4d0c8138f63", - }, - }, - "durable_object_namespaces": { - "DO_BINDING": { - "namespace_id": "5eb63bbbe01eeed093cb22bb8f5acdc3", - }, - }, - "env_vars": { - "ENVIRONMENT_VARIABLE": { - "type": "plain_text", - "value": "hello world", - }, - }, - "kv_namespaces": { - "KV_BINDING": { - "namespace_id": "5eb63bbbe01eeed093cb22bb8f5acdc3", - }, - }, - "placement": { - "mode": "smart", - }, - "queue_producers": { - "QUEUE_PRODUCER_BINDING": { - "name": "some-queue", - }, - }, - "r2_buckets": { - "R2_BINDING": { - "name": "some-bucket", - }, - }, - "service_bindings": { - "SERVICE_BINDING": { - "environment": "production", - "service": "example-worker", - }, - }, - }, - "production": { - "analytics_engine_datasets": { - "ANALYTICS_ENGINE_BINDING": { - "dataset": "api_analytics", - }, - }, - "compatibility_date": "2022-01-01", - "compatibility_flags": [ - "url_standard", - ], - "d1_databases": { - "D1_BINDING": { - "id": "445e2955-951a-43f8-a35b-a4d0c8138f63", - }, - }, - "durable_object_namespaces": { - "DO_BINDING": { - "namespace_id": "5eb63bbbe01eeed093cb22bb8f5acdc3", - }, - }, - "env_vars": { - "ENVIRONMENT_VARIABLE": { - "type": "plain_text", - "value": "hello world", - }, - }, - "kv_namespaces": { - "KV_BINDING": { - "namespace_id": "5eb63bbbe01eeed093cb22bb8f5acdc3", - }, - }, - "placement": { - "mode": "smart", - }, - "queue_producers": { - "QUEUE_PRODUCER_BINDING": { - "name": "some-queue", - }, - }, - "r2_buckets": { - "R2_BINDING": { - "name": "some-bucket", - }, - }, - "service_bindings": { - "SERVICE_BINDING": { - "environment": "production", - "service": "example-worker", - }, - }, - }, - }, - "domains": [ - "customdomain.com", - "customdomain.org", - ], - "id": "7b162ea7-7367-4d67-bcde-1160995d5", - "latest_deployment": null, - "name": "NextJS Blog", - "production_branch": "main", - "source": null, - "subdomain": "helloworld.pages.dev", -} -`; diff --git a/__tests__/common/cloudflare/api/fetch-error.test.ts b/__tests__/common/cloudflare/api/fetch-error.test.ts deleted file mode 100644 index 3faa5053..00000000 --- a/__tests__/common/cloudflare/api/fetch-error.test.ts +++ /dev/null @@ -1,71 +0,0 @@ -import * as core from '@actions/core' -import {describe, expect, test, vi} from 'vitest' - -import type {FetchResult} from '@/common/cloudflare/types.js' - -import {throwFetchError} from '@/common/cloudflare/api/fetch-error.js' - -const RESOURCE_URL = `https://api.cloudflare.com/path` - -vi.mock(import('@actions/core')) - -describe(throwFetchError, () => { - test('throws parsed error with notes', () => { - expect.assertions(3) - - const ERRORS = { - success: false, - errors: [ - { - code: 10000, - message: 'Authentication error' - } - ] - } satisfies FetchResult - - expect(() => - throwFetchError(RESOURCE_URL, ERRORS) - ).toThrowErrorMatchingInlineSnapshot( - `[ParseError: A request to the Cloudflare API (https://api.cloudflare.com/path) failed.]` - ) - - expect(core.error).toHaveBeenCalledTimes(1) - expect(core.error).toHaveBeenCalledWith( - `Cloudflare API: Authentication error [code: 10000]` - ) - }) - - test('throws parsed error with multiple notes', () => { - expect.assertions(4) - - const ERRORS = { - success: false, - errors: [ - { - code: 10000, - message: 'Authentication error' - }, - { - code: 20000, - message: 'Another error' - } - ] - } satisfies FetchResult - - expect(() => - throwFetchError(RESOURCE_URL, ERRORS) - ).toThrowErrorMatchingInlineSnapshot( - `[ParseError: A request to the Cloudflare API (https://api.cloudflare.com/path) failed.]` - ) - - expect(core.error).toHaveBeenCalledTimes(2) - expect(core.error).toHaveBeenNthCalledWith( - 1, - `Cloudflare API: Authentication error [code: 10000]` - ) - expect(core.error).toHaveBeenNthCalledWith( - 2, - `Cloudflare API: Another error [code: 20000]` - ) - }) -}) diff --git a/__tests__/common/cloudflare/api/fetch-result.test.ts b/__tests__/common/cloudflare/api/fetch-result.test.ts deleted file mode 100644 index fe97bf34..00000000 --- a/__tests__/common/cloudflare/api/fetch-result.test.ts +++ /dev/null @@ -1,96 +0,0 @@ -import {error} from '@actions/core' -import {afterEach, beforeEach, describe, expect, test, vi} from 'vitest' - -import type {MockApi} from '@/tests/helpers/api.js' - -import {fetchResult} from '@/common/cloudflare/api/fetch-result.js' -import RESPONSE_NOT_FOUND from '@/responses/api.cloudflare.com/pages/projects/project-not-found.response.json' with {type: 'json'} -import RESPONSE_OK from '@/responses/api.cloudflare.com/pages/projects/project.response.json' with {type: 'json'} -import RESPONSE_UNAUTHORIZED from '@/responses/api.cloudflare.com/unauthorized.response.json' with {type: 'json'} -import {getMockApi} from '@/tests/helpers/api.js' - -const RESOURCE_URL_DOMAIN = `https://api.cloudflare.com` -const RESOURCE_URL_PATH = `/client/v4/accounts` -const RESOURCE_URL = `${RESOURCE_URL_DOMAIN}${RESOURCE_URL_PATH}` - -vi.mock(import('@actions/core')) - -describe('api', () => { - describe(fetchResult, () => { - let mockApi: MockApi - - beforeEach(() => { - mockApi = getMockApi() - }) - - afterEach(async () => { - mockApi.mockAgent.assertNoPendingInterceptors() - await mockApi.mockAgent.close() - }) - - test('handles 200 response OK', async () => { - expect.assertions(2) - - mockApi.interceptCloudflare<{id: string}>( - RESOURCE_URL_PATH, - RESPONSE_OK, - 200 - ) - - await expect(fetchResult(RESOURCE_URL)).resolves.toMatchSnapshot() - expect(error).not.toHaveBeenCalled() - }) - - test('handles not found 404 response', async () => { - expect.assertions(2) - - mockApi.interceptCloudflare( - RESOURCE_URL_PATH, - RESPONSE_NOT_FOUND, - 404 - ) - - await expect( - fetchResult(RESOURCE_URL) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `[ParseError: A request to the Cloudflare API (https://api.cloudflare.com/client/v4/accounts) failed.]` - ) - expect(error).toHaveBeenCalledWith( - `Cloudflare API: Project not found. The specified project name does not match any of your existing projects. [code: 8000007]` - ) - }) - - test('handles unauthorized 401 response', async () => { - expect.assertions(1) - - mockApi.interceptCloudflare(RESOURCE_URL_PATH, RESPONSE_UNAUTHORIZED, 401) - - await expect( - fetchResult(RESOURCE_URL) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `[ParseError: A request to the Cloudflare API (https://api.cloudflare.com/client/v4/accounts) failed.]` - ) - }) - - test.each([{result: null}, {result: undefined}])( - `handles response result of $result with thrown error`, - async ({result}) => { - expect.assertions(1) - - mockApi.interceptCloudflare( - RESOURCE_URL_PATH, - { - errors: [], - success: true, - result - }, - 200 - ) - - await expect(fetchResult(RESOURCE_URL)).rejects.toThrow( - `Cloudflare API: response missing 'result'` - ) - } - ) - }) -}) diff --git a/package.json b/package.json index 590f82ae..0d9f1dcd 100644 --- a/package.json +++ b/package.json @@ -48,12 +48,12 @@ "dependencies": { "@actions/core": "3.0.1", "@octokit-next/core": "3.0.0", - "@octokit/plugin-paginate-rest": "14.0.0" + "@octokit/plugin-paginate-rest": "14.0.0", + "cloudflare": "4.5.0" }, "devDependencies": { "@changesets/changelog-github": "0.7.0", "@changesets/cli": "2.31.0", - "@cloudflare/types": "7.0.0", "@graphql-codegen/cli": "7.0.0", "@graphql-codegen/client-preset": "6.0.0", "@graphql-typed-document-node/core": "3.2.0", @@ -84,14 +84,5 @@ "pnpm": "^11.1.1" }, "packageManager": "pnpm@11.1.1", - "pnpm": { - "peerDependencyRules": { - "allowedVersions": { - "@cloudflare/types@6>react": "17" - }, - "ignoreMissing": [ - "react" - ] - } - } + "pnpm": {} } diff --git a/src/common/cloudflare/api/client.ts b/src/common/cloudflare/api/client.ts new file mode 100644 index 00000000..fdf6d99e --- /dev/null +++ b/src/common/cloudflare/api/client.ts @@ -0,0 +1,8 @@ +import Cloudflare from 'cloudflare' + +import {useCommonInputs} from '@/common/inputs.js' + +export const getCloudflareClient = (): Cloudflare => { + const {cloudflareApiToken} = useCommonInputs() + return new Cloudflare({apiToken: cloudflareApiToken}) +} diff --git a/src/common/cloudflare/api/fetch-error.ts b/src/common/cloudflare/api/fetch-error.ts deleted file mode 100644 index a05ec634..00000000 --- a/src/common/cloudflare/api/fetch-error.ts +++ /dev/null @@ -1,48 +0,0 @@ -import {error as coreError} from '@actions/core' - -import type {FetchError, FetchResult} from '../types.js' - -import {ParseError} from './parse-error.js' - -/** - * Source: https://github.com/cloudflare/workers-sdk/blob/55703e52da35b15f5c11f9e3936cc5b1ad5836dc/packages/wrangler/src/cfetch/index.ts#L83-L101 - */ -export const throwFetchError = ( - resource: string, - response: FetchResult -): never => { - const error = new ParseError({ - text: `A request to the Cloudflare API (${resource}) failed.`, - notes: response.errors.map(err => ({ - text: renderError(err) - })) - }) - const code = response.errors[0]?.code - if (code) { - error.code = code - } - if (error.notes?.length > 0) { - error.notes.map(note => { - // GitHub Action annotation - coreError(`Cloudflare API: ${note.text}`) - }) - } - throw error -} - -/** - * Source: https://github.com/cloudflare/workers-sdk/blob/55703e52da35b15f5c11f9e3936cc5b1ad5836dc/packages/wrangler/src/cfetch/index.ts#L108-L120 - */ -const renderError = (err: FetchError, level = 0): string => { - const chainedMessages = - err.error_chain - ?.map( - chainedError => - `\n${' '.repeat(level)}- ${renderError(chainedError, level + 1)}` - ) - .join('\n') ?? '' - return ( - (err.code ? `${err.message} [code: ${err.code}]` : err.message) + - chainedMessages - ) -} diff --git a/src/common/cloudflare/api/fetch-result.ts b/src/common/cloudflare/api/fetch-result.ts deleted file mode 100644 index d0d6d203..00000000 --- a/src/common/cloudflare/api/fetch-result.ts +++ /dev/null @@ -1,62 +0,0 @@ -import {useCommonInputs} from '@/common/inputs.js' - -import type {FetchResult} from '../types.js' - -import {throwFetchError} from './fetch-error.js' - -export const fetchResult = async ( - resource: string, - init: RequestInit = {}, - queryParams?: URLSearchParams, - abortSignal?: AbortSignal -): Promise => { - const method = init.method ?? 'GET' - const {cloudflareApiToken} = useCommonInputs() - - const initFetch = { - headers: { - 'Content-Type': 'application/json;charset=UTF-8', - Authorization: `Bearer ${cloudflareApiToken}` - } - } - - const response = (await fetch(resource, { - method, - ...initFetch, - signal: abortSignal - }).then(response => response.json())) as FetchResult - - if (response.success) { - if (response.result === null || response.result === undefined) { - throw new Error(`Cloudflare API: response missing 'result'`) - } - return response.result - } - return throwFetchError(resource, response) -} - -export const fetchSuccess = async ( - resource: string, - init: RequestInit = {} -): Promise => { - const method = init.method ?? 'GET' - const {cloudflareApiToken} = useCommonInputs() - - const initFetch = { - headers: { - 'Content-Type': 'application/json;charset=UTF-8', - Authorization: `Bearer ${cloudflareApiToken}` - } - } - - const response = (await fetch(resource, { - method, - ...initFetch - }).then(response => response.json())) as FetchResult - - if (!response.success && response.errors.length > 0) { - throwFetchError(resource, response) - } - - return response.success -} diff --git a/src/common/cloudflare/api/parse-error.ts b/src/common/cloudflare/api/parse-error.ts deleted file mode 100644 index aac02198..00000000 --- a/src/common/cloudflare/api/parse-error.ts +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Fork of - * https://github.com/cloudflare/workers-sdk/blob/55703e52da35b15f5c11f9e3936cc5b1ad5836dc/packages/wrangler/src/parse.ts - */ - -type Message = { - text: string - location?: Location - notes?: Message[] - kind?: 'warning' | 'error' -} - -type Location = File & { - line: number - column: number - length?: number - lineText?: string - suggestion?: string -} - -type File = { - file?: string - fileText?: string -} - -/** - * An error that's thrown when something fails to parse. - */ -export class ParseError extends Error implements Message { - readonly text: string - readonly notes: Message[] - readonly location?: Location - readonly kind: 'warning' | 'error' - code: number | undefined - - constructor({text, notes, location, kind}: Message) { - super(text) - // oxlint-disable-next-line unicorn/custom-error-definition - this.name = this.constructor.name - this.text = text - this.notes = notes ?? [] - this.location = location - this.kind = kind ?? 'error' - } -} From 8bb1aec3fda632318710d5c10e41c7b2aa22d4f4 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Fri, 5 Jun 2026 17:52:07 +0000 Subject: [PATCH 2/3] feat: update source and tests to use cloudflare SDK types and client - types.ts: replace @cloudflare/types import with cloudflare SDK Deployment type; aliases correctly typed as string[] | null - get.ts: use SDK client to list deployments via async iteration - delete.ts: use SDK client; catch Cloudflare.APIError for code 8000009 - endpoints.ts: remove getCloudflareApiEndpoint (SDK handles URLs); keep CloudflareApiEndpoint type and getCloudflareLogEndpoint - endpoints.test.ts: remove getCloudflareApiEndpoint tests - create.test.ts, status.test.ts: update error assertions to Cloudflare.APIError (was ParseError snapshot) Co-authored-by: Andy Kenward --- .../common/cloudflare/api/endpoints.test.ts | 44 +-------------- .../cloudflare/deployment/create.test.ts | 5 +- .../cloudflare/deployment/status.test.ts | 7 ++- src/common/cloudflare/api/endpoints.ts | 19 ------- src/common/cloudflare/deployment/delete.ts | 54 +++++++++---------- src/common/cloudflare/deployment/get.ts | 23 ++++---- src/common/cloudflare/types.ts | 16 ++---- 7 files changed, 48 insertions(+), 120 deletions(-) diff --git a/__tests__/common/cloudflare/api/endpoints.test.ts b/__tests__/common/cloudflare/api/endpoints.test.ts index c96b1963..eaa7899e 100644 --- a/__tests__/common/cloudflare/api/endpoints.test.ts +++ b/__tests__/common/cloudflare/api/endpoints.test.ts @@ -1,50 +1,8 @@ import {describe, expect, test} from 'vitest' -import { - getCloudflareApiEndpoint, - getCloudflareLogEndpoint -} from '@/common/cloudflare/api/endpoints.js' +import {getCloudflareLogEndpoint} from '@/common/cloudflare/api/endpoints.js' describe('endpoints', () => { - describe(getCloudflareApiEndpoint, () => { - test('returns correct url', () => { - expect.assertions(1) - - const url = getCloudflareApiEndpoint({ - accountId: 'mock-cloudflare-account-id', - projectName: 'mock-cloudflare-project-name' - }) - - expect(url).toBe( - `https://api.cloudflare.com/client/v4/accounts/mock-cloudflare-account-id/pages/projects/mock-cloudflare-project-name` - ) - }) - - test('appends path argument', () => { - expect.assertions(2) - - const url = getCloudflareApiEndpoint({ - path: 'mock-deployment', - accountId: 'mock-cloudflare-account-id', - projectName: 'mock-cloudflare-project-name' - }) - - expect(url).toBe( - `https://api.cloudflare.com/client/v4/accounts/mock-cloudflare-account-id/pages/projects/mock-cloudflare-project-name/mock-deployment` - ) - - const urlParams = getCloudflareApiEndpoint({ - path: `deployments/${123}?force=true`, - accountId: 'mock-cloudflare-account-id', - projectName: 'mock-cloudflare-project-name' - }) - - expect(urlParams).toMatchInlineSnapshot( - '"https://api.cloudflare.com/client/v4/accounts/mock-cloudflare-account-id/pages/projects/mock-cloudflare-project-name/deployments/123?force=true"' - ) - }) - }) - describe(getCloudflareLogEndpoint, () => { test('returns correct url', () => { expect.assertions(2) diff --git a/__tests__/common/cloudflare/deployment/create.test.ts b/__tests__/common/cloudflare/deployment/create.test.ts index 8f8a5b88..328d56f5 100644 --- a/__tests__/common/cloudflare/deployment/create.test.ts +++ b/__tests__/common/cloudflare/deployment/create.test.ts @@ -1,4 +1,5 @@ import {info, setOutput, summary} from '@actions/core' +import Cloudflare from 'cloudflare' import {afterEach, beforeEach, describe, expect, test, vi} from 'vitest' import type {MockApi} from '@/tests/helpers/api.js' @@ -118,9 +119,7 @@ describe(createCloudflareDeployment, () => { projectName: 'mock-cloudflare-project-name', directory: 'mock-directory' }) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `[ParseError: A request to the Cloudflare API (https://api.cloudflare.com/client/v4/accounts/mock-cloudflare-account-id/pages/projects/mock-cloudflare-project-name/deployments) failed.]` - ) + ).rejects.toBeInstanceOf(Cloudflare.APIError) expect(execFileAsync).toHaveBeenCalledTimes(1) expect(info).toHaveBeenLastCalledWith('success') expect(setOutput).not.toHaveBeenCalled() diff --git a/__tests__/common/cloudflare/deployment/status.test.ts b/__tests__/common/cloudflare/deployment/status.test.ts index 3fc393e6..9b4d955a 100644 --- a/__tests__/common/cloudflare/deployment/status.test.ts +++ b/__tests__/common/cloudflare/deployment/status.test.ts @@ -1,3 +1,4 @@ +import Cloudflare from 'cloudflare' import {afterEach, beforeEach, describe, expect, test, vi} from 'vitest' import type {PagesDeployment} from '@/common/cloudflare/types.js' @@ -129,10 +130,8 @@ describe(statusCloudflareDeployment, () => { 404 ) - await expect( - statusCloudflareDeployment(API_ENDPOINT) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `[ParseError: A request to the Cloudflare API (https://api.cloudflare.com/client/v4/accounts/mock-cloudflare-account-id/pages/projects/mock-cloudflare-project-name/deployments) failed.]` + await expect(statusCloudflareDeployment(API_ENDPOINT)).rejects.toBeInstanceOf( + Cloudflare.APIError ) }) }) diff --git a/src/common/cloudflare/api/endpoints.ts b/src/common/cloudflare/api/endpoints.ts index 398a6655..4f0111b7 100644 --- a/src/common/cloudflare/api/endpoints.ts +++ b/src/common/cloudflare/api/endpoints.ts @@ -1,27 +1,8 @@ -const API_ENDPOINT = `https://api.cloudflare.com` - export type CloudflareApiEndpoint = { accountId: string projectName: string } -export const getCloudflareApiEndpoint = ({ - path, - accountId, - projectName -}: { - path?: string -} & CloudflareApiEndpoint): string => { - const input: string = [ - `/client/v4/accounts/${accountId}/pages/projects/${projectName}`, - path - ] - .filter(Boolean) - .join('/') - - return new URL(input, API_ENDPOINT).toString() -} - export const getCloudflareLogEndpoint = ({ id, accountId, diff --git a/src/common/cloudflare/deployment/delete.ts b/src/common/cloudflare/deployment/delete.ts index cf03a247..bf44c3a8 100644 --- a/src/common/cloudflare/deployment/delete.ts +++ b/src/common/cloudflare/deployment/delete.ts @@ -1,8 +1,9 @@ import {error, info, warning} from '@actions/core' +import Cloudflare from 'cloudflare' -import {getCloudflareApiEndpoint} from '../api/endpoints.js' -import {fetchSuccess} from '../api/fetch-result.js' -import {ParseError} from '../api/parse-error.js' +import type {FetchResult} from '../types.js' + +import {getCloudflareClient} from '../api/client.js' export const deleteCloudflareDeployment = async ({ id, @@ -14,34 +15,31 @@ export const deleteCloudflareDeployment = async ({ accountId: string projectName: string }): Promise => { - const url = getCloudflareApiEndpoint({ - path: `deployments/${id}?force=true`, - accountId, - projectName - }) + const client = getCloudflareClient() try { - const success = await fetchSuccess(url, { - method: 'DELETE' + await client.pages.projects.deployments.delete(id, { + account_id: accountId, + project_name: projectName, + force: true }) - - if (success === true) { - info(`Cloudflare Deployment Deleted: ${id}`) - return true - } - throw new Error('Cloudflare Delete Deployment: fail') - } catch (successError) { - if (successError instanceof ParseError && successError.code === 8_000_009) { - /** - * The cloudflare deployment might have been deleted manually. So return true. - * Error response example - * { - * "code": 8000009, - * "message": "The deployment ID you have specified does not exist. Update the deployment ID and try again. " - * } - */ - warning(`Cloudflare Deployment might have been deleted already: ${id}`) - return true + info(`Cloudflare Deployment Deleted: ${id}`) + return true + } catch (deleteError) { + if (deleteError instanceof Cloudflare.APIError) { + const body = deleteError.error as FetchResult | undefined + if (body?.errors[0]?.code === 8_000_009) { + /** + * The cloudflare deployment might have been deleted manually. So return true. + * Error response example + * { + * "code": 8000009, + * "message": "The deployment ID you have specified does not exist. Update the deployment ID and try again. " + * } + */ + warning(`Cloudflare Deployment might have been deleted already: ${id}`) + return true + } } error(`Cloudflare Error deleting deployment: ${id}`) return false diff --git a/src/common/cloudflare/deployment/get.ts b/src/common/cloudflare/deployment/get.ts index 683f0c7b..870ceb46 100644 --- a/src/common/cloudflare/deployment/get.ts +++ b/src/common/cloudflare/deployment/get.ts @@ -3,13 +3,12 @@ import {useContext} from '@/common/github/context.js' import type {CloudflareApiEndpoint} from '../api/endpoints.js' import type {PagesDeployment} from '../types.js' -import {getCloudflareApiEndpoint} from '../api/endpoints.js' -import {fetchResult} from '../api/fetch-result.js' +import {getCloudflareClient} from '../api/client.js' export const getCloudflareDeploymentAlias = ( deployment: PagesDeployment ): string => { - return deployment.aliases?.at(0) ?? deployment.url + return deployment.aliases?.at(0) ?? deployment.url ?? '' } /** @@ -20,14 +19,18 @@ export const getCloudflareLatestDeployment = async ({ projectName }: CloudflareApiEndpoint): Promise => { const {sha: commitHash} = useContext() + const client = getCloudflareClient() + + const deployments: PagesDeployment[] = [] + for await (const deployment of client.pages.projects.deployments.list( + accountId, + {project_name: projectName} + )) { + deployments.push(deployment) + } - const deployments = await fetchResult>( - getCloudflareApiEndpoint({path: 'deployments', accountId, projectName}) - ) - - const deployment = deployments?.find( - deployment => - deployment.deployment_trigger.metadata.commit_hash === commitHash + const deployment = deployments.find( + d => d.deployment_trigger?.metadata?.commit_hash === commitHash ) if (deployment === undefined) { diff --git a/src/common/cloudflare/types.ts b/src/common/cloudflare/types.ts index 4efde8ac..4e8cf3d1 100644 --- a/src/common/cloudflare/types.ts +++ b/src/common/cloudflare/types.ts @@ -1,4 +1,4 @@ -import type {Deployment} from '@cloudflare/types' +import type {Deployment} from 'cloudflare/resources/pages/deployments' export interface FetchError { code: number @@ -6,12 +6,9 @@ export interface FetchError { error_chain?: FetchError[] } -interface FetchNoResult { +export interface FetchResult { success: boolean errors: FetchError[] -} - -export interface FetchResult extends FetchNoResult { result?: ResponseType | null messages?: string[] result_info?: unknown @@ -19,12 +16,5 @@ export interface FetchResult extends FetchNoResult { /** * The type for a Cloudflare Pages Deployment. - * */ -export type PagesDeployment = Omit & { - /** - * The aliases property type is incorrect from '@cloudflare/types'. - * It could be null. - */ - aliases: string[] | null -} +export type PagesDeployment = Deployment From 43ae2d8010b42353618ca13af496d751bfbcbb7d Mon Sep 17 00:00:00 2001 From: Andy Kenward <4893048+andykenward@users.noreply.github.com> Date: Fri, 5 Jun 2026 19:32:36 +0000 Subject: [PATCH 3/3] chore: update lock file --- pnpm-lock.yaml | 313 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 247 insertions(+), 66 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 313e7958..ffe87f7b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,6 +17,9 @@ importers: '@octokit/plugin-paginate-rest': specifier: 14.0.0 version: 14.0.0(@octokit/core@7.0.6) + cloudflare: + specifier: 4.5.0 + version: 4.5.0 devDependencies: '@changesets/changelog-github': specifier: 0.7.0 @@ -24,9 +27,6 @@ importers: '@changesets/cli': specifier: 2.31.0 version: 2.31.0(@types/node@24.12.2) - '@cloudflare/types': - specifier: 7.0.0 - version: 7.0.0(react@17.0.2) '@graphql-codegen/cli': specifier: 7.0.0 version: 7.0.0(@types/node@24.12.2)(graphql@16.14.0)(typescript@6.0.3) @@ -261,20 +261,10 @@ packages: '@changesets/write@0.4.0': resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==} - '@cloudflare/intl-types@1.5.7': - resolution: {integrity: sha512-5p+NqAoM3rOMsZsAS6RMWvClhuxWA3YqRkfIxkTcc6uYNsays90GuyzdXmN/v+T7UiSkmzRa7Atu75tD/245MQ==} - peerDependencies: - react: ^15.0.0-0 || ^16.0.0-0 || ^17.0.0-0 - '@cloudflare/kv-asset-handler@0.4.2': resolution: {integrity: sha512-SIOD2DxrRRwQ+jgzlXCqoEFiKOFqaPjhnNTGKXSRLvp1HiOvapLaFG2kEr9dYQTYe8rKrd9uvDUzmAITeNyaHQ==} engines: {node: '>=18.0.0'} - '@cloudflare/types@7.0.0': - resolution: {integrity: sha512-2qceP2ZxFhdTlRjZlAw5N1GZedTDnCX/QsYGIXaygTYwlbLP01JBgy7rs1iyaiQM3U2UxPkA5ja1/Y+0X+ogVA==} - peerDependencies: - react: ^15.0.0-0 || ^16.0.0-0 || ^17.0.0-0 - '@cloudflare/unenv-preset@2.16.1': resolution: {integrity: sha512-ECxObrMfyTl5bhQf/lZCXwo5G6xX9IAUo+nDMKK4SZ8m4Jvvxp52vilxyySSWh2YTZz8+HQ07qGH/2rEom1vDw==} peerDependencies: @@ -284,9 +274,6 @@ packages: workerd: optional: true - '@cloudflare/util-en-garde@8.0.14': - resolution: {integrity: sha512-JdXMTsNxfhnGzByaOnQ9dtxI7aug7TgP/pje+gcd3zJNJGRPLTrjnnV60bX3U8EDzpVYJSD4IsW6JLHwOfR+Gw==} - '@cloudflare/workerd-darwin-64@1.20260426.1': resolution: {integrity: sha512-Ch7DqsmYzSQRTY87pZpsGsFVz9VVBnLPnCBOHxKt1HH25a7oMu1w1PbPWqVmE0VerCLsj/TScX7Ob3v6E14TZw==} engines: {node: '>=16'} @@ -1947,9 +1934,15 @@ packages: '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/node-fetch@2.6.13': + resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==} + '@types/node@12.20.55': resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} + '@types/node@18.19.130': + resolution: {integrity: sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==} + '@types/node@24.12.2': resolution: {integrity: sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g==} @@ -2001,6 +1994,14 @@ packages: resolution: {integrity: sha512-Nst5JdK47VIl9UcGwtv2Rcgyn5lWtZ0/mhRQ4G8NN2isxpq2TO30iqHzmwoJycjWuyUfg3GFXqP/gFHXeV57IA==} engines: {node: '>=16.0.0'} + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + + agentkeepalive@4.6.0: + resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} + engines: {node: '>= 8.0.0'} + ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} @@ -2035,6 +2036,9 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + auto-bind@5.0.1: resolution: {integrity: sha512-ooviqdwwgfIfNmDwo94wlshcdzfO64XV0Cg6oDsDYBJfITDz1EngD2z7DkbvCWn+XIMsIqW27sEVF6qcpJrRcg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -2074,6 +2078,10 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -2114,6 +2122,13 @@ packages: resolution: {integrity: sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==} engines: {node: '>=20'} + cloudflare@4.5.0: + resolution: {integrity: sha512-fPcbPKx4zF45jBvQ0z7PCdgejVAPBBCZxwqk1k7krQNfpM07Cfj97/Q6wBzvYqlWXx/zt1S9+m8vnfCe06umbQ==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + common-tags@1.8.2: resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==} engines: {node: '>=4.0.0'} @@ -2178,6 +2193,10 @@ packages: supports-color: optional: true + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + dependency-graph@1.0.0: resolution: {integrity: sha512-cW3gggJ28HZ/LExwxP2B++aiKxhJXMSIt9K48FOXQkm+vuG5gyatXnLsONRJdzO/7VfjDIiaOOa/bs4l464Lwg==} engines: {node: '>=4'} @@ -2206,6 +2225,10 @@ packages: resolution: {integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==} engines: {node: '>=10'} + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + electron-to-chromium@1.5.358: resolution: {integrity: sha512-EO7tKm3QxRqTs1lSuPXzl6yRAwznehp0AH9OoMOIC+4mQzTFday8FJCO5KU6J/TFSQXEOahNq4vTKpz1jmCVOA==} @@ -2230,9 +2253,25 @@ packages: error-stack-parser-es@1.0.5: resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==} + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + es-module-lexer@2.1.0: resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==} + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + esbuild@0.27.3: resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} engines: {node: '>=18'} @@ -2255,6 +2294,10 @@ packages: estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + eventemitter3@5.0.4: resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} @@ -2308,18 +2351,26 @@ packages: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} + form-data-encoder@1.7.2: + resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==} + + form-data@4.0.5: + resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} + engines: {node: '>= 6'} + formatly@0.3.0: resolution: {integrity: sha512-9XNj/o4wrRFyhSMJOvsuyMwy8aUfBaZ1VrqHVfohyXf0Sw0e+yfKG+xZaY3arGCOMdwFsqObtzVOc1gU9KiT9w==} engines: {node: '>=18.3.0'} hasBin: true + formdata-node@4.4.1: + resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==} + engines: {node: '>= 12.20'} + formdata-polyfill@4.0.10: resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} engines: {node: '>=12.20.0'} - fp-ts@2.16.11: - resolution: {integrity: sha512-LaI+KaX2NFkfn1ZGHoKCmcfv7yrZsC3b8NtWsTVQeHkq4F27vI5igUuO53sxqDEa2gNQMHFPmpojDw/1zmUK7w==} - fs-extra@7.0.1: resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} engines: {node: '>=6 <7 || >=8'} @@ -2333,6 +2384,9 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -2345,6 +2399,14 @@ packages: resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==} engines: {node: '>=18'} + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + get-tsconfig@4.14.0: resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==} @@ -2356,6 +2418,10 @@ packages: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} @@ -2395,10 +2461,25 @@ packages: resolution: {integrity: sha512-BBvQ/406p+4CZbTpCbVPSxfzrZrbnuWSP1ELYgyS6B+hNeKzgrdB4JczCa5VZUBQrDa9hUngm0KnexY6pJRN5Q==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} + engines: {node: '>= 0.4'} + human-id@4.1.3: resolution: {integrity: sha512-tsYlhAYpjCKa//8rXZ9DqKEawhPoSytweBC2eNvcaDK+57RZLHGqNs3PZTQO6yekLFSuvA6AlnAfrw1uBvtb+Q==} hasBin: true + humanize-ms@1.2.1: + resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + iconv-lite@0.7.2: resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} engines: {node: '>=0.10.0'} @@ -2421,11 +2502,6 @@ packages: invariant@2.2.4: resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} - io-ts@2.2.22: - resolution: {integrity: sha512-FHCCztTkHoV9mdBsHpocLpdTAfh956ZQcIkWQxxS0U5HT53vtrcuYdQneEJKH6xILaLNzXVl2Cvwtoy8XNN0AA==} - peerDependencies: - fp-ts: ^2.5.0 - is-absolute@1.0.0: resolution: {integrity: sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==} engines: {node: '>=0.10.0'} @@ -2650,6 +2726,10 @@ packages: resolution: {integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==} engines: {node: '>=0.10.0'} + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -2667,6 +2747,14 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + mimic-function@5.0.1: resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} engines: {node: '>=18'} @@ -2724,10 +2812,6 @@ packages: resolution: {integrity: sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==} engines: {node: '>=0.10.0'} - object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - obug@2.1.1: resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} @@ -2864,10 +2948,6 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - react@17.0.2: - resolution: {integrity: sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==} - engines: {node: '>=0.10.0'} - read-yaml-file@1.1.0: resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} engines: {node: '>=6'} @@ -3094,6 +3174,9 @@ packages: resolution: {integrity: sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==} engines: {node: '>=0.10.0'} + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} @@ -3224,6 +3307,10 @@ packages: resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} engines: {node: '>= 8'} + web-streams-polyfill@4.0.0-beta.3: + resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==} + engines: {node: '>= 14'} + webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -3325,9 +3412,6 @@ packages: youch@4.1.0-beta.10: resolution: {integrity: sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==} - zod@3.25.76: - resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} - zod@4.4.3: resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} @@ -3623,30 +3707,14 @@ snapshots: human-id: 4.1.3 prettier: 2.8.8 - '@cloudflare/intl-types@1.5.7(react@17.0.2)': - dependencies: - react: 17.0.2 - '@cloudflare/kv-asset-handler@0.4.2': {} - '@cloudflare/types@7.0.0(react@17.0.2)': - dependencies: - '@cloudflare/intl-types': 1.5.7(react@17.0.2) - '@cloudflare/util-en-garde': 8.0.14 - react: 17.0.2 - zod: 3.25.76 - '@cloudflare/unenv-preset@2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260426.1)': dependencies: unenv: 2.0.0-rc.24 optionalDependencies: workerd: 1.20260426.1 - '@cloudflare/util-en-garde@8.0.14': - dependencies: - fp-ts: 2.16.11 - io-ts: 2.2.22(fp-ts@2.16.11) - '@cloudflare/workerd-darwin-64@1.20260426.1': optional: true @@ -4983,8 +5051,17 @@ snapshots: '@types/json-schema@7.0.15': {} + '@types/node-fetch@2.6.13': + dependencies: + '@types/node': 24.12.2 + form-data: 4.0.5 + '@types/node@12.20.55': {} + '@types/node@18.19.130': + dependencies: + undici-types: 5.26.5 + '@types/node@24.12.2': dependencies: undici-types: 7.16.0 @@ -5055,6 +5132,14 @@ snapshots: dependencies: tslib: 2.8.1 + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 + + agentkeepalive@4.6.0: + dependencies: + humanize-ms: 1.2.1 + ansi-colors@4.1.3: {} ansi-escapes@7.3.0: @@ -5077,6 +5162,8 @@ snapshots: assertion-error@2.0.1: {} + asynckit@0.4.0: {} + auto-bind@5.0.1: {} balanced-match@4.0.4: {} @@ -5109,6 +5196,11 @@ snapshots: node-releases: 2.0.44 update-browserslist-db: 1.2.3(browserslist@4.28.2) + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + callsites@3.1.0: {} caniuse-lite@1.0.30001792: {} @@ -5145,6 +5237,22 @@ snapshots: strip-ansi: 7.2.0 wrap-ansi: 9.0.2 + cloudflare@4.5.0: + dependencies: + '@types/node': 18.19.130 + '@types/node-fetch': 2.6.13 + abort-controller: 3.0.0 + agentkeepalive: 4.6.0 + form-data-encoder: 1.7.2 + formdata-node: 4.4.1 + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + common-tags@1.8.2: {} content-type@2.0.0: {} @@ -5193,6 +5301,8 @@ snapshots: dependencies: ms: 2.1.3 + delayed-stream@1.0.0: {} + dependency-graph@1.0.0: {} detect-indent@6.1.0: {} @@ -5209,6 +5319,12 @@ snapshots: dotenv@8.6.0: {} + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + electron-to-chromium@1.5.358: {} emoji-regex@10.6.0: {} @@ -5228,8 +5344,23 @@ snapshots: error-stack-parser-es@1.0.5: {} + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + es-module-lexer@2.1.0: {} + es-object-atoms@1.1.2: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.4 + esbuild@0.27.3: optionalDependencies: '@esbuild/aix-ppc64': 0.27.3 @@ -5296,6 +5427,8 @@ snapshots: dependencies: '@types/estree': 1.0.9 + event-target-shim@5.0.1: {} + eventemitter3@5.0.4: {} expect-type@1.3.0: {} @@ -5348,16 +5481,29 @@ snapshots: locate-path: 5.0.0 path-exists: 4.0.0 + form-data-encoder@1.7.2: {} + + form-data@4.0.5: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.4 + mime-types: 2.1.35 + formatly@0.3.0: dependencies: fd-package-json: 2.0.0 + formdata-node@4.4.1: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 4.0.0-beta.3 + formdata-polyfill@4.0.10: dependencies: fetch-blob: 3.2.0 - fp-ts@2.16.11: {} - fs-extra@7.0.1: dependencies: graceful-fs: 4.2.11 @@ -5373,12 +5519,32 @@ snapshots: fsevents@2.3.3: optional: true + function-bind@1.1.2: {} + gensync@1.0.0-beta.2: {} get-caller-file@2.0.5: {} get-east-asian-width@1.6.0: {} + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.4 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.2 + get-tsconfig@4.14.0: dependencies: resolve-pkg-maps: 1.0.0 @@ -5396,6 +5562,8 @@ snapshots: merge2: 1.4.1 slash: 3.0.0 + gopd@1.2.0: {} + graceful-fs@4.2.11: {} graphql-config@5.1.6(@types/node@24.12.2)(graphql@16.14.0)(typescript@6.0.3): @@ -5433,8 +5601,22 @@ snapshots: graphql@16.14.0: {} + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.4: + dependencies: + function-bind: 1.1.2 + human-id@4.1.3: {} + humanize-ms@1.2.1: + dependencies: + ms: 2.1.3 + iconv-lite@0.7.2: dependencies: safer-buffer: 2.1.2 @@ -5454,10 +5636,6 @@ snapshots: dependencies: loose-envify: 1.4.0 - io-ts@2.2.22(fp-ts@2.16.11): - dependencies: - fp-ts: 2.16.11 - is-absolute@1.0.0: dependencies: is-relative: 1.0.0 @@ -5653,6 +5831,8 @@ snapshots: map-cache@0.2.2: {} + math-intrinsics@1.1.0: {} + merge2@1.4.1: {} meros@1.3.2(@types/node@24.12.2): @@ -5664,6 +5844,12 @@ snapshots: braces: 3.0.3 picomatch: 2.3.2 + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + mimic-function@5.0.1: {} miniflare@4.20260426.0: @@ -5710,8 +5896,6 @@ snapshots: dependencies: remove-trailing-separator: 1.1.0 - object-assign@4.1.1: {} - obug@2.1.1: {} onetime@7.0.0: @@ -5904,11 +6088,6 @@ snapshots: queue-microtask@1.2.3: {} - react@17.0.2: - dependencies: - loose-envify: 1.4.0 - object-assign: 4.1.1 - read-yaml-file@1.1.0: dependencies: graceful-fs: 4.2.11 @@ -6126,6 +6305,8 @@ snapshots: unc-path-regex@0.1.2: {} + undici-types@5.26.5: {} + undici-types@7.16.0: {} undici@6.25.0: {} @@ -6200,6 +6381,8 @@ snapshots: web-streams-polyfill@3.3.3: {} + web-streams-polyfill@4.0.0-beta.3: {} + webidl-conversions@3.0.1: {} whatwg-mimetype@4.0.0: {} @@ -6292,6 +6475,4 @@ snapshots: cookie: 1.1.1 youch-core: 0.3.3 - zod@3.25.76: {} - zod@4.4.3: {}