From 560f95081533601e094d697a32be2f4912785340 Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Wed, 23 Jul 2025 15:20:03 -0500 Subject: [PATCH 001/245] feat(cli): create deployment (#2491) * feat(cli): create deployment * chore: use conf to read from file * refactor: update how to call conf * refactor: create class for store config * feat: add get/set to config * fix: remove describe import * fix: error message * chore: rename projectId to projectUuid --- packages/cli/package.json | 1 + packages/cli/src/commands/deploy.ts | 158 ++++++++++++------ packages/cli/src/lib/project-config.ts | 35 ++++ packages/cli/tests/commands/deploy.spec.ts | 36 ++-- packages/cli/tests/lib/project-config.spec.ts | 57 +++++++ packages/cli/tests/mocks/handlers.ts | 11 +- pnpm-lock.yaml | 105 ++---------- 7 files changed, 244 insertions(+), 159 deletions(-) create mode 100644 packages/cli/src/lib/project-config.ts create mode 100644 packages/cli/tests/lib/project-config.spec.ts diff --git a/packages/cli/package.json b/packages/cli/package.json index b4a1e259f3..bd510769cf 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -25,6 +25,7 @@ "adm-zip": "^0.5.16", "chalk": "^5.3.0", "commander": "^14.0.0", + "conf": "^13.1.0", "consola": "^3.4.2", "nypm": "^0.6.0", "zod": "^4.0.5" diff --git a/packages/cli/src/commands/deploy.ts b/packages/cli/src/commands/deploy.ts index 3e7e7c511a..98936310c2 100644 --- a/packages/cli/src/commands/deploy.ts +++ b/packages/cli/src/commands/deploy.ts @@ -5,6 +5,8 @@ import { access, readdir, readFile } from 'node:fs/promises'; import { join } from 'node:path'; import { z } from 'zod'; +import { ProjectConfig } from '../lib/project-config'; + const UploadSignatureSchema = z.object({ data: z.object({ upload_url: z.url(), @@ -12,6 +14,12 @@ const UploadSignatureSchema = z.object({ }), }); +const CreateDeploymentSchema = z.object({ + data: z.object({ + deployment_uuid: z.uuid(), + }), +}); + export const generateBundleZip = async (rootDir: string) => { consola.info('Generating bundle...'); @@ -21,16 +29,14 @@ export const generateBundleZip = async (rootDir: string) => { try { await access(distDir); } catch { - consola.error(`Dist directory not found: ${distDir}`); - process.exit(1); + throw new Error(`Dist directory not found: ${distDir}`); } // Check if .bigcommerce/dist is not empty const buildDirContents = await readdir(distDir); if (buildDirContents.length === 0) { - consola.error(`Dist directory is empty: ${distDir}`); - process.exit(1); + throw new Error(`Dist directory is empty: ${distDir}`); } const outputZip = join(distDir, 'bundle.zip'); @@ -51,35 +57,29 @@ export const generateUploadSignature = async ( ) => { consola.info('Generating upload signature...'); - try { - const response = await fetch( - `https://${apiHost}/stores/${storeHash}/v3/headless/deployments/uploads`, - { - method: 'POST', - headers: { - 'X-Auth-Token': accessToken, - 'Content-Type': 'application/json', - Accept: 'application/json', - }, - body: JSON.stringify({}), + const response = await fetch( + `https://${apiHost}/stores/${storeHash}/v3/headless/deployments/uploads`, + { + method: 'POST', + headers: { + 'X-Auth-Token': accessToken, + 'Content-Type': 'application/json', + Accept: 'application/json', }, - ); + body: JSON.stringify({}), + }, + ); - if (!response.ok) { - consola.error(`Failed to fetch upload signature: ${response.status} ${response.statusText}`); - process.exit(1); - } + if (!response.ok) { + throw new Error(`Failed to fetch upload signature: ${response.status} ${response.statusText}`); + } - const res: unknown = await response.json(); - const { data } = UploadSignatureSchema.parse(res); + const res: unknown = await response.json(); + const { data } = UploadSignatureSchema.parse(res); - consola.success('Upload signature generated.'); + consola.success('Upload signature generated.'); - return data; - } catch (error) { - consola.error('Error in generateUploadSignature:', error); - process.exit(1); - } + return data; }; export const uploadBundleZip = async (uploadUrl: string, rootDir: string) => { @@ -90,27 +90,55 @@ export const uploadBundleZip = async (uploadUrl: string, rootDir: string) => { // Read the zip file as a buffer const fileBuffer = await readFile(zipPath); - try { - const response = await fetch(uploadUrl, { - method: 'PUT', - headers: { - 'Content-Type': 'application/zip', - }, - body: fileBuffer, - }); + const response = await fetch(uploadUrl, { + method: 'PUT', + headers: { + 'Content-Type': 'application/zip', + }, + body: fileBuffer, + }); - if (!response.ok) { - consola.error(`Failed to upload bundle: ${response.status} ${response.statusText}`); - process.exit(1); - } + if (!response.ok) { + throw new Error(`Failed to upload bundle: ${response.status} ${response.statusText}`); + } + + consola.success('Bundle uploaded successfully.'); - consola.success('Bundle uploaded successfully.'); + return true; +}; + +export const createDeployment = async ( + projectUuid: string, + uploadUuid: string, + storeHash: string, + accessToken: string, + apiHost: string, +) => { + consola.info('Creating deployment...'); + + const response = await fetch(`https://${apiHost}/stores/${storeHash}/v3/headless/deployments`, { + method: 'POST', + headers: { + 'X-Auth-Token': accessToken, + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + body: JSON.stringify({ + project_uuid: projectUuid, + upload_uuid: uploadUuid, + }), + }); - return true; - } catch (error) { - consola.error('Error in uploadBundleZip:', error); - process.exit(1); + if (!response.ok) { + throw new Error(`Failed to create deployment: ${response.status} ${response.statusText}`); } + + const res: unknown = await response.json(); + const { data } = CreateDeploymentSchema.parse(res); + + consola.success('Deployment started...'); + + return data; }; export const deploy = new Command('deploy') @@ -136,18 +164,42 @@ export const deploy = new Command('deploy') .env('BIGCOMMERCE_API_HOST') .default('api.bigcommerce.com'), ) + .addOption( + new Option( + '--project-uuid ', + 'BigCommerce headless project UUID. Can be found via the BigCommerce API (GET /v3/headless/projects).', + ).env('BIGCOMMERCE_PROJECT_UUID'), + ) .option('--root-dir ', 'Root directory to deploy from.', process.cwd()) .action(async (opts) => { - await generateBundleZip(opts.rootDir); + const config = new ProjectConfig(opts.rootDir); + + try { + const projectUuid = opts.projectUuid ?? config.get('projectUuid'); + + await generateBundleZip(opts.rootDir); - const uploadSignature = await generateUploadSignature( - opts.storeHash, - opts.accessToken, - opts.apiHost, - ); + const uploadSignature = await generateUploadSignature( + opts.storeHash, + opts.accessToken, + opts.apiHost, + ); - await uploadBundleZip(uploadSignature.upload_url, opts.rootDir); + await uploadBundleZip(uploadSignature.upload_url, opts.rootDir); + + await createDeployment( + projectUuid, + uploadSignature.upload_uuid, + opts.storeHash, + opts.accessToken, + opts.apiHost, + ); + + // @todo poll for deployment status + } catch (error) { + consola.error(error); + process.exit(1); + } - // @todo rest of upload flow process.exit(0); }); diff --git a/packages/cli/src/lib/project-config.ts b/packages/cli/src/lib/project-config.ts new file mode 100644 index 0000000000..f73dcd25ee --- /dev/null +++ b/packages/cli/src/lib/project-config.ts @@ -0,0 +1,35 @@ +import Conf from 'conf'; +import { join } from 'path'; + +export interface ProjectConfigSchema { + projectUuid: string; +} + +export class ProjectConfig { + private config: Conf; + + constructor(rootDir = process.cwd()) { + this.config = new Conf({ + cwd: join(rootDir, '.bigcommerce'), + projectSuffix: '', + configName: 'project', + schema: { + projectUuid: { type: 'string', format: 'uuid' }, + }, + }); + } + + get(field: keyof ProjectConfigSchema): string { + const value = this.config.get(field); + + if (!value) { + throw new Error(`No \`${field}\` found in .bigcommerce/project.json.`); + } + + return value; + } + + set(field: string, value: string): void { + this.config.set(field, value); + } +} diff --git a/packages/cli/tests/commands/deploy.spec.ts b/packages/cli/tests/commands/deploy.spec.ts index 2dd876c347..196a6ea192 100644 --- a/packages/cli/tests/commands/deploy.spec.ts +++ b/packages/cli/tests/commands/deploy.spec.ts @@ -4,6 +4,7 @@ import { dirname, join } from 'node:path'; import { afterAll, beforeAll, describe, expect, test } from 'vitest'; import { + createDeployment, generateBundleZip, generateUploadSignature, uploadBundleZip, @@ -14,6 +15,13 @@ let tmpDir: string; let cleanup: () => Promise; let outputZip: string; +const projectUuid = 'a23f5785-fd99-4a94-9fb3-945551623923'; +const storeHash = 'test-store'; +const accessToken = 'test-token'; +const apiHost = 'api.bigcommerce.com'; +const uploadUuid = '0e93ce5f-6f91-4236-87ec-ca79627f31ba'; +const uploadUrl = 'https://mock-upload-url.com'; + beforeAll(async () => { // Setup test directories and files [tmpDir, cleanup] = await mkTempDir(); @@ -33,7 +41,7 @@ afterAll(async () => { await cleanup(); }); -describe('bundle zip generation', () => { +describe('bundle zip generation and upload', () => { test('creates bundle.zip from build output', async () => { await generateBundleZip(tmpDir); @@ -61,25 +69,33 @@ describe('bundle zip generation', () => { // Check for output/worker.js expect(entries).toContain('output/worker.js'); }); -}); -describe('bundle zip upload', () => { test('fetches upload signature and uploads bundle zip', async () => { - const storeHash = 'test-store'; - const accessToken = 'test-token'; - const apiHost = 'api.bigcommerce.com'; - // Test generateUploadSignature const signature = await generateUploadSignature(storeHash, accessToken, apiHost); - expect(signature.upload_url).toBe('https://mock-upload-url.com'); - expect(signature.upload_uuid).toBe('mock-uuid'); + expect(signature.upload_url).toBe(uploadUrl); + expect(signature.upload_uuid).toBe(uploadUuid); // Test uploadBundleZip await generateBundleZip(tmpDir); // Ensure zip exists - const uploadResult = await uploadBundleZip('https://mock-upload-url.com', tmpDir); + const uploadResult = await uploadBundleZip(uploadUrl, tmpDir); expect(uploadResult).toBe(true); }); }); + +describe('deployment and polling', () => { + test('creates a deployment', async () => { + const deployment = await createDeployment( + projectUuid, + uploadUuid, + storeHash, + accessToken, + apiHost, + ); + + expect(deployment.deployment_uuid).toBe('5b29c3c0-5f68-44fe-99e5-06492babf7be'); + }); +}); diff --git a/packages/cli/tests/lib/project-config.spec.ts b/packages/cli/tests/lib/project-config.spec.ts new file mode 100644 index 0000000000..02cd1abf70 --- /dev/null +++ b/packages/cli/tests/lib/project-config.spec.ts @@ -0,0 +1,57 @@ +import { mkdir, writeFile } from 'node:fs/promises'; +import { dirname, join } from 'node:path'; +import { afterAll, beforeAll, expect, test } from 'vitest'; + +import { mkTempDir } from '../../src/lib/mk-temp-dir'; +import { ProjectConfig } from '../../src/lib/project-config'; + +let tmpDir: string; +let cleanup: () => Promise; +let config: ProjectConfig; + +const projectUuid = 'a23f5785-fd99-4a94-9fb3-945551623923'; + +beforeAll(async () => { + [tmpDir, cleanup] = await mkTempDir(); + + config = new ProjectConfig(tmpDir); +}); + +afterAll(async () => { + await cleanup(); +}); + +test('throws error if field is missing', async () => { + const projectJsonPath = join(tmpDir, '.bigcommerce/project.json'); + + await mkdir(dirname(projectJsonPath), { recursive: true }); + await writeFile(projectJsonPath, JSON.stringify({})); + + expect(() => config.get('projectUuid')).toThrowError( + 'No `projectUuid` found in .bigcommerce/project.json.', + ); +}); + +test('throws error if field does not match schema', async () => { + const projectJsonPath = join(tmpDir, '.bigcommerce/project.json'); + + await mkdir(dirname(projectJsonPath), { recursive: true }); + await writeFile(projectJsonPath, JSON.stringify({ projectUuid: 'invalid-uuid' })); + + expect(() => config.get('projectUuid')).toThrowError( + 'Config schema violation: `projectUuid` must match format "uuid"', + ); +}); + +test('writes and reads field from .bigcommerce/project.json', async () => { + const projectJsonPath = join(tmpDir, '.bigcommerce/project.json'); + + await mkdir(dirname(projectJsonPath), { recursive: true }); + await writeFile(projectJsonPath, JSON.stringify({})); + + config.set('projectUuid', projectUuid); + + const modifiedProjectUuid = config.get('projectUuid'); + + expect(modifiedProjectUuid).toBe(projectUuid); +}); diff --git a/packages/cli/tests/mocks/handlers.ts b/packages/cli/tests/mocks/handlers.ts index 4c00eb1e8b..4f6f0cdfed 100644 --- a/packages/cli/tests/mocks/handlers.ts +++ b/packages/cli/tests/mocks/handlers.ts @@ -6,11 +6,20 @@ export const handlers = [ HttpResponse.json({ data: { upload_url: 'https://mock-upload-url.com', - upload_uuid: 'mock-uuid', + upload_uuid: '0e93ce5f-6f91-4236-87ec-ca79627f31ba', }, }), ), // Handler for uploadBundleZip http.put('https://mock-upload-url.com', () => new HttpResponse(null, { status: 200 })), + + // Handler for createDeployment + http.post('https://:apiHost/stores/:storeHash/v3/headless/deployments', () => + HttpResponse.json({ + data: { + deployment_uuid: '5b29c3c0-5f68-44fe-99e5-06492babf7be', + }, + }), + ), ]; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 603fe2a073..840ce11e1a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -203,7 +203,7 @@ importers: version: 1.12.16(graphql@16.11.0)(typescript@5.8.3) '@bigcommerce/eslint-config': specifier: ^2.11.0 - version: 2.11.0(@types/eslint@9.6.1)(eslint@8.57.1)(jest@29.7.0(@types/node@22.15.30))(typescript@5.8.3) + version: 2.11.0(@types/eslint@9.6.1)(eslint@8.57.1)(jest@29.7.0)(typescript@5.8.3) '@bigcommerce/eslint-config-catalyst': specifier: workspace:^ version: link:../packages/eslint-config-catalyst @@ -297,6 +297,9 @@ importers: commander: specifier: ^14.0.0 version: 14.0.0 + conf: + specifier: ^13.1.0 + version: 13.1.0 consola: specifier: ^3.4.2 version: 3.4.2 @@ -309,7 +312,7 @@ importers: devDependencies: '@bigcommerce/eslint-config': specifier: ^2.11.0 - version: 2.11.0(@types/eslint@9.6.1)(eslint@8.57.1)(jest@29.7.0(@types/node@22.15.30))(typescript@5.8.3) + version: 2.11.0(@types/eslint@9.6.1)(eslint@8.57.1)(jest@29.7.0)(typescript@5.8.3) '@bigcommerce/eslint-config-catalyst': specifier: workspace:^ version: link:../eslint-config-catalyst @@ -358,7 +361,7 @@ importers: devDependencies: '@bigcommerce/eslint-config': specifier: ^2.11.0 - version: 2.11.0(@types/eslint@9.6.1)(eslint@8.57.1)(jest@29.7.0(@types/node@22.15.30))(typescript@5.8.3) + version: 2.11.0(@types/eslint@9.6.1)(eslint@8.57.1)(jest@29.7.0)(typescript@5.8.3) '@bigcommerce/eslint-config-catalyst': specifier: workspace:^ version: link:../eslint-config-catalyst @@ -455,7 +458,7 @@ importers: devDependencies: '@bigcommerce/eslint-config': specifier: ^2.11.0 - version: 2.11.0(@types/eslint@9.6.1)(eslint@8.57.1)(jest@29.7.0(@types/node@22.15.30))(typescript@5.8.3) + version: 2.11.0(@types/eslint@9.6.1)(eslint@8.57.1)(jest@29.7.0)(typescript@5.8.3) '@bigcommerce/eslint-config-catalyst': specifier: workspace:^ version: link:../eslint-config-catalyst @@ -8056,39 +8059,6 @@ snapshots: '@bcoe/v8-coverage@1.0.2': {} - '@bigcommerce/eslint-config@2.11.0(@types/eslint@9.6.1)(eslint@8.57.1)(jest@29.7.0(@types/node@22.15.30))(typescript@5.8.3)': - dependencies: - '@bigcommerce/eslint-plugin': 1.4.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3) - '@rushstack/eslint-patch': 1.11.0 - '@stylistic/eslint-plugin': 2.7.2(eslint@8.57.1)(typescript@5.8.3) - '@typescript-eslint/eslint-plugin': 8.28.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3) - '@typescript-eslint/parser': 8.28.0(eslint@8.57.1)(typescript@5.8.3) - eslint: 8.57.1 - eslint-config-prettier: 9.1.0(eslint@8.57.1) - eslint-import-resolver-typescript: 3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1) - eslint-plugin-gettext: 1.2.0 - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) - eslint-plugin-jest: 28.11.0(@typescript-eslint/eslint-plugin@8.28.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(jest@29.7.0)(typescript@5.8.3) - eslint-plugin-jest-dom: 5.5.0(eslint@8.57.1) - eslint-plugin-jest-formatting: 3.1.0(eslint@8.57.1) - eslint-plugin-jsdoc: 50.6.9(eslint@8.57.1) - eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1) - eslint-plugin-prettier: 5.4.1(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@8.57.1))(eslint@8.57.1)(prettier@3.6.2) - eslint-plugin-react: 7.37.4(eslint@8.57.1) - eslint-plugin-react-hooks: 5.2.0(eslint@8.57.1) - eslint-plugin-switch-case: 1.1.2 - eslint-plugin-testing-library: 7.1.1(eslint@8.57.1)(typescript@5.8.3) - prettier: 3.6.2 - optionalDependencies: - typescript: 5.8.3 - transitivePeerDependencies: - - '@testing-library/dom' - - '@types/eslint' - - eslint-import-resolver-webpack - - eslint-plugin-import-x - - jest - - supports-color - '@bigcommerce/eslint-config@2.11.0(@types/eslint@9.6.1)(eslint@8.57.1)(jest@29.7.0)(typescript@5.8.3)': dependencies: '@bigcommerce/eslint-plugin': 1.4.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3) @@ -11974,8 +11944,8 @@ snapshots: '@typescript-eslint/parser': 8.28.0(eslint@8.57.1)(typescript@5.8.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) + eslint-import-resolver-typescript: 3.9.1(eslint-plugin-import@2.31.0)(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1)(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1) eslint-plugin-react: 7.37.4(eslint@8.57.1) eslint-plugin-react-hooks: 5.2.0(eslint@8.57.1) @@ -12002,21 +11972,6 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1): - dependencies: - '@nolyfill/is-core-module': 1.0.39 - debug: 4.4.1 - eslint: 8.57.1 - get-tsconfig: 4.10.0 - is-bun-module: 1.3.0 - rspack-resolver: 1.2.2 - stable-hash: 0.0.5 - tinyglobby: 0.2.14 - optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) - transitivePeerDependencies: - - supports-color - eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0)(eslint@8.57.1): dependencies: '@nolyfill/is-core-module': 1.0.39 @@ -12033,17 +11988,6 @@ snapshots: - supports-color eslint-module-utils@2.12.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): - dependencies: - debug: 3.2.7 - optionalDependencies: - '@typescript-eslint/parser': 8.28.0(eslint@8.57.1)(typescript@5.8.3) - eslint: 8.57.1 - eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1) - transitivePeerDependencies: - - supports-color - - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.9.1)(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: @@ -12064,35 +12008,6 @@ snapshots: dependencies: gettext-parser: 4.2.0 - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): - dependencies: - '@rtsao/scc': 1.1.0 - array-includes: 3.1.8 - array.prototype.findlastindex: 1.2.6 - array.prototype.flat: 1.3.3 - array.prototype.flatmap: 1.3.3 - debug: 3.2.7 - doctrine: 2.1.0 - eslint: 8.57.1 - eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) - hasown: 2.0.2 - is-core-module: 2.16.1 - is-glob: 4.0.3 - minimatch: 3.1.2 - object.fromentries: 2.0.8 - object.groupby: 1.0.3 - object.values: 1.2.1 - semver: 6.3.1 - string.prototype.trimend: 1.0.9 - tsconfig-paths: 3.15.0 - optionalDependencies: - '@typescript-eslint/parser': 8.28.0(eslint@8.57.1)(typescript@5.8.3) - transitivePeerDependencies: - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1)(eslint@8.57.1): dependencies: '@rtsao/scc': 1.1.0 @@ -12104,7 +12019,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.9.1)(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 From 2b9b1b2325319c4b6edfdfd6c3ed0129e33d408e Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Fri, 1 Aug 2025 10:39:31 -0500 Subject: [PATCH 002/245] refactor(cli): use consola for version logs and update tests (#2505) --- packages/cli/src/commands/version.ts | 11 +++++---- packages/cli/src/program.ts | 3 ++- packages/cli/tests/commands/version.spec.ts | 26 +++++++++------------ packages/cli/tests/index.spec.ts | 2 ++ 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/packages/cli/src/commands/version.ts b/packages/cli/src/commands/version.ts index 85cb43e97f..5c7ef31131 100644 --- a/packages/cli/src/commands/version.ts +++ b/packages/cli/src/commands/version.ts @@ -1,13 +1,14 @@ import chalk from 'chalk'; import { Command } from 'commander'; +import consola from 'consola'; import PACKAGE_INFO from '../../package.json'; export const version = new Command('version') - .description('Display detailed version information') + .description('Display detailed version information.') .action(() => { - console.log(chalk.cyanBright('\nVersion Information:')); - console.log(`${chalk.bold('CLI Version:')} ${PACKAGE_INFO.version}`); - console.log(`${chalk.bold('Node Version:')} ${process.version}`); - console.log(`${chalk.bold('Platform:')} ${process.platform} (${process.arch})\n`); + consola.log(chalk.cyanBright('\nVersion Information:')); + consola.log(`${chalk.bold('CLI Version:')} ${PACKAGE_INFO.version}`); + consola.log(`${chalk.bold('Node Version:')} ${process.version}`); + consola.log(`${chalk.bold('Platform:')} ${process.platform} (${process.arch})\n`); }); diff --git a/packages/cli/src/program.ts b/packages/cli/src/program.ts index f72a893479..9ee03b0590 100644 --- a/packages/cli/src/program.ts +++ b/packages/cli/src/program.ts @@ -1,5 +1,6 @@ import chalk from 'chalk'; import { Command } from 'commander'; +import consola from 'consola'; import PACKAGE_INFO from '../package.json'; @@ -9,7 +10,7 @@ import { version } from './commands/version'; export const program = new Command(); -console.log(chalk.cyanBright(`\n◢ ${PACKAGE_INFO.name} v${PACKAGE_INFO.version}\n`)); +consola.log(chalk.cyanBright(`\n◢ ${PACKAGE_INFO.name} v${PACKAGE_INFO.version}\n`)); program .name(PACKAGE_INFO.name) diff --git a/packages/cli/tests/commands/version.spec.ts b/packages/cli/tests/commands/version.spec.ts index 0e726d7c40..43fa59729c 100644 --- a/packages/cli/tests/commands/version.spec.ts +++ b/packages/cli/tests/commands/version.spec.ts @@ -1,7 +1,9 @@ import { Command } from '@commander-js/extra-typings'; -import { afterEach, beforeEach, expect, MockInstance, test, vi } from 'vitest'; +import consola from 'consola'; +import { beforeAll, expect, test, vi } from 'vitest'; import { version } from '../../src/commands/version'; +import { program } from '../../src/program'; vi.mock('chalk', () => ({ default: new Proxy( @@ -12,36 +14,30 @@ vi.mock('chalk', () => ({ ), })); -let consoleMock: MockInstance; - -beforeEach(() => { - consoleMock = vi.spyOn(console, 'log').mockImplementation(() => null); -}); - -afterEach(() => { - consoleMock.mockReset(); +beforeAll(() => { + consola.mockTypes(() => vi.fn()); }); test('properly configured Command instance', () => { expect(version).toBeInstanceOf(Command); expect(version.name()).toBe('version'); - expect(version.description()).toBe('Display detailed version information'); + expect(version.description()).toBe('Display detailed version information.'); }); test('displays version information when executed', async () => { - await version.parseAsync([]); + await program.parseAsync(['node', 'catalyst', 'version']); - expect(consoleMock).toHaveBeenCalledWith(expect.stringContaining('Version Information:')); + expect(consola.log).toHaveBeenCalledWith(expect.stringContaining('Version Information:')); - expect(consoleMock).toHaveBeenCalledWith( + expect(consola.log).toHaveBeenCalledWith( expect.stringContaining(`CLI Version: ${process.env.npm_package_version}`), ); - expect(consoleMock).toHaveBeenCalledWith( + expect(consola.log).toHaveBeenCalledWith( expect.stringContaining(`Node Version: ${process.version}`), ); - expect(consoleMock).toHaveBeenCalledWith( + expect(consola.log).toHaveBeenCalledWith( expect.stringContaining(`Platform: ${process.platform} (${process.arch})`), ); }); diff --git a/packages/cli/tests/index.spec.ts b/packages/cli/tests/index.spec.ts index cdd9416423..a7b4f7704f 100644 --- a/packages/cli/tests/index.spec.ts +++ b/packages/cli/tests/index.spec.ts @@ -15,5 +15,7 @@ describe('CLI program', () => { const commands = program.commands.map((cmd) => cmd.name()); expect(commands).toContain('version'); + expect(commands).toContain('build'); + expect(commands).toContain('deploy'); }); }); From 071b7f554600528095493b414581736831a2e846 Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Fri, 1 Aug 2025 10:46:41 -0500 Subject: [PATCH 003/245] feat(cli): add dev command (#2498) * feat(cli): adds dev command * refactor: run local binary * fix: pass port to execa command * chore: add test * feat: remove codegen * refactor: handle error message correctly * fix: add dev to program test --- packages/cli/package.json | 1 + packages/cli/src/commands/dev.ts | 26 +++++++++++++++ packages/cli/src/program.ts | 6 ++-- packages/cli/tests/commands/dev.spec.ts | 44 +++++++++++++++++++++++++ packages/cli/tests/index.spec.ts | 1 + pnpm-lock.yaml | 3 ++ 6 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 packages/cli/src/commands/dev.ts create mode 100644 packages/cli/tests/commands/dev.spec.ts diff --git a/packages/cli/package.json b/packages/cli/package.json index bd510769cf..a45c33b70c 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -27,6 +27,7 @@ "commander": "^14.0.0", "conf": "^13.1.0", "consola": "^3.4.2", + "execa": "^9.6.0", "nypm": "^0.6.0", "zod": "^4.0.5" }, diff --git a/packages/cli/src/commands/dev.ts b/packages/cli/src/commands/dev.ts new file mode 100644 index 0000000000..928f52e2ef --- /dev/null +++ b/packages/cli/src/commands/dev.ts @@ -0,0 +1,26 @@ +import { Command } from 'commander'; +import consola from 'consola'; +import { execa } from 'execa'; +import { join } from 'node:path'; + +export const dev = new Command('dev') + .description('Start the Catalyst development server.') + .option('-p, --port ', 'Port to run the development server on (default: 3000).', '3000') + .option( + '--root-dir ', + 'Path to the root directory of your Catalyst project (default: current working directory).', + process.cwd(), + ) + .action(async (opts) => { + try { + const nextBin = join(opts.rootDir, 'node_modules', '.bin', 'next'); + + await execa(nextBin, ['dev', '-p', opts.port], { + stdio: 'inherit', + cwd: opts.rootDir, + }); + } catch (error) { + consola.error(error instanceof Error ? error.message : error); + process.exit(1); + } + }); diff --git a/packages/cli/src/program.ts b/packages/cli/src/program.ts index 9ee03b0590..da1f775f79 100644 --- a/packages/cli/src/program.ts +++ b/packages/cli/src/program.ts @@ -6,6 +6,7 @@ import PACKAGE_INFO from '../package.json'; import { build } from './commands/build'; import { deploy } from './commands/deploy'; +import { dev } from './commands/dev'; import { version } from './commands/version'; export const program = new Command(); @@ -16,6 +17,7 @@ program .name(PACKAGE_INFO.name) .version(PACKAGE_INFO.version) .description('CLI tool for Catalyst development') - .addCommand(version) .addCommand(build) - .addCommand(deploy); + .addCommand(deploy) + .addCommand(dev) + .addCommand(version); diff --git a/packages/cli/tests/commands/dev.spec.ts b/packages/cli/tests/commands/dev.spec.ts new file mode 100644 index 0000000000..41f8df96e4 --- /dev/null +++ b/packages/cli/tests/commands/dev.spec.ts @@ -0,0 +1,44 @@ +import { Command } from 'commander'; +import { execa } from 'execa'; +import { expect, test, vi } from 'vitest'; + +import { dev } from '../../src/commands/dev'; +import { program } from '../../src/program'; + +vi.mock('execa', () => ({ + execa: vi.fn(() => Promise.resolve({ stdout: '' })), + __esModule: true, +})); + +test('properly configured Command instance', () => { + expect(dev).toBeInstanceOf(Command); + expect(dev.name()).toBe('dev'); + expect(dev.description()).toBe('Start the Catalyst development server.'); + expect(dev.options).toEqual( + expect.arrayContaining([ + expect.objectContaining({ flags: '-p, --port ', defaultValue: '3000' }), + expect.objectContaining({ flags: '--root-dir ', defaultValue: process.cwd() }), + ]), + ); +}); + +test('calls execa with Next.js development server', async () => { + await program.parseAsync([ + 'node', + 'catalyst', + 'dev', + '-p', + '3001', + '--root-dir', + '/path/to/root', + ]); + + expect(execa).toHaveBeenCalledWith( + '/path/to/root/node_modules/.bin/next', + ['dev', '-p', '3001'], + expect.objectContaining({ + stdio: 'inherit', + cwd: '/path/to/root', + }), + ); +}); diff --git a/packages/cli/tests/index.spec.ts b/packages/cli/tests/index.spec.ts index a7b4f7704f..3eaee398e3 100644 --- a/packages/cli/tests/index.spec.ts +++ b/packages/cli/tests/index.spec.ts @@ -17,5 +17,6 @@ describe('CLI program', () => { expect(commands).toContain('version'); expect(commands).toContain('build'); expect(commands).toContain('deploy'); + expect(commands).toContain('dev'); }); }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 840ce11e1a..83a414d69d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -303,6 +303,9 @@ importers: consola: specifier: ^3.4.2 version: 3.4.2 + execa: + specifier: ^9.6.0 + version: 9.6.0 nypm: specifier: ^0.6.0 version: 0.6.0 From 59f0d15873bc1950fb780236e8c627e1eb961f59 Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Fri, 1 Aug 2025 10:52:57 -0500 Subject: [PATCH 004/245] feat(cli): add start command (#2501) * feat(cli): add start command * fix: pass port to execa command * chore: add test * refactor: handle error message correctly * fix: add start to program test --- packages/cli/src/commands/start.ts | 27 ++++++++++++++ packages/cli/src/program.ts | 4 ++- packages/cli/tests/commands/start.spec.ts | 44 +++++++++++++++++++++++ packages/cli/tests/index.spec.ts | 1 + 4 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 packages/cli/src/commands/start.ts create mode 100644 packages/cli/tests/commands/start.spec.ts diff --git a/packages/cli/src/commands/start.ts b/packages/cli/src/commands/start.ts new file mode 100644 index 0000000000..7d6bf3a058 --- /dev/null +++ b/packages/cli/src/commands/start.ts @@ -0,0 +1,27 @@ +import { Command } from 'commander'; +import consola from 'consola'; +import { execa } from 'execa'; +import { join } from 'node:path'; + +export const start = new Command('start') + .description('Start your Catalyst storefront in optimized production mode.') + .option('-p, --port ', 'Port to run the production server on (default: 3000).', '3000') + .option( + '--root-dir ', + 'Path to the root directory of your Catalyst project (default: current working directory).', + process.cwd(), + ) + .action(async (opts) => { + try { + const nextBin = join(opts.rootDir, 'node_modules', '.bin', 'next'); + + // @todo conditionally run `next start` or `opennextjs-cloudflare preview` based on the framework type + await execa(nextBin, ['start', '-p', opts.port], { + stdio: 'inherit', + cwd: opts.rootDir, + }); + } catch (error) { + consola.error(error instanceof Error ? error.message : error); + process.exit(1); + } + }); diff --git a/packages/cli/src/program.ts b/packages/cli/src/program.ts index da1f775f79..b9b6b283bc 100644 --- a/packages/cli/src/program.ts +++ b/packages/cli/src/program.ts @@ -7,6 +7,7 @@ import PACKAGE_INFO from '../package.json'; import { build } from './commands/build'; import { deploy } from './commands/deploy'; import { dev } from './commands/dev'; +import { start } from './commands/start'; import { version } from './commands/version'; export const program = new Command(); @@ -20,4 +21,5 @@ program .addCommand(build) .addCommand(deploy) .addCommand(dev) - .addCommand(version); + .addCommand(version) + .addCommand(start); diff --git a/packages/cli/tests/commands/start.spec.ts b/packages/cli/tests/commands/start.spec.ts new file mode 100644 index 0000000000..38f43b5fd3 --- /dev/null +++ b/packages/cli/tests/commands/start.spec.ts @@ -0,0 +1,44 @@ +import { Command } from 'commander'; +import { execa } from 'execa'; +import { expect, test, vi } from 'vitest'; + +import { start } from '../../src/commands/start'; +import { program } from '../../src/program'; + +vi.mock('execa', () => ({ + execa: vi.fn(() => Promise.resolve({})), + __esModule: true, +})); + +test('properly configured Command instance', () => { + expect(start).toBeInstanceOf(Command); + expect(start.name()).toBe('start'); + expect(start.description()).toBe('Start your Catalyst storefront in optimized production mode.'); + expect(start.options).toEqual( + expect.arrayContaining([ + expect.objectContaining({ flags: '-p, --port ', defaultValue: '3000' }), + expect.objectContaining({ flags: '--root-dir ', defaultValue: process.cwd() }), + ]), + ); +}); + +test('calls execa with Next.js production optimized server', async () => { + await program.parseAsync([ + 'node', + 'catalyst', + 'start', + '-p', + '3001', + '--root-dir', + '/path/to/root', + ]); + + expect(execa).toHaveBeenCalledWith( + '/path/to/root/node_modules/.bin/next', + ['start', '-p', '3001'], + expect.objectContaining({ + stdio: 'inherit', + cwd: '/path/to/root', + }), + ); +}); diff --git a/packages/cli/tests/index.spec.ts b/packages/cli/tests/index.spec.ts index 3eaee398e3..95c872fcfb 100644 --- a/packages/cli/tests/index.spec.ts +++ b/packages/cli/tests/index.spec.ts @@ -18,5 +18,6 @@ describe('CLI program', () => { expect(commands).toContain('build'); expect(commands).toContain('deploy'); expect(commands).toContain('dev'); + expect(commands).toContain('start'); }); }); From a4ee0b7bef6bde5cfb00f6f66a0d13e8616d4120 Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Fri, 1 Aug 2025 12:53:22 -0500 Subject: [PATCH 005/245] feat(cli): add link command (#2503) * feat(cli): add link command * feat: add project framework when users succesfully links * chore: update root-dir * fix: update tests * fix: throw error correctly * feat: add test for no projects * fix: show message when user is not opt in to alpha * fix: use consola.mockTypes * fix: add link to program test --- packages/cli/src/commands/link.ts | 126 +++++++++++ packages/cli/src/lib/project-config.ts | 6 + packages/cli/src/program.ts | 8 +- packages/cli/tests/commands/link.spec.ts | 197 +++++++++++++++++ packages/cli/tests/index.spec.ts | 5 +- packages/cli/tests/lib/project-config.spec.ts | 9 + packages/cli/tests/mocks/handlers.ts | 10 + pnpm-lock.yaml | 209 ++++++++++++++---- 8 files changed, 519 insertions(+), 51 deletions(-) create mode 100644 packages/cli/src/commands/link.ts create mode 100644 packages/cli/tests/commands/link.spec.ts diff --git a/packages/cli/src/commands/link.ts b/packages/cli/src/commands/link.ts new file mode 100644 index 0000000000..8e39b742a4 --- /dev/null +++ b/packages/cli/src/commands/link.ts @@ -0,0 +1,126 @@ +import { Command, Option } from 'commander'; +import consola from 'consola'; +import z from 'zod'; + +import { ProjectConfig } from '../lib/project-config'; + +const fetchProjectsSchema = z.object({ + data: z.array( + z.object({ + uuid: z.string(), + name: z.string(), + }), + ), +}); + +async function fetchProjects(storeHash: string, accessToken: string, apiHost: string) { + const response = await fetch(`https://${apiHost}/stores/${storeHash}/v3/headless/projects`, { + method: 'GET', + headers: { + 'X-Auth-Token': accessToken, + }, + }); + + if (response.status === 404) { + throw new Error( + 'Headless Projects API not enabled. If you are part of the alpha, contact support@bigcommerce.com to enable it.', + ); + } + + if (!response.ok) { + throw new Error(`Failed to fetch projects: ${response.statusText}`); + } + + const res: unknown = await response.json(); + + const { data } = fetchProjectsSchema.parse(res); + + return data; +} + +export const link = new Command('link') + .description( + 'Link your local Catalyst project to a BigCommerce headless project. You can provide a project UUID directly, or fetch and select from available projects using your store credentials.', + ) + .addOption( + new Option( + '--store-hash ', + 'BigCommerce store hash. Can be found in the URL of your store Control Panel.', + ).env('BIGCOMMERCE_STORE_HASH'), + ) + .addOption( + new Option( + '--access-token ', + 'BigCommerce access token. Can be found after creating a store-level API account.', + ).env('BIGCOMMERCE_ACCESS_TOKEN'), + ) + .addOption( + new Option('--api-host ', 'BigCommerce API host. The default is api.bigcommerce.com.') + .env('BIGCOMMERCE_API_HOST') + .default('api.bigcommerce.com'), + ) + .option( + '--project-uuid ', + 'BigCommerce headless project UUID. Can be found via the BigCommerce API (GET /v3/headless/projects). Use this to link directly without fetching projects.', + ) + .option( + '--root-dir ', + 'Path to the root directory of your Catalyst project (default: current working directory).', + process.cwd(), + ) + .action(async (options) => { + try { + const config = new ProjectConfig(options.rootDir); + + const writeProjectConfig = (uuid: string) => { + consola.start('Writing project UUID to .bigcommerce/project.json...'); + config.set('projectUuid', uuid); + config.set('framework', 'catalyst'); + consola.success('Project UUID written to .bigcommerce/project.json.'); + }; + + if (options.projectUuid) { + writeProjectConfig(options.projectUuid); + + process.exit(0); + } + + if (options.storeHash && options.accessToken) { + consola.start('Fetching projects...'); + + const projects = await fetchProjects( + options.storeHash, + options.accessToken, + options.apiHost, + ); + + consola.success('Projects fetched.'); + + if (!projects.length) { + throw new Error('No headless projects found for this store.'); + } + + const projectUuid = await consola.prompt('Select a project (Press to select).', { + type: 'select', + options: projects.map((project) => ({ + label: project.name, + value: project.uuid, + hint: project.uuid, + })), + cancel: 'reject', + }); + + writeProjectConfig(projectUuid); + + process.exit(0); + } + + consola.error('Insufficient information to link a project.'); + consola.info('Provide a project UUID with --project-uuid, or'); + consola.info('Provide both --store-hash and --access-token to fetch and select a project.'); + process.exit(1); + } catch (error) { + consola.error(error instanceof Error ? error.message : error); + process.exit(1); + } + }); diff --git a/packages/cli/src/lib/project-config.ts b/packages/cli/src/lib/project-config.ts index f73dcd25ee..739c26350c 100644 --- a/packages/cli/src/lib/project-config.ts +++ b/packages/cli/src/lib/project-config.ts @@ -3,6 +3,7 @@ import { join } from 'path'; export interface ProjectConfigSchema { projectUuid: string; + framework: 'catalyst' | 'nextjs'; } export class ProjectConfig { @@ -15,6 +16,11 @@ export class ProjectConfig { configName: 'project', schema: { projectUuid: { type: 'string', format: 'uuid' }, + framework: { + type: 'string', + enum: ['catalyst', 'nextjs'], + default: 'catalyst', + }, }, }); } diff --git a/packages/cli/src/program.ts b/packages/cli/src/program.ts index b9b6b283bc..0ae4f0c243 100644 --- a/packages/cli/src/program.ts +++ b/packages/cli/src/program.ts @@ -7,6 +7,7 @@ import PACKAGE_INFO from '../package.json'; import { build } from './commands/build'; import { deploy } from './commands/deploy'; import { dev } from './commands/dev'; +import { link } from './commands/link'; import { start } from './commands/start'; import { version } from './commands/version'; @@ -18,8 +19,9 @@ program .name(PACKAGE_INFO.name) .version(PACKAGE_INFO.version) .description('CLI tool for Catalyst development') + .addCommand(version) + .addCommand(dev) + .addCommand(start) .addCommand(build) .addCommand(deploy) - .addCommand(dev) - .addCommand(version) - .addCommand(start); + .addCommand(link); diff --git a/packages/cli/tests/commands/link.spec.ts b/packages/cli/tests/commands/link.spec.ts new file mode 100644 index 0000000000..6e1f82fc8a --- /dev/null +++ b/packages/cli/tests/commands/link.spec.ts @@ -0,0 +1,197 @@ +import { Command } from 'commander'; +import consola from 'consola'; +import { http, HttpResponse } from 'msw'; +import { afterAll, afterEach, beforeAll, expect, MockInstance, test, vi } from 'vitest'; + +import { link } from '../../src/commands/link'; +import { mkTempDir } from '../../src/lib/mk-temp-dir'; +import { ProjectConfig } from '../../src/lib/project-config'; +import { program } from '../../src/program'; +import { server } from '../mocks/node'; + +let exitMock: MockInstance; + +let tmpDir: string; +let cleanup: () => Promise; +let config: ProjectConfig; + +const projectUuid1 = 'a23f5785-fd99-4a94-9fb3-945551623923'; +const projectUuid2 = 'b23f5785-fd99-4a94-9fb3-945551623924'; +const storeHash = 'test-store'; +const accessToken = 'test-token'; + +beforeAll(async () => { + consola.mockTypes(() => vi.fn()); + + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + exitMock = vi.spyOn(process, 'exit').mockImplementation(() => null as never); + + [tmpDir, cleanup] = await mkTempDir(); + + config = new ProjectConfig(tmpDir); +}); + +afterEach(() => { + vi.clearAllMocks(); +}); + +afterAll(async () => { + vi.restoreAllMocks(); + exitMock.mockRestore(); + + await cleanup(); +}); + +test('properly configured Command instance', () => { + expect(link).toBeInstanceOf(Command); + expect(link.name()).toBe('link'); + expect(link.description()).toBe( + 'Link your local Catalyst project to a BigCommerce headless project. You can provide a project UUID directly, or fetch and select from available projects using your store credentials.', + ); + expect(link.options).toEqual( + expect.arrayContaining([ + expect.objectContaining({ flags: '--store-hash ' }), + expect.objectContaining({ flags: '--access-token ' }), + expect.objectContaining({ flags: '--api-host ', defaultValue: 'api.bigcommerce.com' }), + expect.objectContaining({ flags: '--project-uuid ' }), + expect.objectContaining({ flags: '--root-dir ', defaultValue: process.cwd() }), + ]), + ); +}); + +test('sets projectUuid when called with --project-uuid', async () => { + await program.parseAsync([ + 'node', + 'catalyst', + 'link', + '--project-uuid', + projectUuid1, + '--root-dir', + tmpDir, + ]); + + expect(consola.start).toHaveBeenCalledWith( + 'Writing project UUID to .bigcommerce/project.json...', + ); + expect(consola.success).toHaveBeenCalledWith( + 'Project UUID written to .bigcommerce/project.json.', + ); + expect(exitMock).toHaveBeenCalledWith(0); + expect(config.get('projectUuid')).toBe(projectUuid1); + expect(config.get('framework')).toBe('catalyst'); +}); + +test('fetches projects and prompts user to select one', async () => { + const consolaPromptMock = vi + .spyOn(consola, 'prompt') + .mockImplementation(async (message, opts) => { + // Assert the prompt message and options + expect(message).toContain('Select a project (Press to select).'); + + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + const options = (opts as { options: Array<{ label: string; value: string }> }).options; + + expect(options).toHaveLength(2); + expect(options[0]).toMatchObject({ label: 'Project One', value: projectUuid1 }); + expect(options[1]).toMatchObject({ + label: 'Project Two', + value: projectUuid2, + }); + + // Simulate selecting the second option + return new Promise((resolve) => resolve(projectUuid2)); + }); + + await program.parseAsync([ + 'node', + 'catalyst', + 'link', + '--store-hash', + storeHash, + '--access-token', + accessToken, + '--root-dir', + tmpDir, + ]); + + expect(consola.start).toHaveBeenCalledWith('Fetching projects...'); + expect(consola.success).toHaveBeenCalledWith('Projects fetched.'); + + expect(consola.start).toHaveBeenCalledWith( + 'Writing project UUID to .bigcommerce/project.json...', + ); + expect(consola.success).toHaveBeenCalledWith( + 'Project UUID written to .bigcommerce/project.json.', + ); + + expect(exitMock).toHaveBeenCalledWith(0); + + expect(config.get('projectUuid')).toBe(projectUuid2); + expect(config.get('framework')).toBe('catalyst'); + + consolaPromptMock.mockRestore(); +}); + +test('errors when no projects are found', async () => { + server.use( + http.get('https://:apiHost/stores/:storeHash/v3/headless/projects', () => + HttpResponse.json({ + data: [], + }), + ), + ); + + await program.parseAsync([ + 'node', + 'catalyst', + 'link', + '--store-hash', + storeHash, + '--access-token', + accessToken, + '--root-dir', + tmpDir, + ]); + + expect(consola.start).toHaveBeenCalledWith('Fetching projects...'); + expect(consola.error).toHaveBeenCalledWith('No headless projects found for this store.'); + expect(exitMock).toHaveBeenCalledWith(1); +}); + +test('errors when headless projects API is not found', async () => { + server.use( + http.get('https://:apiHost/stores/:storeHash/v3/headless/projects', () => + HttpResponse.json({}, { status: 404 }), + ), + ); + await program.parseAsync([ + 'node', + 'catalyst', + 'link', + '--store-hash', + storeHash, + '--access-token', + accessToken, + '--root-dir', + tmpDir, + ]); + + expect(consola.start).toHaveBeenCalledWith('Fetching projects...'); + expect(consola.error).toHaveBeenCalledWith( + 'Headless Projects API not enabled. If you are part of the alpha, contact support@bigcommerce.com to enable it.', + ); +}); + +test('errors when no projectUuid, storeHash, or accessToken are provided', async () => { + await program.parseAsync(['node', 'catalyst', 'link', '--root-dir', tmpDir]); + + expect(consola.start).not.toHaveBeenCalled(); + expect(consola.success).not.toHaveBeenCalled(); + expect(consola.error).toHaveBeenCalledWith('Insufficient information to link a project.'); + expect(consola.info).toHaveBeenCalledWith('Provide a project UUID with --project-uuid, or'); + expect(consola.info).toHaveBeenCalledWith( + 'Provide both --store-hash and --access-token to fetch and select a project.', + ); + + expect(exitMock).toHaveBeenCalledWith(1); +}); diff --git a/packages/cli/tests/index.spec.ts b/packages/cli/tests/index.spec.ts index 95c872fcfb..c4ab81613d 100644 --- a/packages/cli/tests/index.spec.ts +++ b/packages/cli/tests/index.spec.ts @@ -15,9 +15,10 @@ describe('CLI program', () => { const commands = program.commands.map((cmd) => cmd.name()); expect(commands).toContain('version'); - expect(commands).toContain('build'); - expect(commands).toContain('deploy'); expect(commands).toContain('dev'); expect(commands).toContain('start'); + expect(commands).toContain('build'); + expect(commands).toContain('deploy'); + expect(commands).toContain('link'); }); }); diff --git a/packages/cli/tests/lib/project-config.spec.ts b/packages/cli/tests/lib/project-config.spec.ts index 02cd1abf70..c75143a204 100644 --- a/packages/cli/tests/lib/project-config.spec.ts +++ b/packages/cli/tests/lib/project-config.spec.ts @@ -55,3 +55,12 @@ test('writes and reads field from .bigcommerce/project.json', async () => { expect(modifiedProjectUuid).toBe(projectUuid); }); + +test('sets default framework to catalyst', async () => { + const projectJsonPath = join(tmpDir, '.bigcommerce/project.json'); + + await mkdir(dirname(projectJsonPath), { recursive: true }); + await writeFile(projectJsonPath, JSON.stringify({})); + + expect(config.get('framework')).toBe('catalyst'); +}); diff --git a/packages/cli/tests/mocks/handlers.ts b/packages/cli/tests/mocks/handlers.ts index 4f6f0cdfed..202a5680f2 100644 --- a/packages/cli/tests/mocks/handlers.ts +++ b/packages/cli/tests/mocks/handlers.ts @@ -22,4 +22,14 @@ export const handlers = [ }, }), ), + + // Handler for fetchProjects + http.get('https://:apiHost/stores/:storeHash/v3/headless/projects', () => + HttpResponse.json({ + data: [ + { uuid: 'a23f5785-fd99-4a94-9fb3-945551623923', name: 'Project One' }, + { uuid: 'b23f5785-fd99-4a94-9fb3-945551623924', name: 'Project Two' }, + ], + }), + ), ]; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 83a414d69d..2c04bf1742 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -190,7 +190,7 @@ importers: version: 1.7.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0) tailwindcss-radix: specifier: ^3.0.5 - version: 3.0.5(tailwindcss@3.4.17) + version: 3.0.5(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3))) uuid: specifier: ^11.1.0 version: 11.1.0 @@ -203,7 +203,7 @@ importers: version: 1.12.16(graphql@16.11.0)(typescript@5.8.3) '@bigcommerce/eslint-config': specifier: ^2.11.0 - version: 2.11.0(@types/eslint@9.6.1)(eslint@8.57.1)(jest@29.7.0)(typescript@5.8.3) + version: 2.11.0(@types/eslint@9.6.1)(eslint@8.57.1)(jest@29.7.0(@types/node@22.15.30)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)))(typescript@5.8.3) '@bigcommerce/eslint-config-catalyst': specifier: workspace:^ version: link:../packages/eslint-config-catalyst @@ -221,10 +221,10 @@ importers: version: 1.52.0 '@tailwindcss/container-queries': specifier: ^0.1.1 - version: 0.1.1(tailwindcss@3.4.17) + version: 0.1.1(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3))) '@tailwindcss/typography': specifier: ^0.5.16 - version: 0.5.16(tailwindcss@3.4.17) + version: 0.5.16(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3))) '@types/gtag.js': specifier: ^0.0.20 version: 0.0.20 @@ -278,10 +278,10 @@ importers: version: 0.6.12(prettier@3.6.2) tailwindcss: specifier: ^3.4.17 - version: 3.4.17 + version: 3.4.17(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)) tailwindcss-animate: specifier: 1.0.7 - version: 1.0.7(tailwindcss@3.4.17) + version: 1.0.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3))) typescript: specifier: ^5.8.3 version: 5.8.3 @@ -315,7 +315,7 @@ importers: devDependencies: '@bigcommerce/eslint-config': specifier: ^2.11.0 - version: 2.11.0(@types/eslint@9.6.1)(eslint@8.57.1)(jest@29.7.0)(typescript@5.8.3) + version: 2.11.0(@types/eslint@9.6.1)(eslint@8.57.1)(jest@29.7.0(@types/node@22.15.30)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)))(typescript@5.8.3) '@bigcommerce/eslint-config-catalyst': specifier: workspace:^ version: link:../eslint-config-catalyst @@ -364,7 +364,7 @@ importers: devDependencies: '@bigcommerce/eslint-config': specifier: ^2.11.0 - version: 2.11.0(@types/eslint@9.6.1)(eslint@8.57.1)(jest@29.7.0)(typescript@5.8.3) + version: 2.11.0(@types/eslint@9.6.1)(eslint@8.57.1)(jest@29.7.0(@types/node@22.15.30)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)))(typescript@5.8.3) '@bigcommerce/eslint-config-catalyst': specifier: workspace:^ version: link:../eslint-config-catalyst @@ -461,7 +461,7 @@ importers: devDependencies: '@bigcommerce/eslint-config': specifier: ^2.11.0 - version: 2.11.0(@types/eslint@9.6.1)(eslint@8.57.1)(jest@29.7.0)(typescript@5.8.3) + version: 2.11.0(@types/eslint@9.6.1)(eslint@8.57.1)(jest@29.7.0(@types/node@22.15.30)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)))(typescript@5.8.3) '@bigcommerce/eslint-config-catalyst': specifier: workspace:^ version: link:../eslint-config-catalyst @@ -497,7 +497,7 @@ importers: version: 8.57.1 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@22.15.30) + version: 29.7.0(@types/node@22.15.30)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)) msw: specifier: ^2.9.0 version: 2.9.0(@types/node@22.15.30)(typescript@5.8.3) @@ -515,7 +515,7 @@ importers: dependencies: '@bigcommerce/eslint-config': specifier: ^2.11.0 - version: 2.11.0(@types/eslint@9.6.1)(eslint@8.57.1)(jest@29.7.0)(typescript@5.8.3) + version: 2.11.0(@types/eslint@9.6.1)(eslint@8.57.1)(jest@29.7.0(@types/node@22.15.30)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)))(typescript@5.8.3) '@next/eslint-plugin-next': specifier: ^15.3.3 version: 15.3.3 @@ -836,6 +836,10 @@ packages: peerDependencies: zod: ^3.21.0 + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + '@csstools/cascade-layer-name-parser@2.0.5': resolution: {integrity: sha512-p1ko5eHgV+MgXFVa4STPKpvPxr6ReS8oS2jzTukjR74i5zJNyWO1ZM1m8YKBXnzDKWfBN1ztLYlHxbVemDD88A==} engines: {node: '>=18'} @@ -1818,6 +1822,9 @@ packages: '@jridgewell/trace-mapping@0.3.29': resolution: {integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==} + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + '@lhci/utils@0.14.0': resolution: {integrity: sha512-LyP1RbvYQ9xNl7uLnl5AO8fDRata9MG/KYfVFKFkYenlsVS6QJsNjLzWNEoMIaE4jOPdQQlSp4tO7dtnyDxzbQ==} @@ -2850,6 +2857,18 @@ packages: '@tootallnate/quickjs-emscripten@0.23.0': resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} + '@tsconfig/node10@1.0.11': + resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} + + '@tsconfig/node12@1.0.11': + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + + '@tsconfig/node14@1.0.3': + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + + '@tsconfig/node16@1.0.4': + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + '@tybys/wasm-util@0.9.0': resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==} @@ -3341,6 +3360,9 @@ packages: resolution: {integrity: sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==} engines: {node: '>=14'} + arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} @@ -3829,6 +3851,9 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true + create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -4057,6 +4082,10 @@ packages: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + diff@4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -5671,6 +5700,9 @@ packages: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + makeerror@1.0.12: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} @@ -7308,6 +7340,20 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + ts-node@10.9.2: + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} @@ -7558,6 +7604,9 @@ packages: resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} hasBin: true + v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + v8-to-istanbul@9.2.0: resolution: {integrity: sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==} engines: {node: '>=10.12.0'} @@ -7813,6 +7862,10 @@ packages: yauzl@2.10.0: resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -8062,7 +8115,7 @@ snapshots: '@bcoe/v8-coverage@1.0.2': {} - '@bigcommerce/eslint-config@2.11.0(@types/eslint@9.6.1)(eslint@8.57.1)(jest@29.7.0)(typescript@5.8.3)': + '@bigcommerce/eslint-config@2.11.0(@types/eslint@9.6.1)(eslint@8.57.1)(jest@29.7.0(@types/node@22.15.30)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)))(typescript@5.8.3)': dependencies: '@bigcommerce/eslint-plugin': 1.4.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3) '@rushstack/eslint-patch': 1.11.0 @@ -8071,10 +8124,10 @@ snapshots: '@typescript-eslint/parser': 8.28.0(eslint@8.57.1)(typescript@5.8.3) eslint: 8.57.1 eslint-config-prettier: 9.1.0(eslint@8.57.1) - eslint-import-resolver-typescript: 3.9.1(eslint-plugin-import@2.31.0)(eslint@8.57.1) + eslint-import-resolver-typescript: 3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1) eslint-plugin-gettext: 1.2.0 - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1)(eslint@8.57.1) - eslint-plugin-jest: 28.11.0(@typescript-eslint/eslint-plugin@8.28.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(jest@29.7.0)(typescript@5.8.3) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) + eslint-plugin-jest: 28.11.0(@typescript-eslint/eslint-plugin@8.28.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(jest@29.7.0(@types/node@22.15.30)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)))(typescript@5.8.3) eslint-plugin-jest-dom: 5.5.0(eslint@8.57.1) eslint-plugin-jest-formatting: 3.1.0(eslint@8.57.1) eslint-plugin-jsdoc: 50.6.9(eslint@8.57.1) @@ -8288,6 +8341,11 @@ snapshots: '@conform-to/dom': 1.6.1 zod: 3.25.51 + '@cspotcode/source-map-support@0.8.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + optional: true + '@csstools/cascade-layer-name-parser@2.0.5(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': dependencies: '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) @@ -9071,7 +9129,7 @@ snapshots: jest-util: 29.7.0 slash: 3.0.0 - '@jest/core@29.7.0': + '@jest/core@29.7.0(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3))': dependencies: '@jest/console': 29.7.0 '@jest/reporters': 29.7.0 @@ -9085,7 +9143,7 @@ snapshots: exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@22.15.30) + jest-config: 29.7.0(@types/node@22.15.30)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -9242,6 +9300,12 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.4 + '@jridgewell/trace-mapping@0.3.9': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.4 + optional: true + '@lhci/utils@0.14.0(encoding@0.1.13)': dependencies: debug: 4.4.1 @@ -10238,17 +10302,17 @@ snapshots: typescript: 5.8.3 zod: 3.25.51 - '@tailwindcss/container-queries@0.1.1(tailwindcss@3.4.17)': + '@tailwindcss/container-queries@0.1.1(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)))': dependencies: - tailwindcss: 3.4.17 + tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)) - '@tailwindcss/typography@0.5.16(tailwindcss@3.4.17)': + '@tailwindcss/typography@0.5.16(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)))': dependencies: lodash.castarray: 4.4.0 lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 postcss-selector-parser: 6.0.10 - tailwindcss: 3.4.17 + tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)) '@tanstack/virtual-core@3.13.9': {} @@ -10259,6 +10323,18 @@ snapshots: '@tootallnate/quickjs-emscripten@0.23.0': {} + '@tsconfig/node10@1.0.11': + optional: true + + '@tsconfig/node12@1.0.11': + optional: true + + '@tsconfig/node14@1.0.3': + optional: true + + '@tsconfig/node16@1.0.4': + optional: true + '@tybys/wasm-util@0.9.0': dependencies: tslib: 2.8.1 @@ -10912,6 +10988,9 @@ snapshots: are-docs-informative@0.0.2: {} + arg@4.1.3: + optional: true + arg@5.0.2: {} argparse@1.0.10: @@ -11471,13 +11550,13 @@ snapshots: optionalDependencies: typescript: 5.8.3 - create-jest@29.7.0(@types/node@22.15.30): + create-jest@29.7.0(@types/node@22.15.30)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@22.15.30) + jest-config: 29.7.0(@types/node@22.15.30)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -11486,6 +11565,9 @@ snapshots: - supports-color - ts-node + create-require@1.1.1: + optional: true + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -11663,6 +11745,9 @@ snapshots: diff-sequences@29.6.3: {} + diff@4.0.2: + optional: true + dir-glob@3.0.1: dependencies: path-type: 4.0.0 @@ -11947,8 +12032,8 @@ snapshots: '@typescript-eslint/parser': 8.28.0(eslint@8.57.1)(typescript@5.8.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.9.1(eslint-plugin-import@2.31.0)(eslint@8.57.1) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1)(eslint@8.57.1) + eslint-import-resolver-typescript: 3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1) eslint-plugin-react: 7.37.4(eslint@8.57.1) eslint-plugin-react-hooks: 5.2.0(eslint@8.57.1) @@ -11975,7 +12060,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0)(eslint@8.57.1): + eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.1 @@ -11986,7 +12071,7 @@ snapshots: stable-hash: 0.0.5 tinyglobby: 0.2.14 optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1)(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) transitivePeerDependencies: - supports-color @@ -11997,7 +12082,7 @@ snapshots: '@typescript-eslint/parser': 8.28.0(eslint@8.57.1)(typescript@5.8.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.9.1(eslint-plugin-import@2.31.0)(eslint@8.57.1) + eslint-import-resolver-typescript: 3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1) transitivePeerDependencies: - supports-color @@ -12011,7 +12096,7 @@ snapshots: dependencies: gettext-parser: 4.2.0 - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1)(eslint@8.57.1): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -12050,13 +12135,13 @@ snapshots: dependencies: eslint: 8.57.1 - eslint-plugin-jest@28.11.0(@typescript-eslint/eslint-plugin@8.28.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(jest@29.7.0)(typescript@5.8.3): + eslint-plugin-jest@28.11.0(@typescript-eslint/eslint-plugin@8.28.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(jest@29.7.0(@types/node@22.15.30)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)))(typescript@5.8.3): dependencies: '@typescript-eslint/utils': 8.28.0(eslint@8.57.1)(typescript@5.8.3) eslint: 8.57.1 optionalDependencies: '@typescript-eslint/eslint-plugin': 8.28.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3) - jest: 29.7.0(@types/node@22.15.30) + jest: 29.7.0(@types/node@22.15.30)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)) transitivePeerDependencies: - supports-color - typescript @@ -13102,16 +13187,16 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@22.15.30): + jest-cli@29.7.0(@types/node@22.15.30)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)): dependencies: - '@jest/core': 29.7.0 + '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@22.15.30) + create-jest: 29.7.0(@types/node@22.15.30)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)) exit: 0.1.2 import-local: 3.1.0 - jest-config: 29.7.0(@types/node@22.15.30) + jest-config: 29.7.0(@types/node@22.15.30)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -13121,7 +13206,7 @@ snapshots: - supports-color - ts-node - jest-config@29.7.0(@types/node@22.15.30): + jest-config@29.7.0(@types/node@22.15.30)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)): dependencies: '@babel/core': 7.27.4 '@jest/test-sequencer': 29.7.0 @@ -13147,6 +13232,7 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: '@types/node': 22.15.30 + ts-node: 10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -13366,12 +13452,12 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@22.15.30): + jest@29.7.0(@types/node@22.15.30)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)): dependencies: - '@jest/core': 29.7.0 + '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)) '@jest/types': 29.6.3 import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@22.15.30) + jest-cli: 29.7.0(@types/node@22.15.30)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -13757,6 +13843,9 @@ snapshots: dependencies: semver: 7.7.2 + make-error@1.3.6: + optional: true + makeerror@1.0.12: dependencies: tmpl: 1.0.5 @@ -14380,12 +14469,13 @@ snapshots: '@csstools/utilities': 2.0.0(postcss@8.5.6) postcss: 8.5.6 - postcss-load-config@4.0.2(postcss@8.5.6): + postcss-load-config@4.0.2(postcss@8.5.6)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)): dependencies: lilconfig: 3.1.3 yaml: 2.6.0 optionalDependencies: postcss: 8.5.6 + ts-node: 10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3) postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.6)(yaml@2.6.0): dependencies: @@ -15339,15 +15429,15 @@ snapshots: system-architecture@0.1.0: {} - tailwindcss-animate@1.0.7(tailwindcss@3.4.17): + tailwindcss-animate@1.0.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3))): dependencies: - tailwindcss: 3.4.17 + tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)) - tailwindcss-radix@3.0.5(tailwindcss@3.4.17): + tailwindcss-radix@3.0.5(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3))): dependencies: - tailwindcss: 3.4.17 + tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)) - tailwindcss@3.4.17: + tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -15366,7 +15456,7 @@ snapshots: postcss: 8.5.6 postcss-import: 15.1.0(postcss@8.5.6) postcss-js: 4.0.1(postcss@8.5.6) - postcss-load-config: 4.0.2(postcss@8.5.6) + postcss-load-config: 4.0.2(postcss@8.5.6)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)) postcss-nested: 6.2.0(postcss@8.5.6) postcss-selector-parser: 6.1.2 resolve: 1.22.10 @@ -15505,6 +15595,27 @@ snapshots: ts-interface-checker@0.1.13: {} + ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 22.15.30 + acorn: 8.15.0 + acorn-walk: 8.3.4 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.8.3 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + optionalDependencies: + '@swc/core': 1.11.31 + optional: true + tsconfig-paths@3.15.0: dependencies: '@types/json5': 0.0.29 @@ -15793,6 +15904,9 @@ snapshots: uuid@11.1.0: {} + v8-compile-cache-lib@3.0.1: + optional: true + v8-to-istanbul@9.2.0: dependencies: '@jridgewell/trace-mapping': 0.3.29 @@ -16075,6 +16189,9 @@ snapshots: buffer-crc32: 0.2.13 fd-slicer: 1.1.0 + yn@3.1.1: + optional: true + yocto-queue@0.1.0: {} yoctocolors-cjs@2.1.2: {} From c9eeca2500053590eaa54143d3918f4daf3d02ce Mon Sep 17 00:00:00 2001 From: Matthew Volk Date: Mon, 4 Aug 2025 14:05:53 -0500 Subject: [PATCH 006/245] refactor: modify cf observability config to decrease logs generated (#2510) --- packages/cli/templates/wrangler.jsonc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/cli/templates/wrangler.jsonc b/packages/cli/templates/wrangler.jsonc index d908ebec80..0d395790e4 100644 --- a/packages/cli/templates/wrangler.jsonc +++ b/packages/cli/templates/wrangler.jsonc @@ -6,6 +6,12 @@ "compatibility_flags": ["nodejs_compat", "global_fetch_strictly_public"], "observability": { "enabled": true, + "head_sampling_rate": 0.05, + "logs": { + "enabled": true, + "head_sampling_rate": 1, + "invocation_logs": false, + }, }, "assets": { "directory": ".open-next/assets", From 7c80b0b1cd7ccae1167b7551370e7ba631e7cf3b Mon Sep 17 00:00:00 2001 From: Matthew Volk Date: Mon, 4 Aug 2025 17:13:27 -0500 Subject: [PATCH 007/245] refactor: remove chalk in favor of consola.colorize (#2511) --- packages/cli/package.json | 1 - packages/cli/src/commands/version.ts | 9 ++++----- packages/cli/src/program.ts | 4 ++-- packages/cli/tests/commands/version.spec.ts | 9 --------- pnpm-lock.yaml | 3 --- 5 files changed, 6 insertions(+), 20 deletions(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index a45c33b70c..dd2e3a5e05 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -23,7 +23,6 @@ }, "dependencies": { "adm-zip": "^0.5.16", - "chalk": "^5.3.0", "commander": "^14.0.0", "conf": "^13.1.0", "consola": "^3.4.2", diff --git a/packages/cli/src/commands/version.ts b/packages/cli/src/commands/version.ts index 5c7ef31131..5577dba453 100644 --- a/packages/cli/src/commands/version.ts +++ b/packages/cli/src/commands/version.ts @@ -1,4 +1,3 @@ -import chalk from 'chalk'; import { Command } from 'commander'; import consola from 'consola'; @@ -7,8 +6,8 @@ import PACKAGE_INFO from '../../package.json'; export const version = new Command('version') .description('Display detailed version information.') .action(() => { - consola.log(chalk.cyanBright('\nVersion Information:')); - consola.log(`${chalk.bold('CLI Version:')} ${PACKAGE_INFO.version}`); - consola.log(`${chalk.bold('Node Version:')} ${process.version}`); - consola.log(`${chalk.bold('Platform:')} ${process.platform} (${process.arch})\n`); + consola.log('Version Information:'); + consola.log(`CLI Version: ${PACKAGE_INFO.version}`); + consola.log(`Node Version: ${process.version}`); + consola.log(`Platform: ${process.platform} (${process.arch})`); }); diff --git a/packages/cli/src/program.ts b/packages/cli/src/program.ts index 0ae4f0c243..f970489532 100644 --- a/packages/cli/src/program.ts +++ b/packages/cli/src/program.ts @@ -1,6 +1,6 @@ -import chalk from 'chalk'; import { Command } from 'commander'; import consola from 'consola'; +import { colorize } from 'consola/utils'; import PACKAGE_INFO from '../package.json'; @@ -13,7 +13,7 @@ import { version } from './commands/version'; export const program = new Command(); -consola.log(chalk.cyanBright(`\n◢ ${PACKAGE_INFO.name} v${PACKAGE_INFO.version}\n`)); +consola.log(colorize('cyanBright', `◢ ${PACKAGE_INFO.name} v${PACKAGE_INFO.version}\n`)); program .name(PACKAGE_INFO.name) diff --git a/packages/cli/tests/commands/version.spec.ts b/packages/cli/tests/commands/version.spec.ts index 43fa59729c..09a44c12b8 100644 --- a/packages/cli/tests/commands/version.spec.ts +++ b/packages/cli/tests/commands/version.spec.ts @@ -5,15 +5,6 @@ import { beforeAll, expect, test, vi } from 'vitest'; import { version } from '../../src/commands/version'; import { program } from '../../src/program'; -vi.mock('chalk', () => ({ - default: new Proxy( - {}, - { - get: () => (str: string) => str, - }, - ), -})); - beforeAll(() => { consola.mockTypes(() => vi.fn()); }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2c04bf1742..00adf38c8c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -291,9 +291,6 @@ importers: adm-zip: specifier: ^0.5.16 version: 0.5.16 - chalk: - specifier: ^5.3.0 - version: 5.4.1 commander: specifier: ^14.0.0 version: 14.0.0 From b775f69e9142ea246038e6815b6364b551127392 Mon Sep 17 00:00:00 2001 From: Matthew Volk Date: Tue, 5 Aug 2025 13:59:26 -0500 Subject: [PATCH 008/245] feat: build catalyst with opennextjs-cloudflare (#2493) --- .gitignore | 1 + packages/cli/src/commands/build.ts | 53 +++++++++++++- packages/cli/tests/commands/build.spec.ts | 89 ++++++++++++++++++++++- pnpm-lock.yaml | 19 +++-- 4 files changed, 150 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index 5af2d3e5cb..a0caaaaac9 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ bigcommerce-graphql.d.ts coverage/ .history .unlighthouse +.bigcommerce diff --git a/packages/cli/src/commands/build.ts b/packages/cli/src/commands/build.ts index e6b4e3f971..b093312c84 100644 --- a/packages/cli/src/commands/build.ts +++ b/packages/cli/src/commands/build.ts @@ -1,5 +1,6 @@ import { Command } from 'commander'; import consola from 'consola'; +import { execa } from 'execa'; import { cp } from 'node:fs/promises'; import { join, relative, sep } from 'node:path'; import { addDevDependency, installDependencies, runScript } from 'nypm'; @@ -8,6 +9,7 @@ import { getModuleCliPath } from '../lib/get-module-cli-path'; import { mkTempDir } from '../lib/mk-temp-dir'; const OPENNEXTJS_CLOUDFLARE_VERSION = '1.5.2'; +const WRANGLER_VERSION = '4.24.3'; const SKIP_DIRS = new Set([ 'node_modules', @@ -38,9 +40,14 @@ export const build = new Command('build') try { consola.start('Copying project to temp directory...'); - const cwd = process.cwd(); const packageManager = 'pnpm'; + const cwd = process.cwd(); + const tmpCoreDir = join(tmpDir, 'core'); + const wranglerOutDir = join(tmpCoreDir, '.dist'); + const openNextOutDir = join(tmpCoreDir, '.open-next'); + const bigcommerceDistDir = join(cwd, '.bigcommerce', 'dist'); + await cp(cwd, tmpDir, { recursive: true, force: true, @@ -58,7 +65,7 @@ export const build = new Command('build') }); await addDevDependency(`@opennextjs/cloudflare@${OPENNEXTJS_CLOUDFLARE_VERSION}`, { - cwd: join(tmpDir, 'core'), + cwd: tmpCoreDir, packageManager, }); @@ -75,12 +82,52 @@ export const build = new Command('build') consola.start('Copying templates...'); - await cp(join(getModuleCliPath(), 'templates'), join(tmpDir, 'core'), { + await cp(join(getModuleCliPath(), 'templates'), tmpCoreDir, { recursive: true, force: true, }); consola.success('Templates copied'); + + consola.start('Building project...'); + + await execa('pnpm', ['exec', 'opennextjs-cloudflare', 'build'], { + stdout: ['pipe', 'inherit'], + cwd: tmpCoreDir, + }); + + await execa( + 'pnpm', + [ + 'dlx', + `wrangler@${WRANGLER_VERSION}`, + 'deploy', + '--keep-vars', + '--outdir', + wranglerOutDir, + '--dry-run', + ], + { + stdout: ['pipe', 'inherit'], + cwd: tmpCoreDir, + }, + ); + + consola.success('Project built'); + + consola.start('Copying build to project...'); + + await cp(wranglerOutDir, bigcommerceDistDir, { + recursive: true, + force: true, + }); + + await cp(join(openNextOutDir, 'assets'), join(bigcommerceDistDir, 'assets'), { + recursive: true, + force: true, + }); + + consola.success('Build copied to project'); } catch (error) { consola.error(error); process.exitCode = 1; diff --git a/packages/cli/tests/commands/build.spec.ts b/packages/cli/tests/commands/build.spec.ts index 359649dd8f..7b624ac58a 100644 --- a/packages/cli/tests/commands/build.spec.ts +++ b/packages/cli/tests/commands/build.spec.ts @@ -1,6 +1,91 @@ -import { describe, expect, test } from 'vitest'; +import { Command } from 'commander'; +import consola from 'consola'; +import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest'; -import { createFilter } from '../../src/commands/build'; +import { build, createFilter } from '../../src/commands/build'; +import { program } from '../../src/program'; + +const cleanup = vi.fn(); + +beforeAll(() => { + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + vi.spyOn(process, 'exit').mockImplementation(() => null as never); + + consola.wrapAll(); + + vi.mock('../../src/lib/mk-temp-dir', () => ({ + mkTempDir: vi.fn(() => ['/tmp/test', cleanup]), + })); + + vi.mock('node:fs/promises', () => ({ + cp: vi.fn(), + })); + + vi.mock('nypm', () => ({ + installDependencies: vi.fn(), + addDevDependency: vi.fn(), + runScript: vi.fn(), + })); + + vi.mock('execa', () => ({ + execa: vi.fn(), + })); +}); + +beforeEach(() => { + consola.mockTypes(() => vi.fn()); +}); + +afterEach(() => { + vi.clearAllMocks(); +}); + +afterAll(() => { + vi.restoreAllMocks(); +}); + +test('properly configured Command instance', () => { + expect(build).toBeInstanceOf(Command); + expect(build.name()).toBe('build'); + expect(build.options).toEqual( + expect.arrayContaining([expect.objectContaining({ flags: '--keep-temp-dir' })]), + ); +}); + +test('does not remove temp dir if --keep-temp-dir is passed', async () => { + await program.parseAsync(['node', 'catalyst', 'build', '--keep-temp-dir']); + expect(cleanup).not.toHaveBeenCalled(); +}); + +test('removes temp dir if --keep-temp-dir is not passed', async () => { + await program.parseAsync(['node', 'catalyst', 'build']); + expect(cleanup).toHaveBeenCalled(); +}); + +test('successfully builds project', async () => { + await program.parseAsync(['node', 'catalyst', 'build']); + + expect(consola.success).toHaveBeenCalledWith('Project built'); + expect(consola.success).toHaveBeenCalledWith('Build copied to project'); +}); + +test('handles error if cp throws during build', async () => { + // Dynamically mock cp for this test only + // eslint-disable-next-line import/dynamic-import-chunkname + const cpModule = await import('node:fs/promises'); + const originalCp = cpModule.cp; + const cpMock = vi.fn(() => { + throw new Error('cp failed'); + }); + + cpModule.cp = cpMock; + + await program.parseAsync(['node', 'catalyst', 'build']); + + expect(consola.error).toHaveBeenCalledWith(expect.any(Error)); + + cpModule.cp = originalCp; +}); describe('createFilter', () => { const ROOT = '/my/project'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 00adf38c8c..62eb806108 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4529,6 +4529,9 @@ packages: exsolve@1.0.5: resolution: {integrity: sha512-pz5dvkYYKQ1AHVrgOzBKWeP4u4FRb3a6DNK2ucr0OoNwYIU4QWsJ+NM36LLzORT+z845MzKHHhpXiUF5nvQoJg==} + exsolve@1.0.7: + resolution: {integrity: sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==} + extendable-error@0.1.7: resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} @@ -6243,8 +6246,8 @@ packages: pkg-types@1.3.1: resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} - pkg-types@2.1.0: - resolution: {integrity: sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==} + pkg-types@2.2.0: + resolution: {integrity: sha512-2SM/GZGAEkPp3KWORxQZns4M+WSeXbC2HEvmOIJe3Cmiv6ieAJvdVhDldtHqM5J1Y7MrR1XhkBT/rMlhh9FdqQ==} playwright-core@1.52.0: resolution: {integrity: sha512-l2osTgLXSMeuLZOML9qYODUQoPPnUsKsb5/P6LJ2e6uPKXUdPK5WYhN4z03G+YNbWmGDY4YENauNu4ZKczreHg==} @@ -11276,7 +11279,7 @@ snapshots: ohash: 2.0.11 pathe: 2.0.3 perfect-debounce: 1.0.0 - pkg-types: 2.1.0 + pkg-types: 2.2.0 rc9: 2.1.2 optionalDependencies: magicast: 0.3.5 @@ -12384,6 +12387,8 @@ snapshots: exsolve@1.0.5: {} + exsolve@1.0.7: {} + extendable-error@0.1.7: {} external-editor@3.1.0: @@ -13751,7 +13756,7 @@ snapshots: local-pkg@1.1.1: dependencies: mlly: 1.7.4 - pkg-types: 2.1.0 + pkg-types: 2.2.0 quansync: 0.2.10 localforage@1.10.0: @@ -14074,7 +14079,7 @@ snapshots: citty: 0.1.6 consola: 3.4.2 pathe: 2.0.3 - pkg-types: 2.1.0 + pkg-types: 2.2.0 tinyexec: 0.3.2 oauth4webapi@3.1.1: {} @@ -14337,10 +14342,10 @@ snapshots: mlly: 1.7.4 pathe: 2.0.3 - pkg-types@2.1.0: + pkg-types@2.2.0: dependencies: confbox: 0.2.2 - exsolve: 1.0.5 + exsolve: 1.0.7 pathe: 2.0.3 playwright-core@1.52.0: {} From 3d7f8f725def9085b510b054cfa8d7d636c9b26b Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Thu, 7 Aug 2025 13:20:52 -0500 Subject: [PATCH 009/245] feat(cli): streaming updates for deployment (#2497) * feat(cli): poll for deployment * fix: update tests * feat: update streaming logic * fix: improve spinner and tests * fix: add extra expects * feat: use zod enum for steps --- packages/cli/package.json | 1 + packages/cli/src/commands/deploy.ts | 129 +++++++++++++++- packages/cli/tests/commands/deploy.spec.ts | 169 +++++++++++++++++++-- packages/cli/tests/mocks/handlers.ts | 41 +++++ packages/cli/tests/mocks/spinner.ts | 50 ++++++ pnpm-lock.yaml | 11 ++ 6 files changed, 384 insertions(+), 17 deletions(-) create mode 100644 packages/cli/tests/mocks/spinner.ts diff --git a/packages/cli/package.json b/packages/cli/package.json index dd2e3a5e05..d2cb30155f 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -28,6 +28,7 @@ "consola": "^3.4.2", "execa": "^9.6.0", "nypm": "^0.6.0", + "yocto-spinner": "^1.0.0", "zod": "^4.0.5" }, "devDependencies": { diff --git a/packages/cli/src/commands/deploy.ts b/packages/cli/src/commands/deploy.ts index 98936310c2..eed3703340 100644 --- a/packages/cli/src/commands/deploy.ts +++ b/packages/cli/src/commands/deploy.ts @@ -3,10 +3,31 @@ import { Command, Option } from 'commander'; import { consola } from 'consola'; import { access, readdir, readFile } from 'node:fs/promises'; import { join } from 'node:path'; +import yoctoSpinner from 'yocto-spinner'; import { z } from 'zod'; import { ProjectConfig } from '../lib/project-config'; +const stepsEnum = z.enum([ + 'initializing', + 'downloading', + 'unzipping', + 'processing', + 'deploying', + 'finalizing', + 'complete', +]); + +const STEPS: Record, string> = { + initializing: 'Initializing...', + downloading: 'Downloading...', + unzipping: 'Unzipping...', + processing: 'Processing...', + deploying: 'Deploying...', + finalizing: 'Finalizing...', + complete: 'Complete', +}; + const UploadSignatureSchema = z.object({ data: z.object({ upload_url: z.url(), @@ -20,6 +41,22 @@ const CreateDeploymentSchema = z.object({ }), }); +const DeploymentStatusSchema = z.object({ + deployment_uuid: z.uuid(), + deployment_status: z.enum(['queued', 'in_progress', 'failed', 'completed']), + event: z + .object({ + step: stepsEnum, + progress: z.number(), + }) + .nullable(), + error: z + .object({ + code: z.number(), + }) + .optional(), +}); + export const generateBundleZip = async (rootDir: string) => { consola.info('Generating bundle...'); @@ -141,8 +178,82 @@ export const createDeployment = async ( return data; }; +export const getDeploymentStatus = async ( + deploymentUuid: string, + storeHash: string, + accessToken: string, + apiHost: string, +) => { + consola.info('Fetching deployment status...'); + + const spinner = yoctoSpinner().start('Fetching...'); + + const response = await fetch( + `https://${apiHost}/stores/${storeHash}/v3/headless/deployments/${deploymentUuid}/events`, + { + method: 'GET', + headers: { + 'X-Auth-Token': accessToken, + Accept: 'text/event-stream', + Connection: 'keep-alive', + }, + }, + ); + + if (!response.ok) { + throw new Error(`Failed to open event stream: ${response.status} ${response.statusText}`); + } + + const reader = response.body?.getReader(); + + if (!reader) { + throw new Error('Failed to read event stream.'); + } + + const decoder = new TextDecoder(); + let done = false; + + while (!done) { + // eslint-disable-next-line no-await-in-loop + const { value, done: streamDone } = await reader.read(); + let json: unknown; + + if (value) { + const chunk = decoder.decode(value, { stream: true }).trim(); + const split = chunk + .split('\n\n') + .map((s) => s.replace('data:', '').trim()) + .filter(Boolean); + + split.forEach((event) => { + try { + json = JSON.parse(event); + } catch (error) { + consola.warn(`Failed to parse event, dropping from stream. Event: ${event}`, error); + + return; + } + + const data = DeploymentStatusSchema.parse(json); + + if (data.error) { + throw new Error(`Deployment failed with error code: ${data.error.code}`); + } + + if (data.event && STEPS[data.event.step] !== spinner.text) { + spinner.text = STEPS[data.event.step]; + } + }); + } + + done = streamDone; + } + + spinner.success('Deployment completed successfully.'); +}; + export const deploy = new Command('deploy') - .description('Deploy the application to Cloudflare') + .description('Deploy your application to Cloudflare.') .addOption( new Option( '--store-hash ', @@ -170,11 +281,15 @@ export const deploy = new Command('deploy') 'BigCommerce headless project UUID. Can be found via the BigCommerce API (GET /v3/headless/projects).', ).env('BIGCOMMERCE_PROJECT_UUID'), ) - .option('--root-dir ', 'Root directory to deploy from.', process.cwd()) + .option( + '--root-dir ', + 'Path to the root directory of your Catalyst project (default: current working directory).', + process.cwd(), + ) .action(async (opts) => { - const config = new ProjectConfig(opts.rootDir); - try { + const config = new ProjectConfig(opts.rootDir); + const projectUuid = opts.projectUuid ?? config.get('projectUuid'); await generateBundleZip(opts.rootDir); @@ -187,7 +302,7 @@ export const deploy = new Command('deploy') await uploadBundleZip(uploadSignature.upload_url, opts.rootDir); - await createDeployment( + const { deployment_uuid: deploymentUuid } = await createDeployment( projectUuid, uploadSignature.upload_uuid, opts.storeHash, @@ -195,11 +310,9 @@ export const deploy = new Command('deploy') opts.apiHost, ); - // @todo poll for deployment status + await getDeploymentStatus(deploymentUuid, opts.storeHash, opts.accessToken, opts.apiHost); } catch (error) { consola.error(error); process.exit(1); } - - process.exit(0); }); diff --git a/packages/cli/tests/commands/deploy.spec.ts b/packages/cli/tests/commands/deploy.spec.ts index 196a6ea192..ee1b02012b 100644 --- a/packages/cli/tests/commands/deploy.spec.ts +++ b/packages/cli/tests/commands/deploy.spec.ts @@ -1,15 +1,25 @@ import AdmZip from 'adm-zip'; +import { Command } from 'commander'; +import consola from 'consola'; +import { http, HttpResponse } from 'msw'; import { mkdir, stat, writeFile } from 'node:fs/promises'; import { dirname, join } from 'node:path'; -import { afterAll, beforeAll, describe, expect, test } from 'vitest'; +import { afterAll, afterEach, beforeAll, describe, expect, test, vi } from 'vitest'; import { createDeployment, + deploy, generateBundleZip, generateUploadSignature, + getDeploymentStatus, uploadBundleZip, } from '../../src/commands/deploy'; import { mkTempDir } from '../../src/lib/mk-temp-dir'; +import { server } from '../mocks/node'; +import { textHistory } from '../mocks/spinner'; + +// eslint-disable-next-line import/dynamic-import-chunkname +vi.mock('yocto-spinner', () => import('../mocks/spinner')); let tmpDir: string; let cleanup: () => Promise; @@ -21,9 +31,11 @@ const accessToken = 'test-token'; const apiHost = 'api.bigcommerce.com'; const uploadUuid = '0e93ce5f-6f91-4236-87ec-ca79627f31ba'; const uploadUrl = 'https://mock-upload-url.com'; +const deploymentUuid = '5b29c3c0-5f68-44fe-99e5-06492babf7be'; beforeAll(async () => { - // Setup test directories and files + consola.mockTypes(() => vi.fn()); + [tmpDir, cleanup] = await mkTempDir(); const workerPath = join(tmpDir, '.bigcommerce/dist/worker.js'); @@ -37,10 +49,32 @@ beforeAll(async () => { await writeFile(join(assetsDir, 'test.txt'), 'asset file'); }); +afterEach(() => { + vi.clearAllMocks(); + + // Resets spinner text history + textHistory.length = 0; +}); + afterAll(async () => { await cleanup(); }); +test('properly configured Command instance', () => { + expect(deploy).toBeInstanceOf(Command); + expect(deploy.name()).toBe('deploy'); + expect(deploy.description()).toBe('Deploy your application to Cloudflare.'); + expect(deploy.options).toEqual( + expect.arrayContaining([ + expect.objectContaining({ flags: '--store-hash ' }), + expect.objectContaining({ flags: '--access-token ' }), + expect.objectContaining({ flags: '--api-host ', defaultValue: 'api.bigcommerce.com' }), + expect.objectContaining({ flags: '--project-uuid ' }), + expect.objectContaining({ flags: '--root-dir ', defaultValue: process.cwd() }), + ]), + ); +}); + describe('bundle zip generation and upload', () => { test('creates bundle.zip from build output', async () => { await generateBundleZip(tmpDir); @@ -49,6 +83,9 @@ describe('bundle zip generation and upload', () => { const stats = await stat(outputZip); expect(stats.size).toBeGreaterThan(0); + + expect(consola.info).toHaveBeenCalledWith('Generating bundle...'); + expect(consola.success).toHaveBeenCalledWith(`Bundle created at: ${outputZip}`); }); test('zip contains output folder with assets and worker.js', async () => { @@ -68,25 +105,31 @@ describe('bundle zip generation and upload', () => { expect(entries.some((e) => e.startsWith('output/assets/'))).toBe(true); // Check for output/worker.js expect(entries).toContain('output/worker.js'); + + expect(consola.success).toHaveBeenCalledWith(`Bundle created at: ${outputZip}`); }); - test('fetches upload signature and uploads bundle zip', async () => { - // Test generateUploadSignature + test('fetches upload signature', async () => { const signature = await generateUploadSignature(storeHash, accessToken, apiHost); + expect(consola.info).toHaveBeenCalledWith('Generating upload signature...'); + expect(consola.success).toHaveBeenCalledWith('Upload signature generated.'); + expect(signature.upload_url).toBe(uploadUrl); expect(signature.upload_uuid).toBe(uploadUuid); + }); - // Test uploadBundleZip - await generateBundleZip(tmpDir); // Ensure zip exists - + test('fetches upload signature and uploads bundle zip', async () => { const uploadResult = await uploadBundleZip(uploadUrl, tmpDir); + expect(consola.info).toHaveBeenCalledWith('Uploading bundle...'); + expect(consola.success).toHaveBeenCalledWith('Bundle uploaded successfully.'); + expect(uploadResult).toBe(true); }); }); -describe('deployment and polling', () => { +describe('deployment and event streaming', () => { test('creates a deployment', async () => { const deployment = await createDeployment( projectUuid, @@ -96,6 +139,114 @@ describe('deployment and polling', () => { apiHost, ); - expect(deployment.deployment_uuid).toBe('5b29c3c0-5f68-44fe-99e5-06492babf7be'); + expect(deployment.deployment_uuid).toBe(deploymentUuid); + }); + + test('streams deployment status until completion', async () => { + await getDeploymentStatus(deploymentUuid, storeHash, accessToken, apiHost); + + expect(consola.info).toHaveBeenCalledWith('Fetching deployment status...'); + + expect(textHistory).toEqual([ + 'Fetching...', + 'Processing...', + 'Finalizing...', + 'Deployment completed successfully.', + ]); + }); + + test('warns if event stream is incomplete or unable to be parsed', async () => { + const encoder = new TextEncoder(); + + server.use( + http.get( + 'https://:apiHost/stores/:storeHash/v3/headless/deployments/:deploymentUuid/events', + () => { + const stream = new ReadableStream({ + start(controller) { + controller.enqueue( + encoder.encode( + `data: {"deployment_status":"in_progress","deployment_uuid":"${deploymentUuid}","event":{"step":"processing","progress":75}}`, + ), + ); + setTimeout(() => { + // Incomplete stream data + controller.enqueue(encoder.encode(`data: {"deployment_status":"in_progress",`)); + }, 10); + setTimeout(() => { + controller.enqueue( + encoder.encode( + `data: {"deployment_status":"in_progress","deployment_uuid":"${deploymentUuid}","event":{"step":"finalizing","progress":99}}`, + ), + ); + controller.close(); + }, 20); + }, + }); + + return new HttpResponse(stream, { + status: 200, + headers: { 'Content-Type': 'text/event-stream' }, + }); + }, + ), + ); + + await getDeploymentStatus(deploymentUuid, storeHash, accessToken, apiHost); + + expect(consola.info).toHaveBeenCalledWith('Fetching deployment status...'); + + expect(textHistory).toEqual([ + 'Fetching...', + 'Processing...', + 'Finalizing...', + 'Deployment completed successfully.', + ]); + + expect(consola.warn).toHaveBeenCalledWith( + expect.stringContaining('Failed to parse event, dropping from stream.'), + expect.any(Error), + ); + }); + + test('handles deployment errors', async () => { + const encoder = new TextEncoder(); + + server.use( + http.get( + 'https://:apiHost/stores/:storeHash/v3/headless/deployments/:deploymentUuid/events', + () => { + const stream = new ReadableStream({ + start(controller) { + controller.enqueue( + encoder.encode( + `data: {"deployment_status":"in_progress","deployment_uuid":"${deploymentUuid}","event":{"step":"processing","progress":75}}`, + ), + ); + setTimeout(() => { + controller.enqueue( + encoder.encode( + `data: {"deployment_status":"in_progress","deployment_uuid":"${deploymentUuid}","event":{"step":"unzipping","progress":99},"error":{"code":30}}`, + ), + ); + }, 10); + }, + }); + + return new HttpResponse(stream, { + status: 200, + headers: { 'Content-Type': 'text/event-stream' }, + }); + }, + ), + ); + + await expect( + getDeploymentStatus(deploymentUuid, storeHash, accessToken, apiHost), + ).rejects.toThrow('Deployment failed with error code: 30'); + + expect(consola.info).toHaveBeenCalledWith('Fetching deployment status...'); + + expect(textHistory).toEqual(['Fetching...', 'Processing...']); }); }); diff --git a/packages/cli/tests/mocks/handlers.ts b/packages/cli/tests/mocks/handlers.ts index 202a5680f2..61ad83dd29 100644 --- a/packages/cli/tests/mocks/handlers.ts +++ b/packages/cli/tests/mocks/handlers.ts @@ -1,5 +1,7 @@ import { http, HttpResponse } from 'msw'; +const encoder = new TextEncoder(); + export const handlers = [ // Handler for generateUploadSignature http.post('https://:apiHost/stores/:storeHash/v3/headless/deployments/uploads', () => @@ -32,4 +34,43 @@ export const handlers = [ ], }), ), + + // Handler for getDeploymentStatus + http.get( + 'https://:apiHost/stores/:storeHash/v3/headless/deployments/:deploymentUuid/events', + ({ params }) => { + const stream = new ReadableStream({ + start(controller) { + controller.enqueue( + encoder.encode( + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + `data: {"deployment_status":"in_progress","deployment_uuid":"${params.deploymentUuid}","event":{"step":"processing","progress":75}}`, + ), + ); + setTimeout(() => { + controller.enqueue( + encoder.encode( + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + `data: {"deployment_status":"in_progress","deployment_uuid":"${params.deploymentUuid}","event":{"step":"finalizing","progress":99}}`, + ), + ); + }, 10); + setTimeout(() => { + controller.enqueue( + encoder.encode( + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + `data: {"deployment_status":"completed","deployment_uuid":"${params.deploymentUuid}","event":null}`, + ), + ); + controller.close(); + }, 20); + }, + }); + + return new HttpResponse(stream, { + status: 200, + headers: { 'Content-Type': 'text/event-stream' }, + }); + }, + ), ]; diff --git a/packages/cli/tests/mocks/spinner.ts b/packages/cli/tests/mocks/spinner.ts new file mode 100644 index 0000000000..ef72006e34 --- /dev/null +++ b/packages/cli/tests/mocks/spinner.ts @@ -0,0 +1,50 @@ +import { vi } from 'vitest'; + +export const textHistory: string[] = []; + +export default vi.fn().mockImplementation(({ text }: { text?: string } = {}) => { + if (text) textHistory.push(text); + + const spinner = { + _text: text ?? '', + start: vi.fn().mockImplementation((methodText?: string) => { + if (methodText) textHistory.push(methodText); + + return spinner; + }), + stop: vi.fn().mockImplementation((methodText?: string) => { + if (methodText) textHistory.push(methodText); + + return spinner; + }), + success: vi.fn().mockImplementation((methodText?: string) => { + if (methodText) textHistory.push(methodText); + + return spinner; + }), + error: vi.fn().mockImplementation((methodText?: string) => { + if (methodText) textHistory.push(methodText); + + return spinner; + }), + warning: vi.fn().mockImplementation((methodText?: string) => { + if (methodText) textHistory.push(methodText); + + return spinner; + }), + info: vi.fn().mockImplementation((methodText?: string) => { + if (methodText) textHistory.push(methodText); + + return spinner; + }), + get text() { + return this._text; + }, + set text(value: string) { + this._text = value; + textHistory.push(value); + }, + }; + + return spinner; +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 62eb806108..adb2b530f4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -306,6 +306,9 @@ importers: nypm: specifier: ^0.6.0 version: 0.6.0 + yocto-spinner: + specifier: ^1.0.0 + version: 1.0.0 zod: specifier: ^4.0.5 version: 4.0.5 @@ -7870,6 +7873,10 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + yocto-spinner@1.0.0: + resolution: {integrity: sha512-VPX8P/+Z2Fnpx8PC/JELbxp3QRrBxjAekio6yulGtA5gKt9YyRc5ycCb+NHgZCbZ0kx9KxwZp7gC6UlrCcCdSQ==} + engines: {node: '>=18.19'} + yoctocolors-cjs@2.1.2: resolution: {integrity: sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==} engines: {node: '>=18'} @@ -16196,6 +16203,10 @@ snapshots: yocto-queue@0.1.0: {} + yocto-spinner@1.0.0: + dependencies: + yoctocolors: 2.1.1 + yoctocolors-cjs@2.1.2: {} yoctocolors@2.1.1: {} From a1cdcbf6d891e9e1f1537aea995c53b0eb022ba1 Mon Sep 17 00:00:00 2001 From: Matthew Volk Date: Mon, 11 Aug 2025 10:27:14 -0500 Subject: [PATCH 010/245] feat: introduce telemetry to catalyst cli (#2514) --- packages/cli/package.json | 1 + packages/cli/src/commands/deploy.ts | 5 ++ packages/cli/src/commands/link.ts | 5 ++ packages/cli/src/commands/telemetry.ts | 43 +++++++++ packages/cli/src/hooks/telemetry.ts | 50 +++++++++++ packages/cli/src/lib/project-config.ts | 15 +++- packages/cli/src/lib/telemetry.ts | 106 +++++++++++++++++++++++ packages/cli/src/program.ts | 7 +- packages/cli/tests/commands/link.spec.ts | 25 ++++++ packages/cli/tests/index.spec.ts | 20 ++++- packages/cli/tests/vitest.setup.ts | 17 +++- packages/cli/tsup.config.ts | 3 + pnpm-lock.yaml | 20 +++-- 13 files changed, 304 insertions(+), 13 deletions(-) create mode 100644 packages/cli/src/commands/telemetry.ts create mode 100644 packages/cli/src/hooks/telemetry.ts create mode 100644 packages/cli/src/lib/telemetry.ts diff --git a/packages/cli/package.json b/packages/cli/package.json index d2cb30155f..48e15749f7 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -22,6 +22,7 @@ "node": "^20.0.0 || ^22.0.0" }, "dependencies": { + "@segment/analytics-node": "^2.2.1", "adm-zip": "^0.5.16", "commander": "^14.0.0", "conf": "^13.1.0", diff --git a/packages/cli/src/commands/deploy.ts b/packages/cli/src/commands/deploy.ts index eed3703340..95ddd0bf60 100644 --- a/packages/cli/src/commands/deploy.ts +++ b/packages/cli/src/commands/deploy.ts @@ -7,6 +7,9 @@ import yoctoSpinner from 'yocto-spinner'; import { z } from 'zod'; import { ProjectConfig } from '../lib/project-config'; +import { Telemetry } from '../lib/telemetry'; + +const telemetry = new Telemetry(); const stepsEnum = z.enum([ 'initializing', @@ -290,6 +293,8 @@ export const deploy = new Command('deploy') try { const config = new ProjectConfig(opts.rootDir); + await telemetry.identify(opts.storeHash); + const projectUuid = opts.projectUuid ?? config.get('projectUuid'); await generateBundleZip(opts.rootDir); diff --git a/packages/cli/src/commands/link.ts b/packages/cli/src/commands/link.ts index 8e39b742a4..1f765e0237 100644 --- a/packages/cli/src/commands/link.ts +++ b/packages/cli/src/commands/link.ts @@ -3,6 +3,9 @@ import consola from 'consola'; import z from 'zod'; import { ProjectConfig } from '../lib/project-config'; +import { Telemetry } from '../lib/telemetry'; + +const telemetry = new Telemetry(); const fetchProjectsSchema = z.object({ data: z.array( @@ -86,6 +89,8 @@ export const link = new Command('link') } if (options.storeHash && options.accessToken) { + await telemetry.identify(options.storeHash); + consola.start('Fetching projects...'); const projects = await fetchProjects( diff --git a/packages/cli/src/commands/telemetry.ts b/packages/cli/src/commands/telemetry.ts new file mode 100644 index 0000000000..81343f45cc --- /dev/null +++ b/packages/cli/src/commands/telemetry.ts @@ -0,0 +1,43 @@ +import { Argument, Command, Option } from 'commander'; +import consola from 'consola'; +import { colorize } from 'consola/utils'; + +import { Telemetry } from '../lib/telemetry'; + +const telemetryService = new Telemetry(); +let isEnabled = telemetryService.isEnabled(); + +export const telemetry = new Command('telemetry') + .addArgument(new Argument('[arg]').choices(['disable', 'enable', 'status'])) + .addOption(new Option('--enable', `Enables CLI telemetry collection.`).conflicts('disable')) + .option('--disable', `Disables CLI telemetry collection.`) + .action((arg, options) => { + if (options.enable || arg === 'enable') { + telemetryService.setEnabled(true); + isEnabled = true; + + consola.success('Success!\n'); + } else if (options.disable || arg === 'disable') { + telemetryService.setEnabled(false); + + if (isEnabled) { + consola.success('Your preference has been saved to .bigcommerce/project.json'); + } else { + consola.info(`Catalyst CLI telemetry collection is already disabled.`); + } + + isEnabled = false; + } else { + consola.info('Catalyst CLI Telemetry\n'); + } + + consola.info( + `Status: ${colorize('bold', isEnabled ? colorize('green', 'Enabled') : colorize('red', 'Disabled'))}`, + ); + + if (!isEnabled) { + consola.info( + `You have opted-out of Catalyst CLI telemetry. No data will be collected from your machine.`, + ); + } + }); diff --git a/packages/cli/src/hooks/telemetry.ts b/packages/cli/src/hooks/telemetry.ts new file mode 100644 index 0000000000..c9e3de7a80 --- /dev/null +++ b/packages/cli/src/hooks/telemetry.ts @@ -0,0 +1,50 @@ +import { Command } from '@commander-js/extra-typings'; + +import { Telemetry } from '../lib/telemetry'; + +const telemetry = new Telemetry(); + +const allowlistArguments = ['--keep-temp-dir', '--api-host', '--project-uuid']; + +function parseArguments(args: string[]) { + return args.reduce>((result, arg, index, array) => { + if (arg.includes('=')) { + const [key, value] = arg.split('='); + + if (allowlistArguments.includes(key)) { + return { + ...result, + [key]: value, + }; + } + } + + if (allowlistArguments.includes(arg)) { + const nextValue = + array[index + 1] && !array[index + 1].startsWith('--') ? array[index + 1] : null; + + if (nextValue && !nextValue.includes('--')) { + return { + ...result, + [arg]: nextValue, + }; + } + } + + return result; + }, {}); +} + +export const telemetryPreHook = async (command: Command) => { + const [commandName, ...args] = command.args; + + // Return the await to get a proper stack trace. + // eslint-disable-next-line @typescript-eslint/no-confusing-void-expression + return await telemetry.track(commandName, { + ...parseArguments(args), + }); +}; + +export const telemetryPostHook = async () => { + await telemetry.analytics.closeAndFlush(); +}; diff --git a/packages/cli/src/lib/project-config.ts b/packages/cli/src/lib/project-config.ts index 739c26350c..354c323c2a 100644 --- a/packages/cli/src/lib/project-config.ts +++ b/packages/cli/src/lib/project-config.ts @@ -4,6 +4,10 @@ import { join } from 'path'; export interface ProjectConfigSchema { projectUuid: string; framework: 'catalyst' | 'nextjs'; + telemetry: { + enabled: boolean; + anonymousId: string; + }; } export class ProjectConfig { @@ -21,11 +25,18 @@ export class ProjectConfig { enum: ['catalyst', 'nextjs'], default: 'catalyst', }, + telemetry: { + type: 'object', + properties: { + enabled: { type: 'boolean' }, + anonymousId: { type: 'string' }, + }, + }, }, }); } - get(field: keyof ProjectConfigSchema): string { + get(field: T): ProjectConfigSchema[T] { const value = this.config.get(field); if (!value) { @@ -35,7 +46,7 @@ export class ProjectConfig { return value; } - set(field: string, value: string): void { + set(field: string, value: string | boolean): void { this.config.set(field, value); } } diff --git a/packages/cli/src/lib/telemetry.ts b/packages/cli/src/lib/telemetry.ts new file mode 100644 index 0000000000..aa4bb66c0e --- /dev/null +++ b/packages/cli/src/lib/telemetry.ts @@ -0,0 +1,106 @@ +import { Analytics } from '@segment/analytics-node'; +import { randomBytes } from 'node:crypto'; + +import PACKAGE_INFO from '../../package.json'; + +import { ProjectConfig } from './project-config'; + +export class Telemetry { + readonly sessionId: string; + readonly analytics: Analytics; + + private projectConfig: ProjectConfig; + private CATALYST_TELEMETRY_DISABLED: string | undefined; + + private readonly projectName = 'catalyst-cli'; + private readonly projectVersion = PACKAGE_INFO.version; + + constructor() { + this.CATALYST_TELEMETRY_DISABLED = process.env.CATALYST_TELEMETRY_DISABLED; + + this.projectConfig = new ProjectConfig(); + + this.sessionId = randomBytes(32).toString('hex'); + this.analytics = new Analytics({ + writeKey: process.env.CLI_SEGMENT_WRITE_KEY ?? 'not-a-valid-segment-write-key', + }); + } + + async track(eventName: string, payload: Record) { + if (!this.isEnabled()) { + return Promise.resolve(undefined); + } + + this.analytics.track({ + event: eventName, + anonymousId: this.getAnonymousId(), + properties: { + ...payload, + sessionId: this.sessionId, + }, + context: { + app: { + name: this.projectName, + version: this.projectVersion, + }, + }, + }); + } + + async identify(storeHash?: string) { + if (!this.isEnabled()) { + return Promise.resolve(undefined); + } + + if (!storeHash) { + return Promise.resolve(undefined); + } + + this.analytics.identify({ + userId: storeHash, + anonymousId: this.getAnonymousId(), + context: { + app: { + name: this.projectName, + version: this.projectVersion, + }, + }, + }); + } + + setEnabled = (_enabled: boolean) => { + const enabled = Boolean(_enabled); + + this.projectConfig.set('telemetry.enabled', enabled); + }; + + isEnabled() { + try { + return !this.CATALYST_TELEMETRY_DISABLED && this.projectConfig.get('telemetry').enabled; + } catch { + return false; + } + } + + private getAnonymousId(): string { + let anonymousId; + + try { + anonymousId = this.projectConfig.get('telemetry').anonymousId; + + if (!anonymousId) { + anonymousId = randomBytes(32).toString('hex'); + + this.projectConfig.set('telemetry.anonymousId', anonymousId); + } + + return anonymousId; + } catch { + const generated = randomBytes(32).toString('hex'); + + this.projectConfig.set('telemetry.anonymousId', generated); + + return generated; + } + } +} diff --git a/packages/cli/src/program.ts b/packages/cli/src/program.ts index f970489532..1570a1ba38 100644 --- a/packages/cli/src/program.ts +++ b/packages/cli/src/program.ts @@ -9,7 +9,9 @@ import { deploy } from './commands/deploy'; import { dev } from './commands/dev'; import { link } from './commands/link'; import { start } from './commands/start'; +import { telemetry } from './commands/telemetry'; import { version } from './commands/version'; +import { telemetryPostHook, telemetryPreHook } from './hooks/telemetry'; export const program = new Command(); @@ -24,4 +26,7 @@ program .addCommand(start) .addCommand(build) .addCommand(deploy) - .addCommand(link); + .addCommand(link) + .addCommand(telemetry) + .hook('preAction', telemetryPreHook) + .hook('postAction', telemetryPostHook); diff --git a/packages/cli/tests/commands/link.spec.ts b/packages/cli/tests/commands/link.spec.ts index 6e1f82fc8a..fcf20419f7 100644 --- a/packages/cli/tests/commands/link.spec.ts +++ b/packages/cli/tests/commands/link.spec.ts @@ -15,6 +15,10 @@ let tmpDir: string; let cleanup: () => Promise; let config: ProjectConfig; +const { mockIdentify } = vi.hoisted(() => ({ + mockIdentify: vi.fn(), +})); + const projectUuid1 = 'a23f5785-fd99-4a94-9fb3-945551623923'; const projectUuid2 = 'b23f5785-fd99-4a94-9fb3-945551623924'; const storeHash = 'test-store'; @@ -23,6 +27,21 @@ const accessToken = 'test-token'; beforeAll(async () => { consola.mockTypes(() => vi.fn()); + vi.mock('../../src/lib/telemetry', () => { + return { + Telemetry: vi.fn().mockImplementation(() => { + return { + identify: mockIdentify, + isEnabled: vi.fn(() => true), + track: vi.fn(), + analytics: { + closeAndFlush: vi.fn(), + }, + }; + }), + }; + }); + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions exitMock = vi.spyOn(process, 'exit').mockImplementation(() => null as never); @@ -114,6 +133,8 @@ test('fetches projects and prompts user to select one', async () => { tmpDir, ]); + expect(mockIdentify).toHaveBeenCalledWith(storeHash); + expect(consola.start).toHaveBeenCalledWith('Fetching projects...'); expect(consola.success).toHaveBeenCalledWith('Projects fetched.'); @@ -153,6 +174,8 @@ test('errors when no projects are found', async () => { tmpDir, ]); + expect(mockIdentify).toHaveBeenCalledWith(storeHash); + expect(consola.start).toHaveBeenCalledWith('Fetching projects...'); expect(consola.error).toHaveBeenCalledWith('No headless projects found for this store.'); expect(exitMock).toHaveBeenCalledWith(1); @@ -176,6 +199,8 @@ test('errors when headless projects API is not found', async () => { tmpDir, ]); + expect(mockIdentify).toHaveBeenCalledWith(storeHash); + expect(consola.start).toHaveBeenCalledWith('Fetching projects...'); expect(consola.error).toHaveBeenCalledWith( 'Headless Projects API not enabled. If you are part of the alpha, contact support@bigcommerce.com to enable it.', diff --git a/packages/cli/tests/index.spec.ts b/packages/cli/tests/index.spec.ts index c4ab81613d..bbcf9b656f 100644 --- a/packages/cli/tests/index.spec.ts +++ b/packages/cli/tests/index.spec.ts @@ -1,6 +1,12 @@ import { Command } from '@commander-js/extra-typings'; -import { describe, expect, test } from 'vitest'; +import { describe, expect, test, vi } from 'vitest'; +vi.mock('../src/hooks/telemetry', () => ({ + telemetryPreHook: vi.fn().mockResolvedValue(undefined), + telemetryPostHook: vi.fn().mockResolvedValue(undefined), +})); + +import { telemetryPostHook, telemetryPreHook } from '../src/hooks/telemetry'; import { program } from '../src/program'; describe('CLI program', () => { @@ -21,4 +27,16 @@ describe('CLI program', () => { expect(commands).toContain('deploy'); expect(commands).toContain('link'); }); + + test('telemetry hooks are called when executing version command', async () => { + vi.mocked(telemetryPreHook).mockClear(); + vi.mocked(telemetryPostHook).mockClear(); + + await program.parseAsync(['version'], { from: 'user' }); + + expect(telemetryPreHook).toHaveBeenCalledTimes(1); + expect(telemetryPostHook).toHaveBeenCalledTimes(1); + + expect(telemetryPreHook).toHaveBeenCalledWith(expect.any(Command), expect.any(Command)); + }); }); diff --git a/packages/cli/tests/vitest.setup.ts b/packages/cli/tests/vitest.setup.ts index 70ed4d82a6..22d99161e2 100644 --- a/packages/cli/tests/vitest.setup.ts +++ b/packages/cli/tests/vitest.setup.ts @@ -1,7 +1,22 @@ -import { afterAll, afterEach, beforeAll } from 'vitest'; +import { afterAll, afterEach, beforeAll, vi } from 'vitest'; import { server } from './mocks/node'; +vi.mock('../src/lib/telemetry', () => ({ + Telemetry: vi.fn().mockImplementation(() => ({ + sessionId: 'test-session-id', + analytics: { + track: vi.fn(), + identify: vi.fn(), + closeAndFlush: vi.fn().mockResolvedValue(undefined), + }, + track: vi.fn().mockResolvedValue(undefined), + identify: vi.fn().mockResolvedValue(undefined), + setEnabled: vi.fn(), + isEnabled: vi.fn().mockReturnValue(false), + })), +})); + beforeAll(() => server.listen()); afterEach(() => server.resetHandlers()); afterAll(() => server.close()); diff --git a/packages/cli/tsup.config.ts b/packages/cli/tsup.config.ts index 80eb3291df..175ef8047f 100644 --- a/packages/cli/tsup.config.ts +++ b/packages/cli/tsup.config.ts @@ -5,5 +5,8 @@ export default defineConfig((options: Options) => ({ format: ['esm'], clean: !options.watch, sourcemap: true, + env: { + CLI_SEGMENT_WRITE_KEY: process.env.CLI_SEGMENT_WRITE_KEY ?? 'not-a-valid-segment-write-key', + }, ...options, })); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index adb2b530f4..2759526945 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -288,6 +288,9 @@ importers: packages/cli: dependencies: + '@segment/analytics-node': + specifier: ^2.2.1 + version: 2.2.1(encoding@0.1.13) adm-zip: specifier: ^0.5.16 version: 0.5.16 @@ -7014,6 +7017,7 @@ packages: source-map@0.8.0-beta.0: resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} engines: {node: '>= 8'} + deprecated: The work that was done in this beta branch won't be included in future versions spawndamnit@3.0.1: resolution: {integrity: sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==} @@ -8131,9 +8135,9 @@ snapshots: '@typescript-eslint/parser': 8.28.0(eslint@8.57.1)(typescript@5.8.3) eslint: 8.57.1 eslint-config-prettier: 9.1.0(eslint@8.57.1) - eslint-import-resolver-typescript: 3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1) + eslint-import-resolver-typescript: 3.9.1(eslint-plugin-import@2.31.0)(eslint@8.57.1) eslint-plugin-gettext: 1.2.0 - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1)(eslint@8.57.1) eslint-plugin-jest: 28.11.0(@typescript-eslint/eslint-plugin@8.28.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(jest@29.7.0(@types/node@22.15.30)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)))(typescript@5.8.3) eslint-plugin-jest-dom: 5.5.0(eslint@8.57.1) eslint-plugin-jest-formatting: 3.1.0(eslint@8.57.1) @@ -12039,8 +12043,8 @@ snapshots: '@typescript-eslint/parser': 8.28.0(eslint@8.57.1)(typescript@5.8.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) + eslint-import-resolver-typescript: 3.9.1(eslint-plugin-import@2.31.0)(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1)(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1) eslint-plugin-react: 7.37.4(eslint@8.57.1) eslint-plugin-react-hooks: 5.2.0(eslint@8.57.1) @@ -12067,7 +12071,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1): + eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0)(eslint@8.57.1): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.1 @@ -12078,7 +12082,7 @@ snapshots: stable-hash: 0.0.5 tinyglobby: 0.2.14 optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1)(eslint@8.57.1) transitivePeerDependencies: - supports-color @@ -12089,7 +12093,7 @@ snapshots: '@typescript-eslint/parser': 8.28.0(eslint@8.57.1)(typescript@5.8.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1) + eslint-import-resolver-typescript: 3.9.1(eslint-plugin-import@2.31.0)(eslint@8.57.1) transitivePeerDependencies: - supports-color @@ -12103,7 +12107,7 @@ snapshots: dependencies: gettext-parser: 4.2.0 - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1)(eslint@8.57.1): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 From 0b58e589ce0b7be6088955c08632b72cdef870ce Mon Sep 17 00:00:00 2001 From: Matthew Volk Date: Mon, 11 Aug 2025 13:36:00 -0500 Subject: [PATCH 011/245] refactor: unwrap get and set instance methods of conf (#2516) --- packages/cli/src/commands/deploy.ts | 10 +++- packages/cli/src/commands/link.ts | 4 +- packages/cli/src/lib/project-config.ts | 56 +++++++------------ packages/cli/src/lib/telemetry.ts | 41 ++++++-------- packages/cli/tests/commands/link.spec.ts | 7 ++- packages/cli/tests/lib/project-config.spec.ts | 18 ++---- 6 files changed, 55 insertions(+), 81 deletions(-) diff --git a/packages/cli/src/commands/deploy.ts b/packages/cli/src/commands/deploy.ts index 95ddd0bf60..fefb51e6f1 100644 --- a/packages/cli/src/commands/deploy.ts +++ b/packages/cli/src/commands/deploy.ts @@ -6,7 +6,7 @@ import { join } from 'node:path'; import yoctoSpinner from 'yocto-spinner'; import { z } from 'zod'; -import { ProjectConfig } from '../lib/project-config'; +import { getProjectConfig } from '../lib/project-config'; import { Telemetry } from '../lib/telemetry'; const telemetry = new Telemetry(); @@ -291,12 +291,18 @@ export const deploy = new Command('deploy') ) .action(async (opts) => { try { - const config = new ProjectConfig(opts.rootDir); + const config = getProjectConfig(opts.rootDir); await telemetry.identify(opts.storeHash); const projectUuid = opts.projectUuid ?? config.get('projectUuid'); + if (!projectUuid) { + throw new Error( + 'Project UUID is required. Please run either `bigcommerce link` or this command again with --project-uuid .', + ); + } + await generateBundleZip(opts.rootDir); const uploadSignature = await generateUploadSignature( diff --git a/packages/cli/src/commands/link.ts b/packages/cli/src/commands/link.ts index 1f765e0237..f3bd6fa523 100644 --- a/packages/cli/src/commands/link.ts +++ b/packages/cli/src/commands/link.ts @@ -2,7 +2,7 @@ import { Command, Option } from 'commander'; import consola from 'consola'; import z from 'zod'; -import { ProjectConfig } from '../lib/project-config'; +import { getProjectConfig } from '../lib/project-config'; import { Telemetry } from '../lib/telemetry'; const telemetry = new Telemetry(); @@ -73,7 +73,7 @@ export const link = new Command('link') ) .action(async (options) => { try { - const config = new ProjectConfig(options.rootDir); + const config = getProjectConfig(options.rootDir); const writeProjectConfig = (uuid: string) => { consola.start('Writing project UUID to .bigcommerce/project.json...'); diff --git a/packages/cli/src/lib/project-config.ts b/packages/cli/src/lib/project-config.ts index 354c323c2a..6691e50288 100644 --- a/packages/cli/src/lib/project-config.ts +++ b/packages/cli/src/lib/project-config.ts @@ -10,43 +10,25 @@ export interface ProjectConfigSchema { }; } -export class ProjectConfig { - private config: Conf; - - constructor(rootDir = process.cwd()) { - this.config = new Conf({ - cwd: join(rootDir, '.bigcommerce'), - projectSuffix: '', - configName: 'project', - schema: { - projectUuid: { type: 'string', format: 'uuid' }, - framework: { - type: 'string', - enum: ['catalyst', 'nextjs'], - default: 'catalyst', - }, - telemetry: { - type: 'object', - properties: { - enabled: { type: 'boolean' }, - anonymousId: { type: 'string' }, - }, +export function getProjectConfig(rootDir = process.cwd()) { + return new Conf({ + cwd: join(rootDir, '.bigcommerce'), + projectSuffix: '', + configName: 'project', + schema: { + projectUuid: { type: 'string', format: 'uuid' }, + framework: { + type: 'string', + enum: ['catalyst', 'nextjs'], + default: 'catalyst', + }, + telemetry: { + type: 'object', + properties: { + enabled: { type: 'boolean' }, + anonymousId: { type: 'string' }, }, }, - }); - } - - get(field: T): ProjectConfigSchema[T] { - const value = this.config.get(field); - - if (!value) { - throw new Error(`No \`${field}\` found in .bigcommerce/project.json.`); - } - - return value; - } - - set(field: string, value: string | boolean): void { - this.config.set(field, value); - } + }, + }); } diff --git a/packages/cli/src/lib/telemetry.ts b/packages/cli/src/lib/telemetry.ts index aa4bb66c0e..509be9052d 100644 --- a/packages/cli/src/lib/telemetry.ts +++ b/packages/cli/src/lib/telemetry.ts @@ -1,15 +1,19 @@ import { Analytics } from '@segment/analytics-node'; +import Conf from 'conf'; import { randomBytes } from 'node:crypto'; import PACKAGE_INFO from '../../package.json'; -import { ProjectConfig } from './project-config'; +import { getProjectConfig, ProjectConfigSchema } from './project-config'; + +const TELEMETRY_KEY_ENABLED = 'telemetry.enabled'; +const TELEMETRY_KEY_ID = `telemetry.anonymousId`; export class Telemetry { readonly sessionId: string; readonly analytics: Analytics; - private projectConfig: ProjectConfig; + private projectConfig: Conf; private CATALYST_TELEMETRY_DISABLED: string | undefined; private readonly projectName = 'catalyst-cli'; @@ -18,7 +22,7 @@ export class Telemetry { constructor() { this.CATALYST_TELEMETRY_DISABLED = process.env.CATALYST_TELEMETRY_DISABLED; - this.projectConfig = new ProjectConfig(); + this.projectConfig = getProjectConfig(); this.sessionId = randomBytes(32).toString('hex'); this.analytics = new Analytics({ @@ -75,32 +79,23 @@ export class Telemetry { }; isEnabled() { - try { - return !this.CATALYST_TELEMETRY_DISABLED && this.projectConfig.get('telemetry').enabled; - } catch { - return false; - } + return ( + !this.CATALYST_TELEMETRY_DISABLED && + this.projectConfig.get(TELEMETRY_KEY_ENABLED, true) + ); } private getAnonymousId(): string { - let anonymousId; - - try { - anonymousId = this.projectConfig.get('telemetry').anonymousId; + const val = this.projectConfig.get(TELEMETRY_KEY_ID); - if (!anonymousId) { - anonymousId = randomBytes(32).toString('hex'); - - this.projectConfig.set('telemetry.anonymousId', anonymousId); - } + if (val) { + return val; + } - return anonymousId; - } catch { - const generated = randomBytes(32).toString('hex'); + const generated = randomBytes(32).toString('hex'); - this.projectConfig.set('telemetry.anonymousId', generated); + this.projectConfig.set(TELEMETRY_KEY_ID, generated); - return generated; - } + return generated; } } diff --git a/packages/cli/tests/commands/link.spec.ts b/packages/cli/tests/commands/link.spec.ts index fcf20419f7..2ab769bf41 100644 --- a/packages/cli/tests/commands/link.spec.ts +++ b/packages/cli/tests/commands/link.spec.ts @@ -1,11 +1,12 @@ import { Command } from 'commander'; +import Conf from 'conf'; import consola from 'consola'; import { http, HttpResponse } from 'msw'; import { afterAll, afterEach, beforeAll, expect, MockInstance, test, vi } from 'vitest'; import { link } from '../../src/commands/link'; import { mkTempDir } from '../../src/lib/mk-temp-dir'; -import { ProjectConfig } from '../../src/lib/project-config'; +import { getProjectConfig, ProjectConfigSchema } from '../../src/lib/project-config'; import { program } from '../../src/program'; import { server } from '../mocks/node'; @@ -13,7 +14,7 @@ let exitMock: MockInstance; let tmpDir: string; let cleanup: () => Promise; -let config: ProjectConfig; +let config: Conf; const { mockIdentify } = vi.hoisted(() => ({ mockIdentify: vi.fn(), @@ -47,7 +48,7 @@ beforeAll(async () => { [tmpDir, cleanup] = await mkTempDir(); - config = new ProjectConfig(tmpDir); + config = getProjectConfig(tmpDir); }); afterEach(() => { diff --git a/packages/cli/tests/lib/project-config.spec.ts b/packages/cli/tests/lib/project-config.spec.ts index c75143a204..b5c92fb0bb 100644 --- a/packages/cli/tests/lib/project-config.spec.ts +++ b/packages/cli/tests/lib/project-config.spec.ts @@ -1,37 +1,27 @@ +import Conf from 'conf'; import { mkdir, writeFile } from 'node:fs/promises'; import { dirname, join } from 'node:path'; import { afterAll, beforeAll, expect, test } from 'vitest'; import { mkTempDir } from '../../src/lib/mk-temp-dir'; -import { ProjectConfig } from '../../src/lib/project-config'; +import { getProjectConfig, ProjectConfigSchema } from '../../src/lib/project-config'; let tmpDir: string; let cleanup: () => Promise; -let config: ProjectConfig; +let config: Conf; const projectUuid = 'a23f5785-fd99-4a94-9fb3-945551623923'; beforeAll(async () => { [tmpDir, cleanup] = await mkTempDir(); - config = new ProjectConfig(tmpDir); + config = getProjectConfig(tmpDir); }); afterAll(async () => { await cleanup(); }); -test('throws error if field is missing', async () => { - const projectJsonPath = join(tmpDir, '.bigcommerce/project.json'); - - await mkdir(dirname(projectJsonPath), { recursive: true }); - await writeFile(projectJsonPath, JSON.stringify({})); - - expect(() => config.get('projectUuid')).toThrowError( - 'No `projectUuid` found in .bigcommerce/project.json.', - ); -}); - test('throws error if field does not match schema', async () => { const projectJsonPath = join(tmpDir, '.bigcommerce/project.json'); From 6f6a8af4fd7a5754b9d08aef75c4e40ab3057318 Mon Sep 17 00:00:00 2001 From: Nathan Booker Date: Wed, 13 Aug 2025 17:33:31 -0500 Subject: [PATCH 012/245] Preconnect to checkout origin on cart page (#2521) --- .changeset/smooth-rats-rule.md | 5 +++++ .../(default)/cart/_components/checkout-preconnect.tsx | 9 +++++++++ core/app/[locale]/(default)/cart/page-data.ts | 5 +++++ core/app/[locale]/(default)/cart/page.tsx | 4 ++++ 4 files changed, 23 insertions(+) create mode 100644 .changeset/smooth-rats-rule.md create mode 100644 core/app/[locale]/(default)/cart/_components/checkout-preconnect.tsx diff --git a/.changeset/smooth-rats-rule.md b/.changeset/smooth-rats-rule.md new file mode 100644 index 0000000000..17e5a2cdc2 --- /dev/null +++ b/.changeset/smooth-rats-rule.md @@ -0,0 +1,5 @@ +--- +"@bigcommerce/catalyst-core": patch +--- + +Preconnect to checkout domain on cart page to improve checkout load time diff --git a/core/app/[locale]/(default)/cart/_components/checkout-preconnect.tsx b/core/app/[locale]/(default)/cart/_components/checkout-preconnect.tsx new file mode 100644 index 0000000000..0b39432674 --- /dev/null +++ b/core/app/[locale]/(default)/cart/_components/checkout-preconnect.tsx @@ -0,0 +1,9 @@ +'use client'; + +import { preconnect } from 'react-dom'; + +export function CheckoutPreconnect({ url }: { url: string }) { + preconnect(url); + + return null; +} diff --git a/core/app/[locale]/(default)/cart/page-data.ts b/core/app/[locale]/(default)/cart/page-data.ts index 7c6733d455..21e5f5c260 100644 --- a/core/app/[locale]/(default)/cart/page-data.ts +++ b/core/app/[locale]/(default)/cart/page-data.ts @@ -190,6 +190,11 @@ const CartPageQuery = graphql( ` query CartPageQuery($cartId: String) { site { + settings { + url { + checkoutUrl + } + } cart(entityId: $cartId) { entityId version diff --git a/core/app/[locale]/(default)/cart/page.tsx b/core/app/[locale]/(default)/cart/page.tsx index 0dd0d4044c..df61e28227 100644 --- a/core/app/[locale]/(default)/cart/page.tsx +++ b/core/app/[locale]/(default)/cart/page.tsx @@ -12,6 +12,7 @@ import { updateCouponCode } from './_actions/update-coupon-code'; import { updateLineItem } from './_actions/update-line-item'; import { updateShippingInfo } from './_actions/update-shipping-info'; import { CartViewed } from './_components/cart-viewed'; +import { CheckoutPreconnect } from './_components/checkout-preconnect'; import { getCart, getShippingCountries } from './page-data'; interface Props { @@ -152,9 +153,12 @@ export default async function Cart({ params }: Props) { const showShippingForm = shippingConsignment?.address && !shippingConsignment.selectedShippingOption; + const checkoutUrl = data.site.settings?.url.checkoutUrl; + return ( <> getAnalyticsData(cartId))}> + {checkoutUrl ? : null} Date: Mon, 18 Aug 2025 12:18:10 -0500 Subject: [PATCH 013/245] refactor: proxy all valid next start and dev options (#2523) --- packages/cli/src/commands/dev.ts | 26 +++++++++++++++-------- packages/cli/src/commands/start.ts | 26 +++++++++++++++-------- packages/cli/tests/commands/dev.spec.ts | 24 ++++++--------------- packages/cli/tests/commands/start.spec.ts | 24 ++++++--------------- 4 files changed, 48 insertions(+), 52 deletions(-) diff --git a/packages/cli/src/commands/dev.ts b/packages/cli/src/commands/dev.ts index 928f52e2ef..64d3330c20 100644 --- a/packages/cli/src/commands/dev.ts +++ b/packages/cli/src/commands/dev.ts @@ -1,23 +1,31 @@ import { Command } from 'commander'; import consola from 'consola'; import { execa } from 'execa'; +import { existsSync } from 'node:fs'; import { join } from 'node:path'; export const dev = new Command('dev') .description('Start the Catalyst development server.') - .option('-p, --port ', 'Port to run the development server on (default: 3000).', '3000') - .option( - '--root-dir ', - 'Path to the root directory of your Catalyst project (default: current working directory).', - process.cwd(), + // Proxy `--help` to the underlying `next dev` command + .helpOption(false) + .allowUnknownOption(true) + .argument( + '[options...]', + 'Next.js `dev` options (see: https://nextjs.org/docs/app/api-reference/cli/next#next-dev-options)', ) - .action(async (opts) => { + .action(async (options) => { try { - const nextBin = join(opts.rootDir, 'node_modules', '.bin', 'next'); + const nextBin = join('node_modules', '.bin', 'next'); - await execa(nextBin, ['dev', '-p', opts.port], { + if (!existsSync(nextBin)) { + throw new Error( + `Next.js is not installed in ${process.cwd()}. Are you in a valid Next.js project?`, + ); + } + + await execa(nextBin, ['dev', ...options], { stdio: 'inherit', - cwd: opts.rootDir, + cwd: process.cwd(), }); } catch (error) { consola.error(error instanceof Error ? error.message : error); diff --git a/packages/cli/src/commands/start.ts b/packages/cli/src/commands/start.ts index 7d6bf3a058..a94508494d 100644 --- a/packages/cli/src/commands/start.ts +++ b/packages/cli/src/commands/start.ts @@ -1,24 +1,32 @@ import { Command } from 'commander'; import consola from 'consola'; import { execa } from 'execa'; +import { existsSync } from 'node:fs'; import { join } from 'node:path'; export const start = new Command('start') .description('Start your Catalyst storefront in optimized production mode.') - .option('-p, --port ', 'Port to run the production server on (default: 3000).', '3000') - .option( - '--root-dir ', - 'Path to the root directory of your Catalyst project (default: current working directory).', - process.cwd(), + // Proxy `--help` to the underlying `next start` command + .helpOption(false) + .allowUnknownOption(true) + .argument( + '[options...]', + 'Next.js `start` options (see: https://nextjs.org/docs/app/api-reference/cli/next#next-start-options)', ) - .action(async (opts) => { + .action(async (options) => { try { - const nextBin = join(opts.rootDir, 'node_modules', '.bin', 'next'); + const nextBin = join('node_modules', '.bin', 'next'); + + if (!existsSync(nextBin)) { + throw new Error( + `Next.js is not installed in ${process.cwd()}. Are you in a valid Next.js project?`, + ); + } // @todo conditionally run `next start` or `opennextjs-cloudflare preview` based on the framework type - await execa(nextBin, ['start', '-p', opts.port], { + await execa(nextBin, ['start', ...options], { stdio: 'inherit', - cwd: opts.rootDir, + cwd: process.cwd(), }); } catch (error) { consola.error(error instanceof Error ? error.message : error); diff --git a/packages/cli/tests/commands/dev.spec.ts b/packages/cli/tests/commands/dev.spec.ts index 41f8df96e4..07f00f0c8f 100644 --- a/packages/cli/tests/commands/dev.spec.ts +++ b/packages/cli/tests/commands/dev.spec.ts @@ -5,6 +5,10 @@ import { expect, test, vi } from 'vitest'; import { dev } from '../../src/commands/dev'; import { program } from '../../src/program'; +vi.mock('node:fs', () => ({ + existsSync: vi.fn(() => true), +})); + vi.mock('execa', () => ({ execa: vi.fn(() => Promise.resolve({ stdout: '' })), __esModule: true, @@ -14,31 +18,17 @@ test('properly configured Command instance', () => { expect(dev).toBeInstanceOf(Command); expect(dev.name()).toBe('dev'); expect(dev.description()).toBe('Start the Catalyst development server.'); - expect(dev.options).toEqual( - expect.arrayContaining([ - expect.objectContaining({ flags: '-p, --port ', defaultValue: '3000' }), - expect.objectContaining({ flags: '--root-dir ', defaultValue: process.cwd() }), - ]), - ); }); test('calls execa with Next.js development server', async () => { - await program.parseAsync([ - 'node', - 'catalyst', - 'dev', - '-p', - '3001', - '--root-dir', - '/path/to/root', - ]); + await program.parseAsync(['node', 'catalyst', 'dev', '-p', '3001']); expect(execa).toHaveBeenCalledWith( - '/path/to/root/node_modules/.bin/next', + 'node_modules/.bin/next', ['dev', '-p', '3001'], expect.objectContaining({ stdio: 'inherit', - cwd: '/path/to/root', + cwd: process.cwd(), }), ); }); diff --git a/packages/cli/tests/commands/start.spec.ts b/packages/cli/tests/commands/start.spec.ts index 38f43b5fd3..b03a23e799 100644 --- a/packages/cli/tests/commands/start.spec.ts +++ b/packages/cli/tests/commands/start.spec.ts @@ -5,6 +5,10 @@ import { expect, test, vi } from 'vitest'; import { start } from '../../src/commands/start'; import { program } from '../../src/program'; +vi.mock('node:fs', () => ({ + existsSync: vi.fn(() => true), +})); + vi.mock('execa', () => ({ execa: vi.fn(() => Promise.resolve({})), __esModule: true, @@ -14,31 +18,17 @@ test('properly configured Command instance', () => { expect(start).toBeInstanceOf(Command); expect(start.name()).toBe('start'); expect(start.description()).toBe('Start your Catalyst storefront in optimized production mode.'); - expect(start.options).toEqual( - expect.arrayContaining([ - expect.objectContaining({ flags: '-p, --port ', defaultValue: '3000' }), - expect.objectContaining({ flags: '--root-dir ', defaultValue: process.cwd() }), - ]), - ); }); test('calls execa with Next.js production optimized server', async () => { - await program.parseAsync([ - 'node', - 'catalyst', - 'start', - '-p', - '3001', - '--root-dir', - '/path/to/root', - ]); + await program.parseAsync(['node', 'catalyst', 'start', '-p', '3001']); expect(execa).toHaveBeenCalledWith( - '/path/to/root/node_modules/.bin/next', + 'node_modules/.bin/next', ['start', '-p', '3001'], expect.objectContaining({ stdio: 'inherit', - cwd: '/path/to/root', + cwd: process.cwd(), }), ); }); From 699e1612f40d301451a24fa3079e5fb651dd0e55 Mon Sep 17 00:00:00 2001 From: Matthew Volk Date: Mon, 18 Aug 2025 12:21:21 -0500 Subject: [PATCH 014/245] refactor: default framework to nextjs on conf init (#2524) --- packages/cli/src/lib/project-config.ts | 2 +- packages/cli/tests/lib/project-config.spec.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/cli/src/lib/project-config.ts b/packages/cli/src/lib/project-config.ts index 6691e50288..20cd65f98d 100644 --- a/packages/cli/src/lib/project-config.ts +++ b/packages/cli/src/lib/project-config.ts @@ -20,7 +20,7 @@ export function getProjectConfig(rootDir = process.cwd()) { framework: { type: 'string', enum: ['catalyst', 'nextjs'], - default: 'catalyst', + default: 'nextjs', }, telemetry: { type: 'object', diff --git a/packages/cli/tests/lib/project-config.spec.ts b/packages/cli/tests/lib/project-config.spec.ts index b5c92fb0bb..8f841e53f9 100644 --- a/packages/cli/tests/lib/project-config.spec.ts +++ b/packages/cli/tests/lib/project-config.spec.ts @@ -46,11 +46,11 @@ test('writes and reads field from .bigcommerce/project.json', async () => { expect(modifiedProjectUuid).toBe(projectUuid); }); -test('sets default framework to catalyst', async () => { +test('sets default framework to nextjs', async () => { const projectJsonPath = join(tmpDir, '.bigcommerce/project.json'); await mkdir(dirname(projectJsonPath), { recursive: true }); await writeFile(projectJsonPath, JSON.stringify({})); - expect(config.get('framework')).toBe('catalyst'); + expect(config.get('framework')).toBe('nextjs'); }); From 2089a58f6bdaeab68a014ad66422932f392e6c46 Mon Sep 17 00:00:00 2001 From: Chancellor Clark Date: Mon, 18 Aug 2025 16:23:01 -0600 Subject: [PATCH 015/245] fix(core): set secure value whenever we prefix cookie (#2526) --- .changeset/afraid-parts-prove.md | 5 +++++ core/auth/anonymous-session.ts | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 .changeset/afraid-parts-prove.md diff --git a/.changeset/afraid-parts-prove.md b/.changeset/afraid-parts-prove.md new file mode 100644 index 0000000000..30a9ee8d5e --- /dev/null +++ b/.changeset/afraid-parts-prove.md @@ -0,0 +1,5 @@ +--- +"@bigcommerce/catalyst-core": patch +--- + +The anonymous session cookie had `secure` always set to true regardless if we were prefixing it or not. This change updates the cookie to set `secure` to the same "value" if we prefix the cookie with `__Secure-`. diff --git a/core/auth/anonymous-session.ts b/core/auth/anonymous-session.ts index 3c28688688..4fc549114c 100644 --- a/core/auth/anonymous-session.ts +++ b/core/auth/anonymous-session.ts @@ -29,7 +29,7 @@ export const anonymousSignIn = async (user: Partial = { cartId: n }); cookieJar.set(`${cookiePrefix}${anonymousCookieName}`, jwt, { - secure: true, + secure: useSecureCookies, sameSite: 'lax', // We set the maxAge to 7 days as a good default for anonymous sessions. // This can be adjusted based on your application's needs. @@ -70,7 +70,7 @@ export const clearAnonymousSession = async () => { cookieJar.delete({ name: `${cookiePrefix}${anonymousCookieName}`, - secure: true, + secure: useSecureCookies, sameSite: 'lax', httpOnly: true, }); From 48ced7279d59f7c02094d2928e065824774dab8d Mon Sep 17 00:00:00 2001 From: Matthew Volk Date: Tue, 19 Aug 2025 14:14:50 -0500 Subject: [PATCH 016/245] refactor: add command name to bin field (#2529) --- packages/cli/package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index 48e15749f7..d9a966c9ce 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -2,7 +2,9 @@ "name": "@bigcommerce/catalyst", "version": "0.1.0", "type": "module", - "bin": "dist/index.js", + "bin": { + "catalyst": "dist/index.js" + }, "files": [ "dist", "templates" From b1b3dea567510494453df649f6e9ff9236772a50 Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Tue, 19 Aug 2025 14:20:11 -0500 Subject: [PATCH 017/245] feat(cli): update route to /v3/infrastructure/ (#2519) --- packages/cli/src/commands/deploy.ts | 31 ++++++++++++---------- packages/cli/src/commands/link.ts | 15 ++++++----- packages/cli/tests/commands/deploy.spec.ts | 4 +-- packages/cli/tests/commands/link.spec.ts | 4 +-- packages/cli/tests/mocks/handlers.ts | 8 +++--- 5 files changed, 34 insertions(+), 28 deletions(-) diff --git a/packages/cli/src/commands/deploy.ts b/packages/cli/src/commands/deploy.ts index fefb51e6f1..a16629a53f 100644 --- a/packages/cli/src/commands/deploy.ts +++ b/packages/cli/src/commands/deploy.ts @@ -98,7 +98,7 @@ export const generateUploadSignature = async ( consola.info('Generating upload signature...'); const response = await fetch( - `https://${apiHost}/stores/${storeHash}/v3/headless/deployments/uploads`, + `https://${apiHost}/stores/${storeHash}/v3/infrastructure/deployments/uploads`, { method: 'POST', headers: { @@ -156,18 +156,21 @@ export const createDeployment = async ( ) => { consola.info('Creating deployment...'); - const response = await fetch(`https://${apiHost}/stores/${storeHash}/v3/headless/deployments`, { - method: 'POST', - headers: { - 'X-Auth-Token': accessToken, - 'Content-Type': 'application/json', - Accept: 'application/json', + const response = await fetch( + `https://${apiHost}/stores/${storeHash}/v3/infrastructure/deployments`, + { + method: 'POST', + headers: { + 'X-Auth-Token': accessToken, + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + body: JSON.stringify({ + project_uuid: projectUuid, + upload_uuid: uploadUuid, + }), }, - body: JSON.stringify({ - project_uuid: projectUuid, - upload_uuid: uploadUuid, - }), - }); + ); if (!response.ok) { throw new Error(`Failed to create deployment: ${response.status} ${response.statusText}`); @@ -192,7 +195,7 @@ export const getDeploymentStatus = async ( const spinner = yoctoSpinner().start('Fetching...'); const response = await fetch( - `https://${apiHost}/stores/${storeHash}/v3/headless/deployments/${deploymentUuid}/events`, + `https://${apiHost}/stores/${storeHash}/v3/infrastructure/deployments/${deploymentUuid}/events`, { method: 'GET', headers: { @@ -281,7 +284,7 @@ export const deploy = new Command('deploy') .addOption( new Option( '--project-uuid ', - 'BigCommerce headless project UUID. Can be found via the BigCommerce API (GET /v3/headless/projects).', + 'BigCommerce headless project UUID. Can be found via the BigCommerce API (GET /v3/infrastructure/projects).', ).env('BIGCOMMERCE_PROJECT_UUID'), ) .option( diff --git a/packages/cli/src/commands/link.ts b/packages/cli/src/commands/link.ts index f3bd6fa523..5706c01820 100644 --- a/packages/cli/src/commands/link.ts +++ b/packages/cli/src/commands/link.ts @@ -17,12 +17,15 @@ const fetchProjectsSchema = z.object({ }); async function fetchProjects(storeHash: string, accessToken: string, apiHost: string) { - const response = await fetch(`https://${apiHost}/stores/${storeHash}/v3/headless/projects`, { - method: 'GET', - headers: { - 'X-Auth-Token': accessToken, + const response = await fetch( + `https://${apiHost}/stores/${storeHash}/v3/infrastructure/projects`, + { + method: 'GET', + headers: { + 'X-Auth-Token': accessToken, + }, }, - }); + ); if (response.status === 404) { throw new Error( @@ -64,7 +67,7 @@ export const link = new Command('link') ) .option( '--project-uuid ', - 'BigCommerce headless project UUID. Can be found via the BigCommerce API (GET /v3/headless/projects). Use this to link directly without fetching projects.', + 'BigCommerce headless project UUID. Can be found via the BigCommerce API (GET /v3/infrastructure/projects). Use this to link directly without fetching projects.', ) .option( '--root-dir ', diff --git a/packages/cli/tests/commands/deploy.spec.ts b/packages/cli/tests/commands/deploy.spec.ts index ee1b02012b..fea0a708f4 100644 --- a/packages/cli/tests/commands/deploy.spec.ts +++ b/packages/cli/tests/commands/deploy.spec.ts @@ -160,7 +160,7 @@ describe('deployment and event streaming', () => { server.use( http.get( - 'https://:apiHost/stores/:storeHash/v3/headless/deployments/:deploymentUuid/events', + 'https://:apiHost/stores/:storeHash/v3/infrastructure/deployments/:deploymentUuid/events', () => { const stream = new ReadableStream({ start(controller) { @@ -214,7 +214,7 @@ describe('deployment and event streaming', () => { server.use( http.get( - 'https://:apiHost/stores/:storeHash/v3/headless/deployments/:deploymentUuid/events', + 'https://:apiHost/stores/:storeHash/v3/infrastructure/deployments/:deploymentUuid/events', () => { const stream = new ReadableStream({ start(controller) { diff --git a/packages/cli/tests/commands/link.spec.ts b/packages/cli/tests/commands/link.spec.ts index 2ab769bf41..fec49e6c48 100644 --- a/packages/cli/tests/commands/link.spec.ts +++ b/packages/cli/tests/commands/link.spec.ts @@ -156,7 +156,7 @@ test('fetches projects and prompts user to select one', async () => { test('errors when no projects are found', async () => { server.use( - http.get('https://:apiHost/stores/:storeHash/v3/headless/projects', () => + http.get('https://:apiHost/stores/:storeHash/v3/infrastructure/projects', () => HttpResponse.json({ data: [], }), @@ -184,7 +184,7 @@ test('errors when no projects are found', async () => { test('errors when headless projects API is not found', async () => { server.use( - http.get('https://:apiHost/stores/:storeHash/v3/headless/projects', () => + http.get('https://:apiHost/stores/:storeHash/v3/infrastructure/projects', () => HttpResponse.json({}, { status: 404 }), ), ); diff --git a/packages/cli/tests/mocks/handlers.ts b/packages/cli/tests/mocks/handlers.ts index 61ad83dd29..4863fa2e7b 100644 --- a/packages/cli/tests/mocks/handlers.ts +++ b/packages/cli/tests/mocks/handlers.ts @@ -4,7 +4,7 @@ const encoder = new TextEncoder(); export const handlers = [ // Handler for generateUploadSignature - http.post('https://:apiHost/stores/:storeHash/v3/headless/deployments/uploads', () => + http.post('https://:apiHost/stores/:storeHash/v3/infrastructure/deployments/uploads', () => HttpResponse.json({ data: { upload_url: 'https://mock-upload-url.com', @@ -17,7 +17,7 @@ export const handlers = [ http.put('https://mock-upload-url.com', () => new HttpResponse(null, { status: 200 })), // Handler for createDeployment - http.post('https://:apiHost/stores/:storeHash/v3/headless/deployments', () => + http.post('https://:apiHost/stores/:storeHash/v3/infrastructure/deployments', () => HttpResponse.json({ data: { deployment_uuid: '5b29c3c0-5f68-44fe-99e5-06492babf7be', @@ -26,7 +26,7 @@ export const handlers = [ ), // Handler for fetchProjects - http.get('https://:apiHost/stores/:storeHash/v3/headless/projects', () => + http.get('https://:apiHost/stores/:storeHash/v3/infrastructure/projects', () => HttpResponse.json({ data: [ { uuid: 'a23f5785-fd99-4a94-9fb3-945551623923', name: 'Project One' }, @@ -37,7 +37,7 @@ export const handlers = [ // Handler for getDeploymentStatus http.get( - 'https://:apiHost/stores/:storeHash/v3/headless/deployments/:deploymentUuid/events', + 'https://:apiHost/stores/:storeHash/v3/infrastructure/deployments/:deploymentUuid/events', ({ params }) => { const stream = new ReadableStream({ start(controller) { From 3268c45a96e4f6237d2393f18204a15dc305327c Mon Sep 17 00:00:00 2001 From: Matthew Volk Date: Tue, 19 Aug 2025 14:32:26 -0500 Subject: [PATCH 018/245] refactor: add options for framework and project uuid to build command (#2530) --- packages/cli/src/commands/build.ts | 9 ++++++++- packages/cli/tests/commands/build.spec.ts | 6 +++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/commands/build.ts b/packages/cli/src/commands/build.ts index b093312c84..aa4ea29962 100644 --- a/packages/cli/src/commands/build.ts +++ b/packages/cli/src/commands/build.ts @@ -1,4 +1,4 @@ -import { Command } from 'commander'; +import { Command, Option } from 'commander'; import consola from 'consola'; import { execa } from 'execa'; import { cp } from 'node:fs/promises'; @@ -34,6 +34,13 @@ export function createFilter(root: string, skipDirs: Set) { export const build = new Command('build') .option('--keep-temp-dir', 'Keep the temporary directory after the build') + .option('--project-uuid ', 'Project UUID to be included in the deployment configuration.') + .addOption( + new Option('--framework ', 'The framework to use for the build.').choices([ + 'nextjs', + 'catalyst', + ]), + ) .action(async (options) => { const [tmpDir, rmTempDir] = await mkTempDir('catalyst-build-'); diff --git a/packages/cli/tests/commands/build.spec.ts b/packages/cli/tests/commands/build.spec.ts index 7b624ac58a..fc9981ab1d 100644 --- a/packages/cli/tests/commands/build.spec.ts +++ b/packages/cli/tests/commands/build.spec.ts @@ -48,7 +48,11 @@ test('properly configured Command instance', () => { expect(build).toBeInstanceOf(Command); expect(build.name()).toBe('build'); expect(build.options).toEqual( - expect.arrayContaining([expect.objectContaining({ flags: '--keep-temp-dir' })]), + expect.arrayContaining([ + expect.objectContaining({ long: '--keep-temp-dir' }), + expect.objectContaining({ long: '--framework' }), + expect.objectContaining({ long: '--project-uuid' }), + ]), ); }); From 18e8e09e27ff6da9972250928763e0879ab1ba6a Mon Sep 17 00:00:00 2001 From: Matthew Volk Date: Tue, 19 Aug 2025 15:25:35 -0500 Subject: [PATCH 019/245] refactor: remove nypm since dependencies should already be installed (#2531) --- packages/cli/package.json | 1 - packages/cli/src/commands/build.ts | 27 ----------------------- packages/cli/tests/commands/build.spec.ts | 6 ----- pnpm-lock.yaml | 7 ++---- 4 files changed, 2 insertions(+), 39 deletions(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index d9a966c9ce..aca08bd5e2 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -30,7 +30,6 @@ "conf": "^13.1.0", "consola": "^3.4.2", "execa": "^9.6.0", - "nypm": "^0.6.0", "yocto-spinner": "^1.0.0", "zod": "^4.0.5" }, diff --git a/packages/cli/src/commands/build.ts b/packages/cli/src/commands/build.ts index aa4ea29962..4b8347696a 100644 --- a/packages/cli/src/commands/build.ts +++ b/packages/cli/src/commands/build.ts @@ -3,12 +3,10 @@ import consola from 'consola'; import { execa } from 'execa'; import { cp } from 'node:fs/promises'; import { join, relative, sep } from 'node:path'; -import { addDevDependency, installDependencies, runScript } from 'nypm'; import { getModuleCliPath } from '../lib/get-module-cli-path'; import { mkTempDir } from '../lib/mk-temp-dir'; -const OPENNEXTJS_CLOUDFLARE_VERSION = '1.5.2'; const WRANGLER_VERSION = '4.24.3'; const SKIP_DIRS = new Set([ @@ -47,8 +45,6 @@ export const build = new Command('build') try { consola.start('Copying project to temp directory...'); - const packageManager = 'pnpm'; - const cwd = process.cwd(); const tmpCoreDir = join(tmpDir, 'core'); const wranglerOutDir = join(tmpCoreDir, '.dist'); @@ -64,29 +60,6 @@ export const build = new Command('build') consola.success(`Project copied to temp directory: ${tmpDir}`); - consola.start('Installing dependencies...'); - - await installDependencies({ - cwd: tmpDir, - packageManager, - }); - - await addDevDependency(`@opennextjs/cloudflare@${OPENNEXTJS_CLOUDFLARE_VERSION}`, { - cwd: tmpCoreDir, - packageManager, - }); - - consola.success('Dependencies installed'); - - consola.start('Building dependencies...'); - - await runScript('build', { - cwd: join(tmpDir, 'packages', 'client'), - packageManager, - }); - - consola.success('Dependencies built'); - consola.start('Copying templates...'); await cp(join(getModuleCliPath(), 'templates'), tmpCoreDir, { diff --git a/packages/cli/tests/commands/build.spec.ts b/packages/cli/tests/commands/build.spec.ts index fc9981ab1d..973139ede2 100644 --- a/packages/cli/tests/commands/build.spec.ts +++ b/packages/cli/tests/commands/build.spec.ts @@ -21,12 +21,6 @@ beforeAll(() => { cp: vi.fn(), })); - vi.mock('nypm', () => ({ - installDependencies: vi.fn(), - addDevDependency: vi.fn(), - runScript: vi.fn(), - })); - vi.mock('execa', () => ({ execa: vi.fn(), })); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2759526945..af2a58067f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -306,9 +306,6 @@ importers: execa: specifier: ^9.6.0 version: 9.6.0 - nypm: - specifier: ^0.6.0 - version: 0.6.0 yocto-spinner: specifier: ^1.0.0 version: 1.0.0 @@ -12086,7 +12083,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.9.1)(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: @@ -12118,7 +12115,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.9.1)(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 From 16a1197a459845f20b538ea0972466060c10b1aa Mon Sep 17 00:00:00 2001 From: Matthew Volk Date: Tue, 19 Aug 2025 15:36:14 -0500 Subject: [PATCH 020/245] refactor: run build directly on core (#2527) --- packages/cli/package.json | 3 + packages/cli/src/commands/build.ts | 73 +- packages/cli/tests/commands/build.spec.ts | 96 +- pnpm-lock.yaml | 3822 ++++++++++++++++++++- 4 files changed, 3744 insertions(+), 250 deletions(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index aca08bd5e2..aa63b32055 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -47,5 +47,8 @@ "tsup": "^8.5.0", "typescript": "^5.8.3", "vitest": "^3.2.4" + }, + "peerDependencies": { + "@opennextjs/cloudflare": "^1.6.5" } } diff --git a/packages/cli/src/commands/build.ts b/packages/cli/src/commands/build.ts index 4b8347696a..958e93b71a 100644 --- a/packages/cli/src/commands/build.ts +++ b/packages/cli/src/commands/build.ts @@ -2,36 +2,13 @@ import { Command, Option } from 'commander'; import consola from 'consola'; import { execa } from 'execa'; import { cp } from 'node:fs/promises'; -import { join, relative, sep } from 'node:path'; +import { join } from 'node:path'; import { getModuleCliPath } from '../lib/get-module-cli-path'; -import { mkTempDir } from '../lib/mk-temp-dir'; const WRANGLER_VERSION = '4.24.3'; -const SKIP_DIRS = new Set([ - 'node_modules', - '.bigcommerce', - '.git', - '.turbo', - '.next', - '.vscode', - '.github', - '.changeset', - 'dist', -]); - -export function createFilter(root: string, skipDirs: Set) { - return (src: string) => { - const rel = relative(root, src); - const parts = rel.split(sep); - - return !parts.some((part) => skipDirs.has(part)); - }; -} - export const build = new Command('build') - .option('--keep-temp-dir', 'Keep the temporary directory after the build') .option('--project-uuid ', 'Project UUID to be included in the deployment configuration.') .addOption( new Option('--framework ', 'The framework to use for the build.').choices([ @@ -39,30 +16,15 @@ export const build = new Command('build') 'catalyst', ]), ) - .action(async (options) => { - const [tmpDir, rmTempDir] = await mkTempDir('catalyst-build-'); - + .action(async () => { try { - consola.start('Copying project to temp directory...'); - - const cwd = process.cwd(); - const tmpCoreDir = join(tmpDir, 'core'); - const wranglerOutDir = join(tmpCoreDir, '.dist'); - const openNextOutDir = join(tmpCoreDir, '.open-next'); - const bigcommerceDistDir = join(cwd, '.bigcommerce', 'dist'); - - await cp(cwd, tmpDir, { - recursive: true, - force: true, - preserveTimestamps: true, - filter: createFilter(cwd, SKIP_DIRS), - }); - - consola.success(`Project copied to temp directory: ${tmpDir}`); + const coreDir = process.cwd(); + const openNextOutDir = join(coreDir, '.open-next'); + const bigcommerceDistDir = join(coreDir, '.bigcommerce', 'dist'); consola.start('Copying templates...'); - await cp(join(getModuleCliPath(), 'templates'), tmpCoreDir, { + await cp(join(getModuleCliPath(), 'templates'), coreDir, { recursive: true, force: true, }); @@ -73,7 +35,7 @@ export const build = new Command('build') await execa('pnpm', ['exec', 'opennextjs-cloudflare', 'build'], { stdout: ['pipe', 'inherit'], - cwd: tmpCoreDir, + cwd: coreDir, }); await execa( @@ -84,38 +46,23 @@ export const build = new Command('build') 'deploy', '--keep-vars', '--outdir', - wranglerOutDir, + bigcommerceDistDir, '--dry-run', ], { stdout: ['pipe', 'inherit'], - cwd: tmpCoreDir, + cwd: coreDir, }, ); consola.success('Project built'); - consola.start('Copying build to project...'); - - await cp(wranglerOutDir, bigcommerceDistDir, { - recursive: true, - force: true, - }); - await cp(join(openNextOutDir, 'assets'), join(bigcommerceDistDir, 'assets'), { recursive: true, force: true, }); - - consola.success('Build copied to project'); } catch (error) { consola.error(error); - process.exitCode = 1; - } finally { - if (!options.keepTempDir) { - await rmTempDir(); - } - - process.exit(); + process.exit(1); } }); diff --git a/packages/cli/tests/commands/build.spec.ts b/packages/cli/tests/commands/build.spec.ts index 973139ede2..769d664bec 100644 --- a/packages/cli/tests/commands/build.spec.ts +++ b/packages/cli/tests/commands/build.spec.ts @@ -1,107 +1,15 @@ import { Command } from 'commander'; -import consola from 'consola'; -import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest'; +import { expect, test } from 'vitest'; -import { build, createFilter } from '../../src/commands/build'; -import { program } from '../../src/program'; - -const cleanup = vi.fn(); - -beforeAll(() => { - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - vi.spyOn(process, 'exit').mockImplementation(() => null as never); - - consola.wrapAll(); - - vi.mock('../../src/lib/mk-temp-dir', () => ({ - mkTempDir: vi.fn(() => ['/tmp/test', cleanup]), - })); - - vi.mock('node:fs/promises', () => ({ - cp: vi.fn(), - })); - - vi.mock('execa', () => ({ - execa: vi.fn(), - })); -}); - -beforeEach(() => { - consola.mockTypes(() => vi.fn()); -}); - -afterEach(() => { - vi.clearAllMocks(); -}); - -afterAll(() => { - vi.restoreAllMocks(); -}); +import { build } from '../../src/commands/build'; test('properly configured Command instance', () => { expect(build).toBeInstanceOf(Command); expect(build.name()).toBe('build'); expect(build.options).toEqual( expect.arrayContaining([ - expect.objectContaining({ long: '--keep-temp-dir' }), expect.objectContaining({ long: '--framework' }), expect.objectContaining({ long: '--project-uuid' }), ]), ); }); - -test('does not remove temp dir if --keep-temp-dir is passed', async () => { - await program.parseAsync(['node', 'catalyst', 'build', '--keep-temp-dir']); - expect(cleanup).not.toHaveBeenCalled(); -}); - -test('removes temp dir if --keep-temp-dir is not passed', async () => { - await program.parseAsync(['node', 'catalyst', 'build']); - expect(cleanup).toHaveBeenCalled(); -}); - -test('successfully builds project', async () => { - await program.parseAsync(['node', 'catalyst', 'build']); - - expect(consola.success).toHaveBeenCalledWith('Project built'); - expect(consola.success).toHaveBeenCalledWith('Build copied to project'); -}); - -test('handles error if cp throws during build', async () => { - // Dynamically mock cp for this test only - // eslint-disable-next-line import/dynamic-import-chunkname - const cpModule = await import('node:fs/promises'); - const originalCp = cpModule.cp; - const cpMock = vi.fn(() => { - throw new Error('cp failed'); - }); - - cpModule.cp = cpMock; - - await program.parseAsync(['node', 'catalyst', 'build']); - - expect(consola.error).toHaveBeenCalledWith(expect.any(Error)); - - cpModule.cp = originalCp; -}); - -describe('createFilter', () => { - const ROOT = '/my/project'; - const SKIP_DIRS = new Set(['node_modules', '.git', 'dist']); - - const filter = createFilter(ROOT, SKIP_DIRS); - - test('allows files not in skip list', () => { - expect(filter('/my/project/src/index.ts')).toBe(true); - }); - - test('skips files inside a skipped directory', () => { - expect(filter('/my/project/node_modules/lodash/index.js')).toBe(false); - expect(filter('/my/project/.git/config')).toBe(false); - expect(filter('/my/project/dist/main.js')).toBe(false); - }); - - test('handles nested skipped folders', () => { - expect(filter('/my/project/src/node_modules/whatever.js')).toBe(false); - }); -}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index af2a58067f..6d23bb5682 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -288,6 +288,9 @@ importers: packages/cli: dependencies: + '@opennextjs/cloudflare': + specifier: ^1.6.5 + version: 1.6.5(encoding@0.1.13)(wrangler@4.31.0) '@segment/analytics-node': specifier: ^2.2.1 version: 2.2.1(encoding@0.1.13) @@ -345,13 +348,13 @@ importers: version: 3.6.2 tsup: specifier: ^8.5.0 - version: 8.5.0(@swc/core@1.11.31)(jiti@2.4.2)(postcss@8.5.6)(typescript@5.8.3)(yaml@2.6.0) + version: 8.5.0(@swc/core@1.11.31)(jiti@2.4.2)(postcss@8.5.6)(typescript@5.8.3)(yaml@2.8.1) typescript: specifier: ^5.8.3 version: 5.8.3 vitest: specifier: ^3.2.4 - version: 3.2.4(@types/node@22.15.30)(@vitest/ui@3.2.4)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.29.2)(msw@2.9.0(@types/node@22.15.30)(typescript@5.8.3))(yaml@2.6.0) + version: 3.2.4(@types/node@22.15.30)(@vitest/ui@3.2.4)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.29.2)(msw@2.9.0(@types/node@22.15.30)(typescript@5.8.3))(terser@5.16.9)(yaml@2.8.1) packages/client: dependencies: @@ -382,7 +385,7 @@ importers: version: 3.6.2 tsup: specifier: ^8.5.0 - version: 8.5.0(@swc/core@1.11.31)(jiti@2.4.2)(postcss@8.5.6)(typescript@5.8.3)(yaml@2.6.0) + version: 8.5.0(@swc/core@1.11.31)(jiti@2.4.2)(postcss@8.5.6)(typescript@5.8.3)(yaml@2.8.1) typescript: specifier: ^5.8.3 version: 5.8.3 @@ -506,7 +509,7 @@ importers: version: 3.6.2 tsup: specifier: ^8.5.0 - version: 8.5.0(@swc/core@1.11.31)(jiti@2.4.2)(postcss@8.5.6)(typescript@5.8.3)(yaml@2.6.0) + version: 8.5.0(@swc/core@1.11.31)(jiti@2.4.2)(postcss@8.5.6)(typescript@5.8.3)(yaml@2.8.1) typescript: specifier: ^5.8.3 version: 5.8.3 @@ -563,6 +566,64 @@ packages: '@asamuzakjp/css-color@3.2.0': resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==} + '@ast-grep/napi-darwin-arm64@0.35.0': + resolution: {integrity: sha512-T+MN4Oinc+sXjXCIHzfxDDWY7r2pKgPxM6zVeVlkMTrJV2mJtyKYBIS+CABhRM6kflps2T2I6l4DGaKV/8Ym9w==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@ast-grep/napi-darwin-x64@0.35.0': + resolution: {integrity: sha512-pEYiN6JI1HY2uWhMYJ9+3yIMyVYKuYdFzeD+dL7odA3qzK0o9N9AM3/NOt4ynU2EhufaWCJr0P5NoQ636qN6MQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@ast-grep/napi-linux-arm64-gnu@0.35.0': + resolution: {integrity: sha512-NBuzQngABGKz7lhG08IQb+7nPqUx81Ol37xmS3ZhVSdSgM0mtp93rCbgFTkJcAFE8IMfCHQSg7G4g0Iotz4ABQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@ast-grep/napi-linux-arm64-musl@0.35.0': + resolution: {integrity: sha512-1EcvHPwyWpCL/96LuItBYGfeI5FaMTRvL+dHbO/hL5q1npqbb5qn+ppJwtNOjTPz8tayvgggxVk9T4C2O7taYA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@ast-grep/napi-linux-x64-gnu@0.35.0': + resolution: {integrity: sha512-FDzNdlqmQnsiWXhnLxusw5AOfEcEM+5xtmrnAf3SBRFr86JyWD9qsynnFYC2pnP9hlMfifNH2TTmMpyGJW49Xw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@ast-grep/napi-linux-x64-musl@0.35.0': + resolution: {integrity: sha512-wlmndjfBafT8u5p4DBnoRQyoCSGNuVSz7rT3TqhvlHcPzUouRWMn95epU9B1LNLyjXvr9xHeRjSktyCN28w57Q==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@ast-grep/napi-win32-arm64-msvc@0.35.0': + resolution: {integrity: sha512-gkhJeYc4rrZLX2icLxalPikTLMR57DuIYLwLr9g+StHYXIsGHrbfrE6Nnbdd8Izfs34ArFCrcwdaMrGlvOPSeg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@ast-grep/napi-win32-ia32-msvc@0.35.0': + resolution: {integrity: sha512-OdUuRa3chHCZ65y+qALfkUjz0W0Eg21YZ9TyPquV5why07M6HAK38mmYGzLxFH6294SvRQhs+FA/rAfbKeH0jA==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + + '@ast-grep/napi-win32-x64-msvc@0.35.0': + resolution: {integrity: sha512-pcQRUHqbroTN1oQ56V982a7IZTUUySQYWa2KEyksiifHGuBuitlzcyzFGjT96ThcqD9XW0UVJMvpoF2Qjh006Q==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@ast-grep/napi@0.35.0': + resolution: {integrity: sha512-3ucaaSxV6fxXoqHrE/rxAvP1THnDdY5jNzGlnvx+JvnY9C/dSRKc0jlRMRz59N3El572+/yNRUUpAV1T9aBJug==} + engines: {node: '>= 10'} + '@auth/core@0.37.2': resolution: {integrity: sha512-kUvzyvkcd6h1vpeMAojK2y7+PAV5H+0Cc9+ZlKYDFhDY31AlvsB+GW5vNO4qE3Y07KeQgvNO9U0QUx/fN62kBw==} peerDependencies: @@ -577,6 +638,287 @@ packages: nodemailer: optional: true + '@aws-crypto/crc32@5.2.0': + resolution: {integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==} + engines: {node: '>=16.0.0'} + + '@aws-crypto/crc32c@5.2.0': + resolution: {integrity: sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag==} + + '@aws-crypto/ie11-detection@3.0.0': + resolution: {integrity: sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==} + + '@aws-crypto/sha1-browser@5.2.0': + resolution: {integrity: sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg==} + + '@aws-crypto/sha256-browser@3.0.0': + resolution: {integrity: sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==} + + '@aws-crypto/sha256-browser@5.2.0': + resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==} + + '@aws-crypto/sha256-js@3.0.0': + resolution: {integrity: sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==} + + '@aws-crypto/sha256-js@5.2.0': + resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==} + engines: {node: '>=16.0.0'} + + '@aws-crypto/supports-web-crypto@3.0.0': + resolution: {integrity: sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==} + + '@aws-crypto/supports-web-crypto@5.2.0': + resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==} + + '@aws-crypto/util@3.0.0': + resolution: {integrity: sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==} + + '@aws-crypto/util@5.2.0': + resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} + + '@aws-sdk/client-cloudfront@3.398.0': + resolution: {integrity: sha512-kISKhqN1k48TaMPbLgq9jj7mO2jvbJdhirvfu4JW3jhFhENnkY0oCwTPvR4Q6Ne2as6GFAMo2XZDZq4rxC7YDw==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/client-dynamodb@3.868.0': + resolution: {integrity: sha512-a2uKLRplH3vTHgTHr+MaZ1YH0Sy0yVHK9rhM/drktxgXehMf4p7dZtt783c9SEupZvo46LxXryvwifoUdL4nRg==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/client-lambda@3.865.0': + resolution: {integrity: sha512-ncCEW/kNRV8yJA/45z5HO6WEeihADzFY7RISfezDbvP3/X4dZb2gycRVPmJIE6CBqf01jwTkbG36qO+/iHIELg==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/client-s3@3.864.0': + resolution: {integrity: sha512-QGYi9bWliewxumsvbJLLyx9WC0a4DP4F+utygBcq0zwPxaM0xDfBspQvP1dsepi7mW5aAjZmJ2+Xb7X0EhzJ/g==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/client-sqs@3.864.0': + resolution: {integrity: sha512-SxEdQW/g2hb7/O4juAQL0kOD86/QBUSNkdJ5rN3Nd04rJmYTCxe38iCJBT637n+hiedxThLuj8H9ZmY1/OSg7Q==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/client-sso@3.398.0': + resolution: {integrity: sha512-CygL0jhfibw4kmWXG/3sfZMFNjcXo66XUuPC4BqZBk8Rj5vFoxp1vZeMkDLzTIk97Nvo5J5Bh+QnXKhub6AckQ==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/client-sso@3.864.0': + resolution: {integrity: sha512-THiOp0OpQROEKZ6IdDCDNNh3qnNn/kFFaTSOiugDpgcE5QdsOxh1/RXq7LmHpTJum3cmnFf8jG59PHcz9Tjnlw==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/client-sts@3.398.0': + resolution: {integrity: sha512-/3Pa9wLMvBZipKraq3AtbmTfXW6q9kyvhwOno64f1Fz7kFb8ijQFMGoATS70B2pGEZTlxkUqJFWDiisT6Q6dFg==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/core@3.864.0': + resolution: {integrity: sha512-LFUREbobleHEln+Zf7IG83lAZwvHZG0stI7UU0CtwyuhQy5Yx0rKksHNOCmlM7MpTEbSCfntEhYi3jUaY5e5lg==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/credential-provider-env@3.398.0': + resolution: {integrity: sha512-Z8Yj5z7FroAsR6UVML+XUdlpoqEe9Dnle8c2h8/xWwIC2feTfIBhjLhRVxfbpbM1pLgBSNEcZ7U8fwq5l7ESVQ==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/credential-provider-env@3.864.0': + resolution: {integrity: sha512-StJPOI2Rt8UE6lYjXUpg6tqSZaM72xg46ljPg8kIevtBAAfdtq9K20qT/kSliWGIBocMFAv0g2mC0hAa+ECyvg==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/credential-provider-http@3.864.0': + resolution: {integrity: sha512-E/RFVxGTuGnuD+9pFPH2j4l6HvrXzPhmpL8H8nOoJUosjx7d4v93GJMbbl1v/fkDLqW9qN4Jx2cI6PAjohA6OA==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/credential-provider-ini@3.398.0': + resolution: {integrity: sha512-AsK1lStK3nB9Cn6S6ODb1ktGh7SRejsNVQVKX3t5d3tgOaX+aX1Iwy8FzM/ZEN8uCloeRifUGIY9uQFygg5mSw==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/credential-provider-ini@3.864.0': + resolution: {integrity: sha512-PlxrijguR1gxyPd5EYam6OfWLarj2MJGf07DvCx9MAuQkw77HBnsu6+XbV8fQriFuoJVTBLn9ROhMr/ROAYfUg==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/credential-provider-node@3.398.0': + resolution: {integrity: sha512-odmI/DSKfuWUYeDnGTCEHBbC8/MwnF6yEq874zl6+owoVv0ZsYP8qBHfiJkYqrwg7wQ7Pi40sSAPC1rhesGwzg==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/credential-provider-node@3.864.0': + resolution: {integrity: sha512-2BEymFeXURS+4jE9tP3vahPwbYRl0/1MVaFZcijj6pq+nf5EPGvkFillbdBRdc98ZI2NedZgSKu3gfZXgYdUhQ==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/credential-provider-process@3.398.0': + resolution: {integrity: sha512-WrkBL1W7TXN508PA9wRXPFtzmGpVSW98gDaHEaa8GolAPHMPa5t2QcC/z/cFpglzrcVv8SA277zu9Z8tELdZhg==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/credential-provider-process@3.864.0': + resolution: {integrity: sha512-Zxnn1hxhq7EOqXhVYgkF4rI9MnaO3+6bSg/tErnBQ3F8kDpA7CFU24G1YxwaJXp2X4aX3LwthefmSJHwcVP/2g==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/credential-provider-sso@3.398.0': + resolution: {integrity: sha512-2Dl35587xbnzR/GGZqA2MnFs8+kS4wbHQO9BioU0okA+8NRueohNMdrdQmQDdSNK4BfIpFspiZmFkXFNyEAfgw==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/credential-provider-sso@3.864.0': + resolution: {integrity: sha512-UPyPNQbxDwHVGmgWdGg9/9yvzuedRQVF5jtMkmP565YX9pKZ8wYAcXhcYdNPWFvH0GYdB0crKOmvib+bmCuwkw==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/credential-provider-web-identity@3.398.0': + resolution: {integrity: sha512-iG3905Alv9pINbQ8/MIsshgqYMbWx+NDQWpxbIW3W0MkSH3iAqdVpSCteYidYX9G/jv2Um1nW3y360ib20bvNg==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/credential-provider-web-identity@3.864.0': + resolution: {integrity: sha512-nNcjPN4SYg8drLwqK0vgVeSvxeGQiD0FxOaT38mV2H8cu0C5NzpvA+14Xy+W6vT84dxgmJYKk71Cr5QL2Oz+rA==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/endpoint-cache@3.804.0': + resolution: {integrity: sha512-TQVDkA/lV6ua75ELZaichMzlp6x7tDa1bqdy/+0ZftmODPtKXuOOEcJxmdN7Ui/YRo1gkRz2D9txYy7IlNg1Og==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-bucket-endpoint@3.862.0': + resolution: {integrity: sha512-Wcsc7VPLjImQw+CP1/YkwyofMs9Ab6dVq96iS8p0zv0C6YTaMjvillkau4zFfrrrTshdzFWKptIFhKK8Zsei1g==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-endpoint-discovery@3.862.0': + resolution: {integrity: sha512-43KnrSlzsa6/locegW9SLe/kMv51PPPAslDbBuLVtLcFUNWuCE7wgKTTzMPeA+NJQHKuJTFRR2TLKPYEs+4VJA==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-expect-continue@3.862.0': + resolution: {integrity: sha512-oG3AaVUJ+26p0ESU4INFn6MmqqiBFZGrebST66Or+YBhteed2rbbFl7mCfjtPWUFgquQlvT1UP19P3LjQKeKpw==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-flexible-checksums@3.864.0': + resolution: {integrity: sha512-MvakvzPZi9uyP3YADuIqtk/FAcPFkyYFWVVMf5iFs/rCdk0CUzn02Qf4CSuyhbkS6Y0KrAsMgKR4MgklPU79Wg==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-host-header@3.398.0': + resolution: {integrity: sha512-m+5laWdBaxIZK2ko0OwcCHJZJ5V1MgEIt8QVQ3k4/kOkN9ICjevOYmba751pHoTnbOYB7zQd6D2OT3EYEEsUcA==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/middleware-host-header@3.862.0': + resolution: {integrity: sha512-jDje8dCFeFHfuCAxMDXBs8hy8q9NCTlyK4ThyyfAj3U4Pixly2mmzY2u7b7AyGhWsjJNx8uhTjlYq5zkQPQCYw==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-location-constraint@3.862.0': + resolution: {integrity: sha512-MnwLxCw7Cc9OngEH3SHFhrLlDI9WVxaBkp3oTsdY9JE7v8OE38wQ9vtjaRsynjwu0WRtrctSHbpd7h/QVvtjyA==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-logger@3.398.0': + resolution: {integrity: sha512-CiJjW+FL12elS6Pn7/UVjVK8HWHhXMfvHZvOwx/Qkpy340sIhkuzOO6fZEruECDTZhl2Wqn81XdJ1ZQ4pRKpCg==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/middleware-logger@3.862.0': + resolution: {integrity: sha512-N/bXSJznNBR/i7Ofmf9+gM6dx/SPBK09ZWLKsW5iQjqKxAKn/2DozlnE54uiEs1saHZWoNDRg69Ww4XYYSlG1Q==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-recursion-detection@3.398.0': + resolution: {integrity: sha512-7QpOqPQAZNXDXv6vsRex4R8dLniL0E/80OPK4PPFsrCh9btEyhN9Begh4i1T+5lL28hmYkztLOkTQ2N5J3hgRQ==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/middleware-recursion-detection@3.862.0': + resolution: {integrity: sha512-KVoo3IOzEkTq97YKM4uxZcYFSNnMkhW/qj22csofLegZi5fk90ztUnnaeKfaEJHfHp/tm1Y3uSoOXH45s++kKQ==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-sdk-s3@3.864.0': + resolution: {integrity: sha512-GjYPZ6Xnqo17NnC8NIQyvvdzzO7dm+Ks7gpxD/HsbXPmV2aEfuFveJXneGW9e1BheSKFff6FPDWu8Gaj2Iu1yg==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-sdk-sqs@3.862.0': + resolution: {integrity: sha512-DBX+xTAd3uhMYUFI3wIoSQYBmVFmq918Ah2t/NhTtkNmiuHAFxCy4fSzSklt9qS0i1WzccJEqOZNmqxGEFtolA==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-sdk-sts@3.398.0': + resolution: {integrity: sha512-+JH76XHEgfVihkY+GurohOQ5Z83zVN1nYcQzwCFnCDTh4dG4KwhnZKG+WPw6XJECocY0R+H0ivofeALHvVWJtQ==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/middleware-signing@3.398.0': + resolution: {integrity: sha512-O0KqXAix1TcvZBFt1qoFkHMUNJOSgjJTYS7lFTRKSwgsD27bdW2TM2r9R8DAccWFt5Amjkdt+eOwQMIXPGTm8w==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/middleware-ssec@3.862.0': + resolution: {integrity: sha512-72VtP7DZC8lYTE2L3Efx2BrD98oe9WTK8X6hmd3WTLkbIjvgWQWIdjgaFXBs8WevsXkewIctfyA3KEezvL5ggw==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-user-agent@3.398.0': + resolution: {integrity: sha512-nF1jg0L+18b5HvTcYzwyFgfZQQMELJINFqI0mi4yRKaX7T5a3aGp5RVLGGju/6tAGTuFbfBoEhkhU3kkxexPYQ==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/middleware-user-agent@3.864.0': + resolution: {integrity: sha512-wrddonw4EyLNSNBrApzEhpSrDwJiNfjxDm5E+bn8n32BbAojXASH8W8jNpxz/jMgNkkJNxCfyqybGKzBX0OhbQ==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/nested-clients@3.864.0': + resolution: {integrity: sha512-H1C+NjSmz2y8Tbgh7Yy89J20yD/hVyk15hNoZDbCYkXg0M358KS7KVIEYs8E2aPOCr1sK3HBE819D/yvdMgokA==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/region-config-resolver@3.862.0': + resolution: {integrity: sha512-VisR+/HuVFICrBPY+q9novEiE4b3mvDofWqyvmxHcWM7HumTz9ZQSuEtnlB/92GVM3KDUrR9EmBHNRrfXYZkcQ==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/signature-v4-multi-region@3.864.0': + resolution: {integrity: sha512-w2HIn/WIcUyv1bmyCpRUKHXB5KdFGzyxPkp/YK5g+/FuGdnFFYWGfcO8O+How4jwrZTarBYsAHW9ggoKvwr37w==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/token-providers@3.398.0': + resolution: {integrity: sha512-nrYgjzavGCKJL/48Vt0EL+OlIc5UZLfNGpgyUW9cv3XZwl+kXV0QB+HH0rHZZLfpbBgZ2RBIJR9uD5ieu/6hpQ==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/token-providers@3.864.0': + resolution: {integrity: sha512-gTc2QHOBo05SCwVA65dUtnJC6QERvFaPiuppGDSxoF7O5AQNK0UR/kMSenwLqN8b5E1oLYvQTv3C1idJLRX0cg==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/types@3.398.0': + resolution: {integrity: sha512-r44fkS+vsEgKCuEuTV+TIk0t0m5ZlXHNjSDYEUvzLStbbfUFiNus/YG4UCa0wOk9R7VuQI67badsvvPeVPCGDQ==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/types@3.862.0': + resolution: {integrity: sha512-Bei+RL0cDxxV+lW2UezLbCYYNeJm6Nzee0TpW0FfyTRBhH9C1XQh4+x+IClriXvgBnRquTMMYsmJfvx8iyLKrg==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/util-arn-parser@3.804.0': + resolution: {integrity: sha512-wmBJqn1DRXnZu3b4EkE6CWnoWMo1ZMvlfkqU5zPz67xx1GMaXlDCchFvKAXMjk4jn/L1O3tKnoFDNsoLV1kgNQ==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/util-endpoints@3.398.0': + resolution: {integrity: sha512-Fy0gLYAei/Rd6BrXG4baspCnWTUSd0NdokU1pZh4KlfEAEN1i8SPPgfiO5hLk7+2inqtCmqxVJlfqbMVe9k4bw==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/util-endpoints@3.862.0': + resolution: {integrity: sha512-eCZuScdE9MWWkHGM2BJxm726MCmWk/dlHjOKvkM0sN1zxBellBMw5JohNss1Z8/TUmnW2gb9XHTOiHuGjOdksA==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/util-locate-window@3.804.0': + resolution: {integrity: sha512-zVoRfpmBVPodYlnMjgVjfGoEZagyRF5IPn3Uo6ZvOZp24chnW/FRstH7ESDHDDRga4z3V+ElUQHKpFDXWyBW5A==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/util-user-agent-browser@3.398.0': + resolution: {integrity: sha512-A3Tzx1tkDHlBT+IgxmsMCHbV8LM7SwwCozq2ZjJRx0nqw3MCrrcxQFXldHeX/gdUMO+0Oocb7HGSnVODTq+0EA==} + + '@aws-sdk/util-user-agent-browser@3.862.0': + resolution: {integrity: sha512-BmPTlm0r9/10MMr5ND9E92r8KMZbq5ltYXYpVcUbAsnB1RJ8ASJuRoLne5F7mB3YMx0FJoOTuSq7LdQM3LgW3Q==} + + '@aws-sdk/util-user-agent-node@3.398.0': + resolution: {integrity: sha512-RTVQofdj961ej4//fEkppFf4KXqKGMTCqJYghx3G0C/MYXbg7MGl7LjfNGtJcboRE8pfHHQ/TUWBDA7RIAPPlQ==} + engines: {node: '>=14.0.0'} + peerDependencies: + aws-crt: '>=1.0.0' + peerDependenciesMeta: + aws-crt: + optional: true + + '@aws-sdk/util-user-agent-node@3.864.0': + resolution: {integrity: sha512-d+FjUm2eJEpP+FRpVR3z6KzMdx1qwxEYDz8jzNKwxYLBBquaBaP/wfoMtMQKAcbrR7aT9FZVZF7zDgzNxUvQlQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + aws-crt: '>=1.0.0' + peerDependenciesMeta: + aws-crt: + optional: true + + '@aws-sdk/util-utf8-browser@3.259.0': + resolution: {integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==} + + '@aws-sdk/xml-builder@3.310.0': + resolution: {integrity: sha512-TqELu4mOuSIKQCqj63fGVs86Yh+vBx5nHRpWKNUNhB2nPTpfbziTs5c1X358be3peVWA4wPxW7Nt53KIg1tnNw==} + engines: {node: '>=14.0.0'} + + '@aws-sdk/xml-builder@3.862.0': + resolution: {integrity: sha512-6Ed0kmC1NMbuFTEgNmamAUU1h5gShgxL1hBVLbEzUa3trX5aJBz1vU4bXaBTvOYUAnOHtiy1Ml4AMStd6hJnFA==} + engines: {node: '>=18.0.0'} + '@babel/code-frame@7.27.1': resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} @@ -818,6 +1160,49 @@ packages: '@changesets/write@0.4.0': resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==} + '@cloudflare/kv-asset-handler@0.4.0': + resolution: {integrity: sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA==} + engines: {node: '>=18.0.0'} + + '@cloudflare/unenv-preset@2.6.2': + resolution: {integrity: sha512-C7/tW7Qy+wGOCmHXu7xpP1TF3uIhRoi7zVY7dmu/SOSGjPilK+lSQ2lIRILulZsT467ZJNlI0jBxMbd8LzkGRg==} + peerDependencies: + unenv: 2.0.0-rc.19 + workerd: ^1.20250802.0 + peerDependenciesMeta: + workerd: + optional: true + + '@cloudflare/workerd-darwin-64@1.20250816.0': + resolution: {integrity: sha512-yN1Rga4ufTdrJPCP4gEqfB47i1lWi3teY5IoeQbUuKnjnCtm4pZvXur526JzCmaw60Jx+AEWf5tizdwRd5hHBQ==} + engines: {node: '>=16'} + cpu: [x64] + os: [darwin] + + '@cloudflare/workerd-darwin-arm64@1.20250816.0': + resolution: {integrity: sha512-WyKPMQhbU+TTf4uDz3SA7ZObspg7WzyJMv/7J4grSddpdx2A4Y4SfPu3wsZleAOIMOAEVi0A1sYDhdltKM7Mxg==} + engines: {node: '>=16'} + cpu: [arm64] + os: [darwin] + + '@cloudflare/workerd-linux-64@1.20250816.0': + resolution: {integrity: sha512-NWHOuFnVBaPRhLHw8kjPO9GJmc2P/CTYbnNlNm0EThyi57o/oDx0ldWLJqEHlrdEPOw7zEVGBqM/6M+V9agC6w==} + engines: {node: '>=16'} + cpu: [x64] + os: [linux] + + '@cloudflare/workerd-linux-arm64@1.20250816.0': + resolution: {integrity: sha512-FR+/yhaWs7FhfC3GKsM3+usQVrGEweJ9qyh7p+R6HNwnobgKr/h5ATWvJ4obGJF6ZHHodgSe+gOSYR7fkJ1xAQ==} + engines: {node: '>=16'} + cpu: [arm64] + os: [linux] + + '@cloudflare/workerd-windows-64@1.20250816.0': + resolution: {integrity: sha512-0lqClj2UMhFa8tCBiiX7Zhd5Bjp0V+X8oNBG6V6WsR9p9/HlIHAGgwRAM7aYkyG+8KC8xlbC89O2AXUXLpHx0g==} + engines: {node: '>=16'} + cpu: [x64] + os: [win32] + '@commander-js/extra-typings@14.0.0': resolution: {integrity: sha512-hIn0ncNaJRLkZrxBIp5AsW/eXEHNKYQBh0aPdoUqNgD+Io3NIykQqpKFyKcuasZhicGaEZJX/JBSIkZ4e5x8Dg==} peerDependencies: @@ -1105,6 +1490,16 @@ packages: resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==} engines: {node: '>=10.0.0'} + '@dotenvx/dotenvx@1.31.0': + resolution: {integrity: sha512-GeDxvtjiRuoyWVU9nQneId879zIyNdL05bS7RKiqMkfBSKpHMWHLoRyRqjYWLaXmX/llKO1hTlqHDmatkQAjPA==} + hasBin: true + + '@ecies/ciphers@0.2.4': + resolution: {integrity: sha512-t+iX+Wf5nRKyNzk8dviW3Ikb/280+aEJAnw9YXvCp2tYGPSkMki+NRY+8aNLmVFv3eNtMdvViPNOPxS8SZNP+w==} + engines: {bun: '>=1', deno: '>=2', node: '>=16'} + peerDependencies: + '@noble/ciphers': ^1.0.0 + '@emnapi/core@1.3.1': resolution: {integrity: sha512-pVGjBIt1Y6gg3EJN8jTcfpP/+uuRksIo055oE/OBkDNcjZqVbfkWCksG1Jp4yZnj3iKWyWX8fdG/j6UDYPbFog==} @@ -1121,126 +1516,252 @@ packages: resolution: {integrity: sha512-xjZTSFgECpb9Ohuk5yMX5RhUEbfeQcuOp8IF60e+wyzWEF0M5xeSgqsfLtvPEX8BIyOX9saZqzuGPmZ8oWc+5Q==} engines: {node: '>=16'} + '@esbuild/aix-ppc64@0.25.4': + resolution: {integrity: sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/aix-ppc64@0.25.6': resolution: {integrity: sha512-ShbM/3XxwuxjFiuVBHA+d3j5dyac0aEVVq1oluIDf71hUw0aRF59dV/efUsIwFnR6m8JNM2FjZOzmaZ8yG61kw==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] + '@esbuild/android-arm64@0.25.4': + resolution: {integrity: sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm64@0.25.6': resolution: {integrity: sha512-hd5zdUarsK6strW+3Wxi5qWws+rJhCCbMiC9QZyzoxfk5uHRIE8T287giQxzVpEvCwuJ9Qjg6bEjcRJcgfLqoA==} engines: {node: '>=18'} cpu: [arm64] os: [android] + '@esbuild/android-arm@0.25.4': + resolution: {integrity: sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-arm@0.25.6': resolution: {integrity: sha512-S8ToEOVfg++AU/bHwdksHNnyLyVM+eMVAOf6yRKFitnwnbwwPNqKr3srzFRe7nzV69RQKb5DgchIX5pt3L53xg==} engines: {node: '>=18'} cpu: [arm] os: [android] + '@esbuild/android-x64@0.25.4': + resolution: {integrity: sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/android-x64@0.25.6': resolution: {integrity: sha512-0Z7KpHSr3VBIO9A/1wcT3NTy7EB4oNC4upJ5ye3R7taCc2GUdeynSLArnon5G8scPwaU866d3H4BCrE5xLW25A==} engines: {node: '>=18'} cpu: [x64] os: [android] + '@esbuild/darwin-arm64@0.25.4': + resolution: {integrity: sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-arm64@0.25.6': resolution: {integrity: sha512-FFCssz3XBavjxcFxKsGy2DYK5VSvJqa6y5HXljKzhRZ87LvEi13brPrf/wdyl/BbpbMKJNOr1Sd0jtW4Ge1pAA==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-x64@0.25.4': + resolution: {integrity: sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/darwin-x64@0.25.6': resolution: {integrity: sha512-GfXs5kry/TkGM2vKqK2oyiLFygJRqKVhawu3+DOCk7OxLy/6jYkWXhlHwOoTb0WqGnWGAS7sooxbZowy+pK9Yg==} engines: {node: '>=18'} cpu: [x64] os: [darwin] + '@esbuild/freebsd-arm64@0.25.4': + resolution: {integrity: sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-arm64@0.25.6': resolution: {integrity: sha512-aoLF2c3OvDn2XDTRvn8hN6DRzVVpDlj2B/F66clWd/FHLiHaG3aVZjxQX2DYphA5y/evbdGvC6Us13tvyt4pWg==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-x64@0.25.4': + resolution: {integrity: sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/freebsd-x64@0.25.6': resolution: {integrity: sha512-2SkqTjTSo2dYi/jzFbU9Plt1vk0+nNg8YC8rOXXea+iA3hfNJWebKYPs3xnOUf9+ZWhKAaxnQNUf2X9LOpeiMQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] + '@esbuild/linux-arm64@0.25.4': + resolution: {integrity: sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm64@0.25.6': resolution: {integrity: sha512-b967hU0gqKd9Drsh/UuAm21Khpoh6mPBSgz8mKRq4P5mVK8bpA+hQzmm/ZwGVULSNBzKdZPQBRT3+WuVavcWsQ==} engines: {node: '>=18'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm@0.25.4': + resolution: {integrity: sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-arm@0.25.6': resolution: {integrity: sha512-SZHQlzvqv4Du5PrKE2faN0qlbsaW/3QQfUUc6yO2EjFcA83xnwm91UbEEVx4ApZ9Z5oG8Bxz4qPE+HFwtVcfyw==} engines: {node: '>=18'} cpu: [arm] os: [linux] + '@esbuild/linux-ia32@0.25.4': + resolution: {integrity: sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-ia32@0.25.6': resolution: {integrity: sha512-aHWdQ2AAltRkLPOsKdi3xv0mZ8fUGPdlKEjIEhxCPm5yKEThcUjHpWB1idN74lfXGnZ5SULQSgtr5Qos5B0bPw==} engines: {node: '>=18'} cpu: [ia32] os: [linux] + '@esbuild/linux-loong64@0.25.4': + resolution: {integrity: sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-loong64@0.25.6': resolution: {integrity: sha512-VgKCsHdXRSQ7E1+QXGdRPlQ/e08bN6WMQb27/TMfV+vPjjTImuT9PmLXupRlC90S1JeNNW5lzkAEO/McKeJ2yg==} engines: {node: '>=18'} cpu: [loong64] os: [linux] + '@esbuild/linux-mips64el@0.25.4': + resolution: {integrity: sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-mips64el@0.25.6': resolution: {integrity: sha512-WViNlpivRKT9/py3kCmkHnn44GkGXVdXfdc4drNmRl15zVQ2+D2uFwdlGh6IuK5AAnGTo2qPB1Djppj+t78rzw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.25.6': - resolution: {integrity: sha512-wyYKZ9NTdmAMb5730I38lBqVu6cKl4ZfYXIs31Baf8aoOtB4xSGi3THmDYt4BTFHk7/EcVixkOV2uZfwU3Q2Jw==} + '@esbuild/linux-ppc64@0.25.4': + resolution: {integrity: sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.25.6': + '@esbuild/linux-ppc64@0.25.6': + resolution: {integrity: sha512-wyYKZ9NTdmAMb5730I38lBqVu6cKl4ZfYXIs31Baf8aoOtB4xSGi3THmDYt4BTFHk7/EcVixkOV2uZfwU3Q2Jw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.4': + resolution: {integrity: sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.6': resolution: {integrity: sha512-KZh7bAGGcrinEj4qzilJ4hqTY3Dg2U82c8bv+e1xqNqZCrCyc+TL9AUEn5WGKDzm3CfC5RODE/qc96OcbIe33w==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] + '@esbuild/linux-s390x@0.25.4': + resolution: {integrity: sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-s390x@0.25.6': resolution: {integrity: sha512-9N1LsTwAuE9oj6lHMyyAM+ucxGiVnEqUdp4v7IaMmrwb06ZTEVCIs3oPPplVsnjPfyjmxwHxHMF8b6vzUVAUGw==} engines: {node: '>=18'} cpu: [s390x] os: [linux] + '@esbuild/linux-x64@0.25.4': + resolution: {integrity: sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/linux-x64@0.25.6': resolution: {integrity: sha512-A6bJB41b4lKFWRKNrWoP2LHsjVzNiaurf7wyj/XtFNTsnPuxwEBWHLty+ZE0dWBKuSK1fvKgrKaNjBS7qbFKig==} engines: {node: '>=18'} cpu: [x64] os: [linux] + '@esbuild/netbsd-arm64@0.25.4': + resolution: {integrity: sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-arm64@0.25.6': resolution: {integrity: sha512-IjA+DcwoVpjEvyxZddDqBY+uJ2Snc6duLpjmkXm/v4xuS3H+3FkLZlDm9ZsAbF9rsfP3zeA0/ArNDORZgrxR/Q==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-x64@0.25.4': + resolution: {integrity: sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/netbsd-x64@0.25.6': resolution: {integrity: sha512-dUXuZr5WenIDlMHdMkvDc1FAu4xdWixTCRgP7RQLBOkkGgwuuzaGSYcOpW4jFxzpzL1ejb8yF620UxAqnBrR9g==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] + '@esbuild/openbsd-arm64@0.25.4': + resolution: {integrity: sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-arm64@0.25.6': resolution: {integrity: sha512-l8ZCvXP0tbTJ3iaqdNf3pjaOSd5ex/e6/omLIQCVBLmHTlfXW3zAxQ4fnDmPLOB1x9xrcSi/xtCWFwCZRIaEwg==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-x64@0.25.4': + resolution: {integrity: sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/openbsd-x64@0.25.6': resolution: {integrity: sha512-hKrmDa0aOFOr71KQ/19JC7az1P0GWtCN1t2ahYAf4O007DHZt/dW8ym5+CUdJhQ/qkZmI1HAF8KkJbEFtCL7gw==} engines: {node: '>=18'} @@ -1253,24 +1774,48 @@ packages: cpu: [arm64] os: [openharmony] + '@esbuild/sunos-x64@0.25.4': + resolution: {integrity: sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/sunos-x64@0.25.6': resolution: {integrity: sha512-dyCGxv1/Br7MiSC42qinGL8KkG4kX0pEsdb0+TKhmJZgCUDBGmyo1/ArCjNGiOLiIAgdbWgmWgib4HoCi5t7kA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] + '@esbuild/win32-arm64@0.25.4': + resolution: {integrity: sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-arm64@0.25.6': resolution: {integrity: sha512-42QOgcZeZOvXfsCBJF5Afw73t4veOId//XD3i+/9gSkhSV6Gk3VPlWncctI+JcOyERv85FUo7RxuxGy+z8A43Q==} engines: {node: '>=18'} cpu: [arm64] os: [win32] + '@esbuild/win32-ia32@0.25.4': + resolution: {integrity: sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-ia32@0.25.6': resolution: {integrity: sha512-4AWhgXmDuYN7rJI6ORB+uU9DHLq/erBbuMoAuB4VWJTu5KtCgcKYPynF0YI1VkBNuEfjNlLrFr9KZPJzrtLkrQ==} engines: {node: '>=18'} cpu: [ia32] os: [win32] + '@esbuild/win32-x64@0.25.4': + resolution: {integrity: sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@esbuild/win32-x64@0.25.6': resolution: {integrity: sha512-NgJPHHbEpLQgDH2MjQu90pzW/5vvXIZ7KOnPyNBm92A6WgZ/7b6fJyUBjoumLqeOQQGqY2QjQxRo97ah4Sj0cA==} engines: {node: '>=18'} @@ -1727,6 +2272,14 @@ packages: '@types/node': optional: true + '@isaacs/balanced-match@4.0.1': + resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} + engines: {node: 20 || >=22} + + '@isaacs/brace-expansion@5.0.0': + resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} + engines: {node: 20 || >=22} + '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -1816,6 +2369,9 @@ packages: resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} + '@jridgewell/source-map@0.3.11': + resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} + '@jridgewell/sourcemap-codec@1.5.4': resolution: {integrity: sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==} @@ -1909,6 +2465,30 @@ packages: cpu: [x64] os: [win32] + '@noble/ciphers@1.3.0': + resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==} + engines: {node: ^14.21.3 || >=16} + + '@noble/curves@1.9.7': + resolution: {integrity: sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==} + engines: {node: ^14.21.3 || >=16} + + '@noble/hashes@1.8.0': + resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} + engines: {node: ^14.21.3 || >=16} + + '@node-minify/core@8.0.6': + resolution: {integrity: sha512-/vxN46ieWDLU67CmgbArEvOb41zlYFOkOtr9QW9CnTrBLuTyGgkyNWC2y5+khvRw3Br58p2B5ZVSx/PxCTru6g==} + engines: {node: '>=16.0.0'} + + '@node-minify/terser@8.0.6': + resolution: {integrity: sha512-grQ1ipham743ch2c3++C8Isk6toJnxJSyDiwUI/IWUCh4CZFD6aYVw6UAY40IpCnjrq5aXGwiv5OZJn6Pr0hvg==} + engines: {node: '>=16.0.0'} + + '@node-minify/utils@8.0.6': + resolution: {integrity: sha512-csY4qcR7jUwiZmkreNTJhcypQfts2aY2CK+a+rXgXUImZiZiySh0FvwHjRnlqWKvg+y6ae9lHFzDRjBTmqlTIQ==} + engines: {node: '>=16.0.0'} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -1934,6 +2514,16 @@ packages: '@open-draft/until@2.1.0': resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==} + '@opennextjs/aws@3.7.4': + resolution: {integrity: sha512-s50dmKrgQ62GliffoI/hGGQVb3q/7ZN5VRa4jJw0ZsEGLfk25XuAulO/ySCYeE7/A23KoAYuhafnKr/h+vxOeQ==} + hasBin: true + + '@opennextjs/cloudflare@1.6.5': + resolution: {integrity: sha512-eOoRrslJW/cK5RotFHA8Se/KlKyynOFA29i9jor4cp1JF/AkGSwatUaBNK0oLvqM4nDCq3Bo/HlYRbyc/R/T0w==} + hasBin: true + peerDependencies: + wrangler: ^4.24.4 + '@panva/hkdf@1.2.1': resolution: {integrity: sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==} @@ -2051,6 +2641,15 @@ packages: '@polka/url@1.0.0-next.29': resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} + '@poppinss/colors@4.1.5': + resolution: {integrity: sha512-FvdDqtcRCtz6hThExcFOgW0cWX+xwSMWcRuQe5ZEb2m7cVQOAVZOIMt+/v9RxGiD9/OY16qJBXK4CVKWAPalBw==} + + '@poppinss/dumper@0.6.4': + resolution: {integrity: sha512-iG0TIdqv8xJ3Lt9O8DrPRxw1MRLjNpoqiSGU03P/wNLP/s0ra0udPJ1J2Tx5M0J3H/cVyEgpbn8xUKRY9j59kQ==} + + '@poppinss/exception@1.2.2': + resolution: {integrity: sha512-m7bpKCD4QMlFCjA/nKTs23fuvoVFoA83brRKmObCUNmi/9tVu8Ve3w4YQAnJu4q3Tjf5fr685HYIC/IA2zHRSg==} + '@puppeteer/browsers@2.10.5': resolution: {integrity: sha512-eifa0o+i8dERnngJwKrfp3dEq7ia5XFyoqB17S4gK8GhsQE4/P8nxOfQSE0zQHxzzLo/cmF+7+ywEQ7wK7Fb+w==} engines: {node: '>=18'} @@ -2711,6 +3310,10 @@ packages: resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} engines: {node: '>=10'} + '@sindresorhus/is@7.0.2': + resolution: {integrity: sha512-d9xRovfKNz1SKieM0qJdO+PQonjnnIfSNWfHYnBSJ9hkjm0ZPw6HlxscDXYstp3z+7V2GOFHc+J0CYrYTjqCJw==} + engines: {node: '>=18'} + '@sindresorhus/merge-streams@2.3.0': resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} engines: {node: '>=18'} @@ -2725,6 +3328,361 @@ packages: '@sinonjs/fake-timers@10.3.0': resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + '@smithy/abort-controller@2.2.0': + resolution: {integrity: sha512-wRlta7GuLWpTqtFfGo+nZyOO1vEvewdNR1R4rTxpC8XU6vG/NDyrFBhwLZsqg1NUoR1noVaXJPC/7ZK47QCySw==} + engines: {node: '>=14.0.0'} + + '@smithy/abort-controller@4.0.5': + resolution: {integrity: sha512-jcrqdTQurIrBbUm4W2YdLVMQDoL0sA9DTxYd2s+R/y+2U9NLOP7Xf/YqfSg1FZhlZIYEnvk2mwbyvIfdLEPo8g==} + engines: {node: '>=18.0.0'} + + '@smithy/chunked-blob-reader-native@4.0.0': + resolution: {integrity: sha512-R9wM2yPmfEMsUmlMlIgSzOyICs0x9uu7UTHoccMyt7BWw8shcGM8HqB355+BZCPBcySvbTYMs62EgEQkNxz2ig==} + engines: {node: '>=18.0.0'} + + '@smithy/chunked-blob-reader@5.0.0': + resolution: {integrity: sha512-+sKqDBQqb036hh4NPaUiEkYFkTUGYzRsn3EuFhyfQfMy6oGHEUJDurLP9Ufb5dasr/XiAmPNMr6wa9afjQB+Gw==} + engines: {node: '>=18.0.0'} + + '@smithy/config-resolver@2.2.0': + resolution: {integrity: sha512-fsiMgd8toyUba6n1WRmr+qACzXltpdDkPTAaDqc8QqPBUzO+/JKwL6bUBseHVi8tu9l+3JOK+tSf7cay+4B3LA==} + engines: {node: '>=14.0.0'} + + '@smithy/config-resolver@4.1.5': + resolution: {integrity: sha512-viuHMxBAqydkB0AfWwHIdwf/PRH2z5KHGUzqyRtS/Wv+n3IHI993Sk76VCA7dD/+GzgGOmlJDITfPcJC1nIVIw==} + engines: {node: '>=18.0.0'} + + '@smithy/core@3.8.0': + resolution: {integrity: sha512-EYqsIYJmkR1VhVE9pccnk353xhs+lB6btdutJEtsp7R055haMJp2yE16eSxw8fv+G0WUY6vqxyYOP8kOqawxYQ==} + engines: {node: '>=18.0.0'} + + '@smithy/credential-provider-imds@2.3.0': + resolution: {integrity: sha512-BWB9mIukO1wjEOo1Ojgl6LrG4avcaC7T/ZP6ptmAaW4xluhSIPZhY+/PI5YKzlk+jsm+4sQZB45Bt1OfMeQa3w==} + engines: {node: '>=14.0.0'} + + '@smithy/credential-provider-imds@4.0.7': + resolution: {integrity: sha512-dDzrMXA8d8riFNiPvytxn0mNwR4B3h8lgrQ5UjAGu6T9z/kRg/Xncf4tEQHE/+t25sY8IH3CowcmWi+1U5B1Gw==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-codec@4.0.5': + resolution: {integrity: sha512-miEUN+nz2UTNoRYRhRqVTJCx7jMeILdAurStT2XoS+mhokkmz1xAPp95DFW9Gxt4iF2VBqpeF9HbTQ3kY1viOA==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-serde-browser@4.0.5': + resolution: {integrity: sha512-LCUQUVTbM6HFKzImYlSB9w4xafZmpdmZsOh9rIl7riPC3osCgGFVP+wwvYVw6pXda9PPT9TcEZxaq3XE81EdJQ==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-serde-config-resolver@4.1.3': + resolution: {integrity: sha512-yTTzw2jZjn/MbHu1pURbHdpjGbCuMHWncNBpJnQAPxOVnFUAbSIUSwafiphVDjNV93TdBJWmeVAds7yl5QCkcA==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-serde-node@4.0.5': + resolution: {integrity: sha512-lGS10urI4CNzz6YlTe5EYG0YOpsSp3ra8MXyco4aqSkQDuyZPIw2hcaxDU82OUVtK7UY9hrSvgWtpsW5D4rb4g==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-serde-universal@4.0.5': + resolution: {integrity: sha512-JFnmu4SU36YYw3DIBVao3FsJh4Uw65vVDIqlWT4LzR6gXA0F3KP0IXFKKJrhaVzCBhAuMsrUUaT5I+/4ZhF7aw==} + engines: {node: '>=18.0.0'} + + '@smithy/fetch-http-handler@2.5.0': + resolution: {integrity: sha512-BOWEBeppWhLn/no/JxUL/ghTfANTjT7kg3Ww2rPqTUY9R4yHPXxJ9JhMe3Z03LN3aPwiwlpDIUcVw1xDyHqEhw==} + + '@smithy/fetch-http-handler@5.1.1': + resolution: {integrity: sha512-61WjM0PWmZJR+SnmzaKI7t7G0UkkNFboDpzIdzSoy7TByUzlxo18Qlh9s71qug4AY4hlH/CwXdubMtkcNEb/sQ==} + engines: {node: '>=18.0.0'} + + '@smithy/hash-blob-browser@4.0.5': + resolution: {integrity: sha512-F7MmCd3FH/Q2edhcKd+qulWkwfChHbc9nhguBlVjSUE6hVHhec3q6uPQ+0u69S6ppvLtR3eStfCuEKMXBXhvvA==} + engines: {node: '>=18.0.0'} + + '@smithy/hash-node@2.2.0': + resolution: {integrity: sha512-zLWaC/5aWpMrHKpoDF6nqpNtBhlAYKF/7+9yMN7GpdR8CzohnWfGtMznPybnwSS8saaXBMxIGwJqR4HmRp6b3g==} + engines: {node: '>=14.0.0'} + + '@smithy/hash-node@4.0.5': + resolution: {integrity: sha512-cv1HHkKhpyRb6ahD8Vcfb2Hgz67vNIXEp2vnhzfxLFGRukLCNEA5QdsorbUEzXma1Rco0u3rx5VTqbM06GcZqQ==} + engines: {node: '>=18.0.0'} + + '@smithy/hash-stream-node@4.0.5': + resolution: {integrity: sha512-IJuDS3+VfWB67UC0GU0uYBG/TA30w+PlOaSo0GPm9UHS88A6rCP6uZxNjNYiyRtOcjv7TXn/60cW8ox1yuZsLg==} + engines: {node: '>=18.0.0'} + + '@smithy/invalid-dependency@2.2.0': + resolution: {integrity: sha512-nEDASdbKFKPXN2O6lOlTgrEEOO9NHIeO+HVvZnkqc8h5U9g3BIhWsvzFo+UcUbliMHvKNPD/zVxDrkP1Sbgp8Q==} + + '@smithy/invalid-dependency@4.0.5': + resolution: {integrity: sha512-IVnb78Qtf7EJpoEVo7qJ8BEXQwgC4n3igeJNNKEj/MLYtapnx8A67Zt/J3RXAj2xSO1910zk0LdFiygSemuLow==} + engines: {node: '>=18.0.0'} + + '@smithy/is-array-buffer@2.2.0': + resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} + engines: {node: '>=14.0.0'} + + '@smithy/is-array-buffer@4.0.0': + resolution: {integrity: sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==} + engines: {node: '>=18.0.0'} + + '@smithy/md5-js@4.0.5': + resolution: {integrity: sha512-8n2XCwdUbGr8W/XhMTaxILkVlw2QebkVTn5tm3HOcbPbOpWg89zr6dPXsH8xbeTsbTXlJvlJNTQsKAIoqQGbdA==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-content-length@2.2.0': + resolution: {integrity: sha512-5bl2LG1Ah/7E5cMSC+q+h3IpVHMeOkG0yLRyQT1p2aMJkSrZG7RlXHPuAgb7EyaFeidKEnnd/fNaLLaKlHGzDQ==} + engines: {node: '>=14.0.0'} + + '@smithy/middleware-content-length@4.0.5': + resolution: {integrity: sha512-l1jlNZoYzoCC7p0zCtBDE5OBXZ95yMKlRlftooE5jPWQn4YBPLgsp+oeHp7iMHaTGoUdFqmHOPa8c9G3gBsRpQ==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-endpoint@2.5.1': + resolution: {integrity: sha512-1/8kFp6Fl4OsSIVTWHnNjLnTL8IqpIb/D3sTSczrKFnrE9VMNWxnrRKNvpUHOJ6zpGD5f62TPm7+17ilTJpiCQ==} + engines: {node: '>=14.0.0'} + + '@smithy/middleware-endpoint@4.1.18': + resolution: {integrity: sha512-ZhvqcVRPZxnZlokcPaTwb+r+h4yOIOCJmx0v2d1bpVlmP465g3qpVSf7wxcq5zZdu4jb0H4yIMxuPwDJSQc3MQ==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-retry@2.3.1': + resolution: {integrity: sha512-P2bGufFpFdYcWvqpyqqmalRtwFUNUA8vHjJR5iGqbfR6mp65qKOLcUd6lTr4S9Gn/enynSrSf3p3FVgVAf6bXA==} + engines: {node: '>=14.0.0'} + + '@smithy/middleware-retry@4.1.19': + resolution: {integrity: sha512-X58zx/NVECjeuUB6A8HBu4bhx72EoUz+T5jTMIyeNKx2lf+Gs9TmWPNNkH+5QF0COjpInP/xSpJGJ7xEnAklQQ==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-serde@2.3.0': + resolution: {integrity: sha512-sIADe7ojwqTyvEQBe1nc/GXB9wdHhi9UwyX0lTyttmUWDJLP655ZYE1WngnNyXREme8I27KCaUhyhZWRXL0q7Q==} + engines: {node: '>=14.0.0'} + + '@smithy/middleware-serde@4.0.9': + resolution: {integrity: sha512-uAFFR4dpeoJPGz8x9mhxp+RPjo5wW0QEEIPPPbLXiRRWeCATf/Km3gKIVR5vaP8bN1kgsPhcEeh+IZvUlBv6Xg==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-stack@2.2.0': + resolution: {integrity: sha512-Qntc3jrtwwrsAC+X8wms8zhrTr0sFXnyEGhZd9sLtsJ/6gGQKFzNB+wWbOcpJd7BR8ThNCoKt76BuQahfMvpeA==} + engines: {node: '>=14.0.0'} + + '@smithy/middleware-stack@4.0.5': + resolution: {integrity: sha512-/yoHDXZPh3ocRVyeWQFvC44u8seu3eYzZRveCMfgMOBcNKnAmOvjbL9+Cp5XKSIi9iYA9PECUuW2teDAk8T+OQ==} + engines: {node: '>=18.0.0'} + + '@smithy/node-config-provider@2.3.0': + resolution: {integrity: sha512-0elK5/03a1JPWMDPaS726Iw6LpQg80gFut1tNpPfxFuChEEklo2yL823V94SpTZTxmKlXFtFgsP55uh3dErnIg==} + engines: {node: '>=14.0.0'} + + '@smithy/node-config-provider@4.1.4': + resolution: {integrity: sha512-+UDQV/k42jLEPPHSn39l0Bmc4sB1xtdI9Gd47fzo/0PbXzJ7ylgaOByVjF5EeQIumkepnrJyfx86dPa9p47Y+w==} + engines: {node: '>=18.0.0'} + + '@smithy/node-http-handler@2.5.0': + resolution: {integrity: sha512-mVGyPBzkkGQsPoxQUbxlEfRjrj6FPyA3u3u2VXGr9hT8wilsoQdZdvKpMBFMB8Crfhv5dNkKHIW0Yyuc7eABqA==} + engines: {node: '>=14.0.0'} + + '@smithy/node-http-handler@4.1.1': + resolution: {integrity: sha512-RHnlHqFpoVdjSPPiYy/t40Zovf3BBHc2oemgD7VsVTFFZrU5erFFe0n52OANZZ/5sbshgD93sOh5r6I35Xmpaw==} + engines: {node: '>=18.0.0'} + + '@smithy/property-provider@2.2.0': + resolution: {integrity: sha512-+xiil2lFhtTRzXkx8F053AV46QnIw6e7MV8od5Mi68E1ICOjCeCHw2XfLnDEUHnT9WGUIkwcqavXjfwuJbGlpg==} + engines: {node: '>=14.0.0'} + + '@smithy/property-provider@4.0.5': + resolution: {integrity: sha512-R/bswf59T/n9ZgfgUICAZoWYKBHcsVDurAGX88zsiUtOTA/xUAPyiT+qkNCPwFn43pZqN84M4MiUsbSGQmgFIQ==} + engines: {node: '>=18.0.0'} + + '@smithy/protocol-http@2.0.5': + resolution: {integrity: sha512-d2hhHj34mA2V86doiDfrsy2fNTnUOowGaf9hKb0hIPHqvcnShU4/OSc4Uf1FwHkAdYF3cFXTrj5VGUYbEuvMdw==} + engines: {node: '>=14.0.0'} + + '@smithy/protocol-http@3.3.0': + resolution: {integrity: sha512-Xy5XK1AFWW2nlY/biWZXu6/krgbaf2dg0q492D8M5qthsnU2H+UgFeZLbM76FnH7s6RO/xhQRkj+T6KBO3JzgQ==} + engines: {node: '>=14.0.0'} + + '@smithy/protocol-http@5.1.3': + resolution: {integrity: sha512-fCJd2ZR7D22XhDY0l+92pUag/7je2BztPRQ01gU5bMChcyI0rlly7QFibnYHzcxDvccMjlpM/Q1ev8ceRIb48w==} + engines: {node: '>=18.0.0'} + + '@smithy/querystring-builder@2.2.0': + resolution: {integrity: sha512-L1kSeviUWL+emq3CUVSgdogoM/D9QMFaqxL/dd0X7PCNWmPXqt+ExtrBjqT0V7HLN03Vs9SuiLrG3zy3JGnE5A==} + engines: {node: '>=14.0.0'} + + '@smithy/querystring-builder@4.0.5': + resolution: {integrity: sha512-NJeSCU57piZ56c+/wY+AbAw6rxCCAOZLCIniRE7wqvndqxcKKDOXzwWjrY7wGKEISfhL9gBbAaWWgHsUGedk+A==} + engines: {node: '>=18.0.0'} + + '@smithy/querystring-parser@2.2.0': + resolution: {integrity: sha512-BvHCDrKfbG5Yhbpj4vsbuPV2GgcpHiAkLeIlcA1LtfpMz3jrqizP1+OguSNSj1MwBHEiN+jwNisXLGdajGDQJA==} + engines: {node: '>=14.0.0'} + + '@smithy/querystring-parser@4.0.5': + resolution: {integrity: sha512-6SV7md2CzNG/WUeTjVe6Dj8noH32r4MnUeFKZrnVYsQxpGSIcphAanQMayi8jJLZAWm6pdM9ZXvKCpWOsIGg0w==} + engines: {node: '>=18.0.0'} + + '@smithy/service-error-classification@2.1.5': + resolution: {integrity: sha512-uBDTIBBEdAQryvHdc5W8sS5YX7RQzF683XrHePVdFmAgKiMofU15FLSM0/HU03hKTnazdNRFa0YHS7+ArwoUSQ==} + engines: {node: '>=14.0.0'} + + '@smithy/service-error-classification@4.0.7': + resolution: {integrity: sha512-XvRHOipqpwNhEjDf2L5gJowZEm5nsxC16pAZOeEcsygdjv9A2jdOh3YoDQvOXBGTsaJk6mNWtzWalOB9976Wlg==} + engines: {node: '>=18.0.0'} + + '@smithy/shared-ini-file-loader@2.4.0': + resolution: {integrity: sha512-WyujUJL8e1B6Z4PBfAqC/aGY1+C7T0w20Gih3yrvJSk97gpiVfB+y7c46T4Nunk+ZngLq0rOIdeVeIklk0R3OA==} + engines: {node: '>=14.0.0'} + + '@smithy/shared-ini-file-loader@4.0.5': + resolution: {integrity: sha512-YVVwehRDuehgoXdEL4r1tAAzdaDgaC9EQvhK0lEbfnbrd0bd5+CTQumbdPryX3J2shT7ZqQE+jPW4lmNBAB8JQ==} + engines: {node: '>=18.0.0'} + + '@smithy/signature-v4@2.3.0': + resolution: {integrity: sha512-ui/NlpILU+6HAQBfJX8BBsDXuKSNrjTSuOYArRblcrErwKFutjrCNb/OExfVRyj9+26F9J+ZmfWT+fKWuDrH3Q==} + engines: {node: '>=14.0.0'} + + '@smithy/signature-v4@5.1.3': + resolution: {integrity: sha512-mARDSXSEgllNzMw6N+mC+r1AQlEBO3meEAkR/UlfAgnMzJUB3goRBWgip1EAMG99wh36MDqzo86SfIX5Y+VEaw==} + engines: {node: '>=18.0.0'} + + '@smithy/smithy-client@2.5.1': + resolution: {integrity: sha512-jrbSQrYCho0yDaaf92qWgd+7nAeap5LtHTI51KXqmpIFCceKU3K9+vIVTUH72bOJngBMqa4kyu1VJhRcSrk/CQ==} + engines: {node: '>=14.0.0'} + + '@smithy/smithy-client@4.4.10': + resolution: {integrity: sha512-iW6HjXqN0oPtRS0NK/zzZ4zZeGESIFcxj2FkWed3mcK8jdSdHzvnCKXSjvewESKAgGKAbJRA+OsaqKhkdYRbQQ==} + engines: {node: '>=18.0.0'} + + '@smithy/types@2.12.0': + resolution: {integrity: sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==} + engines: {node: '>=14.0.0'} + + '@smithy/types@4.3.2': + resolution: {integrity: sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw==} + engines: {node: '>=18.0.0'} + + '@smithy/url-parser@2.2.0': + resolution: {integrity: sha512-hoA4zm61q1mNTpksiSWp2nEl1dt3j726HdRhiNgVJQMj7mLp7dprtF57mOB6JvEk/x9d2bsuL5hlqZbBuHQylQ==} + + '@smithy/url-parser@4.0.5': + resolution: {integrity: sha512-j+733Um7f1/DXjYhCbvNXABV53NyCRRA54C7bNEIxNPs0YjfRxeMKjjgm2jvTYrciZyCjsicHwQ6Q0ylo+NAUw==} + engines: {node: '>=18.0.0'} + + '@smithy/util-base64@2.3.0': + resolution: {integrity: sha512-s3+eVwNeJuXUwuMbusncZNViuhv2LjVJ1nMwTqSA0XAC7gjKhqqxRdJPhR8+YrkoZ9IiIbFk/yK6ACe/xlF+hw==} + engines: {node: '>=14.0.0'} + + '@smithy/util-base64@4.0.0': + resolution: {integrity: sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==} + engines: {node: '>=18.0.0'} + + '@smithy/util-body-length-browser@2.2.0': + resolution: {integrity: sha512-dtpw9uQP7W+n3vOtx0CfBD5EWd7EPdIdsQnWTDoFf77e3VUf05uA7R7TGipIo8e4WL2kuPdnsr3hMQn9ziYj5w==} + + '@smithy/util-body-length-browser@4.0.0': + resolution: {integrity: sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA==} + engines: {node: '>=18.0.0'} + + '@smithy/util-body-length-node@2.3.0': + resolution: {integrity: sha512-ITWT1Wqjubf2CJthb0BuT9+bpzBfXeMokH/AAa5EJQgbv9aPMVfnM76iFIZVFf50hYXGbtiV71BHAthNWd6+dw==} + engines: {node: '>=14.0.0'} + + '@smithy/util-body-length-node@4.0.0': + resolution: {integrity: sha512-q0iDP3VsZzqJyje8xJWEJCNIu3lktUGVoSy1KB0UWym2CL1siV3artm+u1DFYTLejpsrdGyCSWBdGNjJzfDPjg==} + engines: {node: '>=18.0.0'} + + '@smithy/util-buffer-from@2.2.0': + resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} + engines: {node: '>=14.0.0'} + + '@smithy/util-buffer-from@4.0.0': + resolution: {integrity: sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==} + engines: {node: '>=18.0.0'} + + '@smithy/util-config-provider@2.3.0': + resolution: {integrity: sha512-HZkzrRcuFN1k70RLqlNK4FnPXKOpkik1+4JaBoHNJn+RnJGYqaa3c5/+XtLOXhlKzlRgNvyaLieHTW2VwGN0VQ==} + engines: {node: '>=14.0.0'} + + '@smithy/util-config-provider@4.0.0': + resolution: {integrity: sha512-L1RBVzLyfE8OXH+1hsJ8p+acNUSirQnWQ6/EgpchV88G6zGBTDPdXiiExei6Z1wR2RxYvxY/XLw6AMNCCt8H3w==} + engines: {node: '>=18.0.0'} + + '@smithy/util-defaults-mode-browser@2.2.1': + resolution: {integrity: sha512-RtKW+8j8skk17SYowucwRUjeh4mCtnm5odCL0Lm2NtHQBsYKrNW0od9Rhopu9wF1gHMfHeWF7i90NwBz/U22Kw==} + engines: {node: '>= 10.0.0'} + + '@smithy/util-defaults-mode-browser@4.0.26': + resolution: {integrity: sha512-xgl75aHIS/3rrGp7iTxQAOELYeyiwBu+eEgAk4xfKwJJ0L8VUjhO2shsDpeil54BOFsqmk5xfdesiewbUY5tKQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-defaults-mode-node@2.3.1': + resolution: {integrity: sha512-vkMXHQ0BcLFysBMWgSBLSk3+leMpFSyyFj8zQtv5ZyUBx8/owVh1/pPEkzmW/DR/Gy/5c8vjLDD9gZjXNKbrpA==} + engines: {node: '>= 10.0.0'} + + '@smithy/util-defaults-mode-node@4.0.26': + resolution: {integrity: sha512-z81yyIkGiLLYVDetKTUeCZQ8x20EEzvQjrqJtb/mXnevLq2+w3XCEWTJ2pMp401b6BkEkHVfXb/cROBpVauLMQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-endpoints@3.0.7': + resolution: {integrity: sha512-klGBP+RpBp6V5JbrY2C/VKnHXn3d5V2YrifZbmMY8os7M6m8wdYFoO6w/fe5VkP+YVwrEktW3IWYaSQVNZJ8oQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-hex-encoding@2.2.0': + resolution: {integrity: sha512-7iKXR+/4TpLK194pVjKiasIyqMtTYJsgKgM242Y9uzt5dhHnUDvMNb+3xIhRJ9QhvqGii/5cRUt4fJn3dtXNHQ==} + engines: {node: '>=14.0.0'} + + '@smithy/util-hex-encoding@4.0.0': + resolution: {integrity: sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==} + engines: {node: '>=18.0.0'} + + '@smithy/util-middleware@2.2.0': + resolution: {integrity: sha512-L1qpleXf9QD6LwLCJ5jddGkgWyuSvWBkJwWAZ6kFkdifdso+sk3L3O1HdmPvCdnCK3IS4qWyPxev01QMnfHSBw==} + engines: {node: '>=14.0.0'} + + '@smithy/util-middleware@4.0.5': + resolution: {integrity: sha512-N40PfqsZHRSsByGB81HhSo+uvMxEHT+9e255S53pfBw/wI6WKDI7Jw9oyu5tJTLwZzV5DsMha3ji8jk9dsHmQQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-retry@2.2.0': + resolution: {integrity: sha512-q9+pAFPTfftHXRytmZ7GzLFFrEGavqapFc06XxzZFcSIGERXMerXxCitjOG1prVDR9QdjqotF40SWvbqcCpf8g==} + engines: {node: '>= 14.0.0'} + + '@smithy/util-retry@4.0.7': + resolution: {integrity: sha512-TTO6rt0ppK70alZpkjwy+3nQlTiqNfoXja+qwuAchIEAIoSZW8Qyd76dvBv3I5bCpE38APafG23Y/u270NspiQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-stream@2.2.0': + resolution: {integrity: sha512-17faEXbYWIRst1aU9SvPZyMdWmqIrduZjVOqCPMIsWFNxs5yQQgFrJL6b2SdiCzyW9mJoDjFtgi53xx7EH+BXA==} + engines: {node: '>=14.0.0'} + + '@smithy/util-stream@4.2.4': + resolution: {integrity: sha512-vSKnvNZX2BXzl0U2RgCLOwWaAP9x/ddd/XobPK02pCbzRm5s55M53uwb1rl/Ts7RXZvdJZerPkA+en2FDghLuQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-uri-escape@2.2.0': + resolution: {integrity: sha512-jtmJMyt1xMD/d8OtbVJ2gFZOSKc+ueYJZPW20ULW1GOp/q/YIM0wNh+u8ZFao9UaIGz4WoPW8hC64qlWLIfoDA==} + engines: {node: '>=14.0.0'} + + '@smithy/util-uri-escape@4.0.0': + resolution: {integrity: sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==} + engines: {node: '>=18.0.0'} + + '@smithy/util-utf8@2.3.0': + resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} + engines: {node: '>=14.0.0'} + + '@smithy/util-utf8@4.0.0': + resolution: {integrity: sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==} + engines: {node: '>=18.0.0'} + + '@smithy/util-waiter@2.2.0': + resolution: {integrity: sha512-IHk53BVw6MPMi2Gsn+hCng8rFA3ZmR3Rk7GllxDUW9qFJl/hiSvskn7XldkECapQVkIg/1dHpMAxI9xSTaLLSA==} + engines: {node: '>=14.0.0'} + + '@smithy/util-waiter@4.0.7': + resolution: {integrity: sha512-mYqtQXPmrwvUljaHyGxYUIIRI3qjBTEb/f5QFi3A6VlxhpmZd5mWXn9W+qUkf2pVE1Hv3SqxefiZOPGdxmO64A==} + engines: {node: '>=18.0.0'} + + '@speed-highlight/core@1.2.7': + resolution: {integrity: sha512-0dxmVj4gxg3Jg879kvFS/msl4s9F3T9UXC1InxgOf7t5NvcPD97u/WTA5vL/IxWHMn7qSxBozqrnnE2wvl1m8g==} + '@stylistic/eslint-plugin@2.7.2': resolution: {integrity: sha512-3DVLU5HEuk2pQoBmXJlzvrxbKNpu2mJ0SRqz5O/CJjyNCr12ZiPcYMEtuArTyPOk5i7bsAU44nywh1rGfe3gKQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2869,6 +3827,9 @@ packages: '@tsconfig/node16@1.0.4': resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + '@tsconfig/node18@1.0.3': + resolution: {integrity: sha512-RbwvSJQsuN9TB04AQbGULYfOGE/RnSFk/FLQ5b0NmDf5Kx2q/lABZbHQPKCO1vZ6Fiwkplu+yb9pGdLy1iGseQ==} + '@tybys/wasm-util@0.9.0': resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==} @@ -2953,9 +3914,15 @@ packages: '@types/lodash@4.17.5': resolution: {integrity: sha512-MBIOHVZqVqgfro1euRDWX7OO0fBVUUMrN6Pwm8LQsz8cWhEpihlvR70ENj3f40j58TNxZaWv2ndSkInykNBBJw==} + '@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.123': + resolution: {integrity: sha512-K7DIaHnh0mzVxreCR9qwgNxp3MH9dltPNIEddW9MYUlcKAzm+3grKNSTe2vCJHI1FaLpvpL5JGJrz1UZDKYvDg==} + '@types/node@22.15.30': resolution: {integrity: sha512-6Q7lr06bEHdlfplU6YRbgG1SFBdlsfNC4/lX+SkhiTs0cpJkOElmWls8PxDFv4yY/xKb8Y6SO0OmSX4wgqTZbA==} @@ -2997,6 +3964,9 @@ packages: '@types/uuid@10.0.0': resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==} + '@types/uuid@9.0.8': + resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==} + '@types/yargs-parser@21.0.3': resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} @@ -3272,6 +4242,14 @@ packages: '@vue/shared@3.5.16': resolution: {integrity: sha512-c/0fWy3Jw6Z8L9FmTyYfkpM5zklnqqa9+a6dz3DvONRKW2NEbh46BP0FHuLFSWi2TnQEtp91Z6zOWNrU6QiyPg==} + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -3282,11 +4260,20 @@ packages: peerDependencies: acorn: '>=8.9.0' + acorn-walk@8.3.2: + resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} + engines: {node: '>=0.4.0'} + acorn-walk@8.3.4: resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} engines: {node: '>=0.4.0'} - acorn@8.15.0: + acorn@8.14.0: + resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} + engines: {node: '>=0.4.0'} + hasBin: true + + acorn@8.15.0: resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} engines: {node: '>=0.4.0'} hasBin: true @@ -3303,6 +4290,10 @@ packages: resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} engines: {node: '>= 14'} + agentkeepalive@4.6.0: + resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} + engines: {node: '>= 8.0.0'} + ajv-formats@3.0.1: resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} peerDependencies: @@ -3451,6 +4442,9 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} + aws4fetch@1.0.20: + resolution: {integrity: sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g==} + axe-core@4.10.3: resolution: {integrity: sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg==} engines: {node: '>=4'} @@ -3542,9 +4536,19 @@ packages: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} + blake3-wasm@2.1.5: + resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==} + + body-parser@2.2.0: + resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} + engines: {node: '>=18'} + boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + bowser@2.12.0: + resolution: {integrity: sha512-HcOcTudTeEWgbHh0Y1Tyb6fdeR71m4b/QACf0D4KswGTsNeIJQmg38mRENZPAYPZvGFN3fk3604XbQEPdxXdKg==} + brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -3730,9 +4734,16 @@ packages: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} + cliui@9.0.1: + resolution: {integrity: sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==} + engines: {node: '>=20'} + clone-response@1.0.3: resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} + cloudflare@4.5.0: + resolution: {integrity: sha512-fPcbPKx4zF45jBvQ0z7PCdgejVAPBBCZxwqk1k7krQNfpM07Cfj97/Q6wBzvYqlWXx/zt1S9+m8vnfCe06umbQ==} + clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} @@ -3762,10 +4773,17 @@ packages: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} + commander@11.1.0: + resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} + engines: {node: '>=16'} + commander@14.0.0: resolution: {integrity: sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==} engines: {node: '>=20'} + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} @@ -3807,6 +4825,10 @@ packages: resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} engines: {node: ^14.18.0 || >=16.10.0} + content-disposition@1.0.0: + resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==} + engines: {node: '>= 0.6'} + content-security-policy-builder@2.3.0: resolution: {integrity: sha512-qmdEmn1M+WpadIeBLKr9Em8VJSCjtRINCSbYsyJHQ4liTwCmrLzIRpJdJpoVDnsvWUrR5iblYhQJqA4b4Hs/iw==} engines: {node: '>=18.0.0'} @@ -3821,6 +4843,10 @@ packages: cookie-es@1.2.2: resolution: {integrity: sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==} + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + cookie@0.4.2: resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==} engines: {node: '>= 0.6'} @@ -3833,6 +4859,10 @@ packages: resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} + cookie@1.0.2: + resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} + engines: {node: '>=18'} + cors@2.8.5: resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} engines: {node: '>= 0.10'} @@ -3969,6 +4999,15 @@ packages: supports-color: optional: true + debug@4.3.6: + resolution: {integrity: sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + debug@4.4.1: resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} engines: {node: '>=6.0'} @@ -4043,6 +5082,10 @@ packages: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + destr@2.0.5: resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} @@ -4155,6 +5198,13 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + eciesjs@0.4.15: + resolution: {integrity: sha512-r6kEJXDKecVOCj2nLMuXK/FCPeurW33+3JRpfXVbjLja3XUYFfD9I/JBreH6sUyzcm3G/YQboBjMla6poKeSdA==} + engines: {bun: '>=1', deno: '>=2', node: '>=16'} + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + electron-to-chromium@1.5.165: resolution: {integrity: sha512-naiMx1Z6Nb2TxPU6fiFrUrDTjyPMLdTtaOd2oLmG8zVSg2hCWGkhPyxwk+qRmZ1ytwVqUv0u7ZcDA5+ALhaUtw==} @@ -4194,6 +5244,10 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + encoding-sniffer@0.2.0: resolution: {integrity: sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg==} @@ -4230,6 +5284,9 @@ packages: error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + error-stack-parser-es@1.0.5: + resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==} + es-abstract@1.23.9: resolution: {integrity: sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==} engines: {node: '>= 0.4'} @@ -4265,6 +5322,11 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} + esbuild@0.25.4: + resolution: {integrity: sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==} + engines: {node: '>=18'} + hasBin: true + esbuild@0.25.6: resolution: {integrity: sha512-GVuzuUwtdsghE3ocJ9Bs8PNoF13HNQ5TXbEi2AhvVb8xU1Iwt9Fos9FEamfoee+u/TOsn7GUWc04lz46n2bbTg==} engines: {node: '>=18'} @@ -4274,6 +5336,9 @@ packages: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + escape-string-regexp@2.0.0: resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} engines: {node: '>=8'} @@ -4505,6 +5570,14 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} @@ -4517,6 +5590,10 @@ packages: resolution: {integrity: sha512-jpWzZ1ZhwUmeWRhS7Qv3mhpOhLfwI+uAX4e5fOcXqwMR7EcJ0pj2kV1CVzHVMX/LphnKWD3LObjZCoJ71lKpHw==} engines: {node: ^18.19.0 || >=20.5.0} + exit-hook@2.2.1: + resolution: {integrity: sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==} + engines: {node: '>=6'} + exit@0.1.2: resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} engines: {node: '>= 0.8.0'} @@ -4529,6 +5606,10 @@ packages: resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + express@5.0.1: + resolution: {integrity: sha512-ORF7g6qGnD+YtUG9yx4DFoqCShNMmUKiXuT5oWMHiOvt/4WFbHC6yCwQMTSBMno7AqntNCAzzcnnjowRkTL9eQ==} + engines: {node: '>= 18'} + exsolve@1.0.5: resolution: {integrity: sha512-pz5dvkYYKQ1AHVrgOzBKWeP4u4FRb3a6DNK2ucr0OoNwYIU4QWsJ+NM36LLzORT+z845MzKHHhpXiUF5nvQoJg==} @@ -4576,10 +5657,18 @@ packages: fast-uri@3.0.3: resolution: {integrity: sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==} + fast-xml-parser@4.2.5: + resolution: {integrity: sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==} + hasBin: true + fast-xml-parser@4.5.3: resolution: {integrity: sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==} hasBin: true + fast-xml-parser@5.2.5: + resolution: {integrity: sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ==} + hasBin: true + fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} @@ -4612,6 +5701,10 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} + finalhandler@2.1.0: + resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==} + engines: {node: '>= 0.8'} + find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} @@ -4647,13 +5740,36 @@ packages: resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} engines: {node: '>=14'} + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + + form-data-encoder@1.7.2: + resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==} + form-data@4.0.2: resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==} engines: {node: '>= 6'} + form-data@4.0.4: + resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==} + engines: {node: '>= 6'} + + formdata-node@4.4.1: + resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==} + engines: {node: '>= 12.20'} + + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + fs-extra@11.3.0: resolution: {integrity: sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==} engines: {node: '>=14.14'} @@ -4774,14 +5890,26 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} + glob-to-regexp@0.4.1: + resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} + glob@10.4.5: resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} hasBin: true + glob@11.0.3: + resolution: {integrity: sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==} + engines: {node: 20 || >=22} + hasBin: true + glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} deprecated: Glob versions prior to v9 are no longer supported + glob@9.3.5: + resolution: {integrity: sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==} + engines: {node: '>=16 || 14 >=14.17'} + globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} @@ -4882,6 +6010,10 @@ packages: http-cache-semantics@4.2.0: resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} + http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} + http-link-header@1.1.3: resolution: {integrity: sha512-3cZ0SRL8fb9MUlU3mKM61FcQvPfXx2dBrZW3Vbg5CXa8jFlK8OaEpePenLe1oEXQduhz8b0QjsqfS59QP4AJDQ==} engines: {node: '>=6.0.0'} @@ -4922,6 +6054,9 @@ packages: resolution: {integrity: sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==} engines: {node: '>=18.18.0'} + humanize-ms@1.2.1: + resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + iconv-lite@0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} @@ -4978,6 +6113,10 @@ packages: resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==} engines: {node: '>= 12'} + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + iron-webcrypto@1.2.1: resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} @@ -5107,6 +6246,9 @@ packages: is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + is-reference@3.0.3: resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==} @@ -5195,6 +6337,10 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + isexe@3.1.1: + resolution: {integrity: sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==} + engines: {node: '>=16'} + isomorphic-dompurify@2.25.0: resolution: {integrity: sha512-bcpJzu9DOjN21qaCVpcoCwUX1ytpvA6EFqCK5RNtPg5+F0Jz9PX50jl6jbEicBNeO87eDDfC7XtPs4zjDClZJg==} engines: {node: '>=18'} @@ -5237,6 +6383,10 @@ packages: jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + jackspeak@4.1.1: + resolution: {integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==} + engines: {node: 20 || >=22} + jest-changed-files@29.7.0: resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -5470,6 +6620,10 @@ packages: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} + kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + knitwork@1.2.0: resolution: {integrity: sha512-xYSH7AvuQ6nXkq42x0v5S8/Iry+cfulBz/DJQzhIyESdLD7425jXsPy4vn5cCXU+HhRN2kVw51Vd1K6/By4BQg==} @@ -5716,6 +6870,14 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -5726,6 +6888,10 @@ packages: metaviewport-parser@0.3.0: resolution: {integrity: sha512-EoYJ8xfjQ6kpe9VbVHvZTZHiOl4HL1Z18CrZ+qahvLXT7ZO4YTC2JMyt5FaUp9JJp6J4Ybb/z7IsCXZt86/QkQ==} + methods@1.1.2: + resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} + engines: {node: '>= 0.6'} + micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} @@ -5742,6 +6908,15 @@ packages: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} + mime-types@3.0.1: + resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} + engines: {node: '>= 0.6'} + + mime@3.0.0: + resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} + engines: {node: '>=10.0.0'} + hasBin: true + mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} @@ -5762,9 +6937,22 @@ packages: resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} engines: {node: '>=10'} + miniflare@4.20250816.0: + resolution: {integrity: sha512-HuakGvmsU8aC60wsHP7Su+BgJFly1GmKbmbR/nqIz0Xlk6wcd/pp3vZ7jtbT3unf+aeBOlEO/CzcUb8xFsJLdA==} + engines: {node: '>=18.0.0'} + hasBin: true + + minimatch@10.0.3: + resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==} + engines: {node: 20 || >=22} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@8.0.4: + resolution: {integrity: sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==} + engines: {node: '>=16 || 14 >=14.17'} + minimatch@9.0.5: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} @@ -5776,6 +6964,10 @@ packages: resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} engines: {node: '>=8'} + minipass@4.2.8: + resolution: {integrity: sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==} + engines: {node: '>=8'} + minipass@5.0.0: resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} engines: {node: '>=8'} @@ -5799,6 +6991,9 @@ packages: mlly@1.7.4: resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==} + mnemonist@0.38.3: + resolution: {integrity: sha512-2K9QYubXx/NAjv4VLq1d1Ly8pWNC5L3BrixtdkyTegXWJIqY+zLNDhhX/A+ZwWt70tB1S8H4BE8FLYEFyNoOBw==} + mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} @@ -5810,6 +7005,9 @@ packages: ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -5900,6 +7098,11 @@ packages: node-addon-api@7.1.1: resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + deprecated: Use your platform's native DOMException instead + node-fetch-native@1.6.6: resolution: {integrity: sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ==} @@ -6006,6 +7209,10 @@ packages: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} + object-treeify@1.1.33: + resolution: {integrity: sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A==} + engines: {node: '>= 10'} + object.assign@4.1.7: resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} engines: {node: '>= 0.4'} @@ -6026,6 +7233,9 @@ packages: resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} engines: {node: '>= 0.4'} + obliterator@1.6.1: + resolution: {integrity: sha512-9WXswnqINnnhOG/5SLimUlzuU1hFJUc8zkwyD59Sd+dPOMf05PmnYG/d6Q7HZ+KmgkZJa1PxRso6QdM3sTNHig==} + ofetch@1.4.1: resolution: {integrity: sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw==} @@ -6035,6 +7245,10 @@ packages: ohash@2.0.11: resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + on-headers@1.0.2: resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==} engines: {node: '>= 0.8'} @@ -6166,6 +7380,10 @@ packages: parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -6189,9 +7407,17 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} + path-scurry@2.0.0: + resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} + engines: {node: 20 || >=22} + path-to-regexp@6.3.0: resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} + path-to-regexp@8.2.0: + resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==} + engines: {node: '>=16'} + path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -6593,6 +7819,10 @@ packages: prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + proxy-agent@6.5.0: resolution: {integrity: sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==} engines: {node: '>= 14'} @@ -6631,6 +7861,14 @@ packages: pure-rand@6.1.0: resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + qs@6.13.0: + resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} + engines: {node: '>=0.6'} + + qs@6.14.0: + resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} + engines: {node: '>=0.6'} + quansync@0.2.10: resolution: {integrity: sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==} @@ -6650,6 +7888,14 @@ packages: raf@3.4.1: resolution: {integrity: sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==} + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + raw-body@3.0.0: + resolution: {integrity: sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==} + engines: {node: '>= 0.8'} + rc9@2.1.2: resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} @@ -6824,6 +8070,10 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + rrweb-cssom@0.8.0: resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==} @@ -6885,6 +8135,14 @@ packages: engines: {node: '>=10'} hasBin: true + send@1.2.0: + resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} + engines: {node: '>= 18'} + + serve-static@2.2.0: + resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} + engines: {node: '>= 18'} + server-only@0.0.1: resolution: {integrity: sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==} @@ -6900,6 +8158,9 @@ packages: resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} engines: {node: '>= 0.4'} + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + shallowequal@1.1.0: resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==} @@ -7007,6 +8268,9 @@ packages: source-map-support@0.5.13: resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + source-map@0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} @@ -7059,6 +8323,10 @@ packages: resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==} engines: {node: '>=18'} + stoppable@1.1.0: + resolution: {integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==} + engines: {node: '>=4', npm: '>=6'} + streamx@2.22.1: resolution: {integrity: sha512-znKXEBxfatz2GBNK02kRnCXjV+AA4kjZIUxeWSr3UGirZMJfTE9uiwKHobnbgxWyL/JWro8tTq+vOqAK1/qbSA==} @@ -7148,6 +8416,9 @@ packages: strnum@1.1.2: resolution: {integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==} + strnum@2.1.1: + resolution: {integrity: sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw==} + stubborn-fs@1.2.5: resolution: {integrity: sha512-H2N9c26eXjzL/S/K+i/RHHcFanE74dptvvjM8iwzwbVcWY/zjBbgRqF3K0DY4+OD+uTTASTBvDoxPDaPN02D7g==} @@ -7169,6 +8440,10 @@ packages: engines: {node: '>=16 || 14 >=14.17'} hasBin: true + supports-color@10.2.0: + resolution: {integrity: sha512-5eG9FQjEjDbAlI5+kdpdyPIBMRH4GfTVDGREVupaZHmVoppknhM29b/S9BkQz7cathp85BVgRi/As3Siln7e0Q==} + engines: {node: '>=18'} + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -7230,6 +8505,11 @@ packages: resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} engines: {node: '>=8'} + terser@5.16.9: + resolution: {integrity: sha512-HPa/FdTB9XGI2H1/keLFZHxl6WNvAI4YalHGtDQTlMnJcoqSab1UwL4l1hGEhs6/GmLHBZIg/YgB++jcbzoOEg==} + engines: {node: '>=10'} + hasBin: true + test-exclude@6.0.0: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} engines: {node: '>=8'} @@ -7306,6 +8586,10 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + totalist@3.0.1: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} @@ -7358,6 +8642,9 @@ packages: '@swc/wasm': optional: true + ts-tqdm@0.8.6: + resolution: {integrity: sha512-3X3M1PZcHtgQbnwizL+xU8CAgbYbeLHrrDwL9xxcZZrV5J+e7loJm1XrXozHjSkl44J0Zg0SgA8rXbh83kCkcQ==} + tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} @@ -7446,6 +8733,10 @@ packages: resolution: {integrity: sha512-s6zVrxuyKbbAsSAD5ZPTB77q4YIdRctkTbJ2/Dqlinwz+8ooH2gd+YA7VA6Pa93KML9GockVvoxjZ2vHP+mu8g==} engines: {node: '>=16'} + type-is@2.0.1: + resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} + engines: {node: '>= 0.6'} + typed-array-buffer@1.0.3: resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} engines: {node: '>= 0.4'} @@ -7496,6 +8787,9 @@ packages: unctx@2.4.1: resolution: {integrity: sha512-AbaYw0Nm4mK4qjhns67C+kgxR2YWiwlDBPzxrN8h8C6VtAdCgditAY5Dezu3IJy4XVqAnbrXt9oQJvsn3fyozg==} + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} @@ -7503,6 +8797,13 @@ packages: resolution: {integrity: sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==} engines: {node: '>=18.17'} + undici@7.14.0: + resolution: {integrity: sha512-Vqs8HTzjpQXZeXdpsfChQTlafcMQaaIwnGwLam1wudSSjlJeQ3bw1j+TLPePgrCnCpUXx7Ba5Pdpf5OBih62NQ==} + engines: {node: '>=20.18.1'} + + unenv@2.0.0-rc.19: + resolution: {integrity: sha512-t/OMHBNAkknVCI7bVB9OWjUUAwhVv9vsPIAGnNUxnu3FxPQN11rjh0sksLMzc3g7IlTgvHmOTl4JM7JHpcv5wA==} + unicorn-magic@0.3.0: resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} engines: {node: '>=18'} @@ -7539,6 +8840,10 @@ packages: vue: optional: true + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + unplugin@1.16.1: resolution: {integrity: sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==} engines: {node: '>=14.0.0'} @@ -7604,10 +8909,18 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + utils-merge@1.0.1: + resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} + engines: {node: '>= 0.4.0'} + uuid@11.1.0: resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} hasBin: true + uuid@9.0.1: + resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} + hasBin: true + v8-compile-cache-lib@3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} @@ -7707,6 +9020,10 @@ packages: walker@1.0.8: resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + 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==} @@ -7770,6 +9087,11 @@ packages: engines: {node: '>= 8'} hasBin: true + which@4.0.0: + resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==} + engines: {node: ^16.13.0 || >=18.0.0} + hasBin: true + why-is-node-running@2.3.0: resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} engines: {node: '>=8'} @@ -7779,6 +9101,21 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + workerd@1.20250816.0: + resolution: {integrity: sha512-5gIvHPE/3QVlQR1Sc1NdBkWmqWj/TSgIbY/f/qs9lhiLBw/Da+HbNBTVYGjvwYqEb3NQ+XQM4gAm5b2+JJaUJg==} + engines: {node: '>=16'} + hasBin: true + + wrangler@4.31.0: + resolution: {integrity: sha512-blb8NfA4BGscvSzvLm2mEQRuUTmaMCiglkqHiR3EIque78UXG39xxVtFXlKhK32qaVvGI7ejdM//HC9plVPO3w==} + engines: {node: '>=18.0.0'} + hasBin: true + peerDependencies: + '@cloudflare/workers-types': ^4.20250816.0 + peerDependenciesMeta: + '@cloudflare/workers-types': + optional: true + wrap-ansi@6.2.0: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} engines: {node: '>=8'} @@ -7817,6 +9154,18 @@ packages: utf-8-validate: optional: true + ws@8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + ws@8.18.2: resolution: {integrity: sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==} engines: {node: '>=10.0.0'} @@ -7855,14 +9204,27 @@ packages: engines: {node: '>= 14'} hasBin: true + yaml@2.8.1: + resolution: {integrity: sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==} + engines: {node: '>= 14.6'} + hasBin: true + yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} + yargs-parser@22.0.0: + resolution: {integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + yargs@17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} + yargs@18.0.0: + resolution: {integrity: sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + yauzl@2.10.0: resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} @@ -7886,6 +9248,12 @@ packages: resolution: {integrity: sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==} engines: {node: '>=18'} + youch-core@0.3.3: + resolution: {integrity: sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==} + + youch@4.1.0-beta.10: + resolution: {integrity: sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==} + zimmerframe@1.1.2: resolution: {integrity: sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==} @@ -7895,6 +9263,9 @@ packages: peerDependencies: zod: ^3.24.4 + zod@3.22.3: + resolution: {integrity: sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==} + zod@3.23.8: resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} @@ -7931,6 +9302,45 @@ snapshots: '@csstools/css-tokenizer': 3.0.4 lru-cache: 10.4.3 + '@ast-grep/napi-darwin-arm64@0.35.0': + optional: true + + '@ast-grep/napi-darwin-x64@0.35.0': + optional: true + + '@ast-grep/napi-linux-arm64-gnu@0.35.0': + optional: true + + '@ast-grep/napi-linux-arm64-musl@0.35.0': + optional: true + + '@ast-grep/napi-linux-x64-gnu@0.35.0': + optional: true + + '@ast-grep/napi-linux-x64-musl@0.35.0': + optional: true + + '@ast-grep/napi-win32-arm64-msvc@0.35.0': + optional: true + + '@ast-grep/napi-win32-ia32-msvc@0.35.0': + optional: true + + '@ast-grep/napi-win32-x64-msvc@0.35.0': + optional: true + + '@ast-grep/napi@0.35.0': + optionalDependencies: + '@ast-grep/napi-darwin-arm64': 0.35.0 + '@ast-grep/napi-darwin-x64': 0.35.0 + '@ast-grep/napi-linux-arm64-gnu': 0.35.0 + '@ast-grep/napi-linux-arm64-musl': 0.35.0 + '@ast-grep/napi-linux-x64-gnu': 0.35.0 + '@ast-grep/napi-linux-x64-musl': 0.35.0 + '@ast-grep/napi-win32-arm64-msvc': 0.35.0 + '@ast-grep/napi-win32-ia32-msvc': 0.35.0 + '@ast-grep/napi-win32-x64-msvc': 0.35.0 + '@auth/core@0.37.2(nodemailer@6.9.16)': dependencies: '@panva/hkdf': 1.2.1 @@ -7943,65 +9353,1035 @@ snapshots: optionalDependencies: nodemailer: 6.9.16 - '@babel/code-frame@7.27.1': + '@aws-crypto/crc32@5.2.0': dependencies: - '@babel/helper-validator-identifier': 7.27.1 - js-tokens: 4.0.0 - picocolors: 1.1.1 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.862.0 + tslib: 2.8.1 - '@babel/compat-data@7.27.5': {} + '@aws-crypto/crc32c@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.862.0 + tslib: 2.8.1 - '@babel/core@7.27.4': + '@aws-crypto/ie11-detection@3.0.0': dependencies: - '@ampproject/remapping': 2.3.0 - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.27.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.27.3(@babel/core@7.27.4) - '@babel/helpers': 7.27.4 - '@babel/parser': 7.28.0 - '@babel/template': 7.27.2 - '@babel/traverse': 7.27.4 - '@babel/types': 7.28.0 - convert-source-map: 2.0.0 - debug: 4.4.1 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color + tslib: 1.14.1 - '@babel/generator@7.27.5': + '@aws-crypto/sha1-browser@5.2.0': dependencies: - '@babel/parser': 7.28.0 - '@babel/types': 7.28.0 - '@jridgewell/gen-mapping': 0.3.12 - '@jridgewell/trace-mapping': 0.3.29 - jsesc: 3.1.0 + '@aws-crypto/supports-web-crypto': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.862.0 + '@aws-sdk/util-locate-window': 3.804.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 - '@babel/helper-compilation-targets@7.27.2': + '@aws-crypto/sha256-browser@3.0.0': dependencies: - '@babel/compat-data': 7.27.5 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.25.0 - lru-cache: 5.1.1 - semver: 6.3.1 + '@aws-crypto/ie11-detection': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-crypto/supports-web-crypto': 3.0.0 + '@aws-crypto/util': 3.0.0 + '@aws-sdk/types': 3.398.0 + '@aws-sdk/util-locate-window': 3.804.0 + '@aws-sdk/util-utf8-browser': 3.259.0 + tslib: 1.14.1 - '@babel/helper-module-imports@7.27.1': + '@aws-crypto/sha256-browser@5.2.0': dependencies: - '@babel/traverse': 7.27.4 - '@babel/types': 7.28.0 - transitivePeerDependencies: - - supports-color + '@aws-crypto/sha256-js': 5.2.0 + '@aws-crypto/supports-web-crypto': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.862.0 + '@aws-sdk/util-locate-window': 3.804.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 - '@babel/helper-module-transforms@7.27.3(@babel/core@7.27.4)': + '@aws-crypto/sha256-js@3.0.0': dependencies: - '@babel/core': 7.27.4 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.27.4 - transitivePeerDependencies: - - supports-color + '@aws-crypto/util': 3.0.0 + '@aws-sdk/types': 3.398.0 + tslib: 1.14.1 + + '@aws-crypto/sha256-js@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.862.0 + tslib: 2.8.1 + + '@aws-crypto/supports-web-crypto@3.0.0': + dependencies: + tslib: 1.14.1 + + '@aws-crypto/supports-web-crypto@5.2.0': + dependencies: + tslib: 2.8.1 + + '@aws-crypto/util@3.0.0': + dependencies: + '@aws-sdk/types': 3.398.0 + '@aws-sdk/util-utf8-browser': 3.259.0 + tslib: 1.14.1 + + '@aws-crypto/util@5.2.0': + dependencies: + '@aws-sdk/types': 3.862.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-sdk/client-cloudfront@3.398.0': + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/client-sts': 3.398.0 + '@aws-sdk/credential-provider-node': 3.398.0 + '@aws-sdk/middleware-host-header': 3.398.0 + '@aws-sdk/middleware-logger': 3.398.0 + '@aws-sdk/middleware-recursion-detection': 3.398.0 + '@aws-sdk/middleware-signing': 3.398.0 + '@aws-sdk/middleware-user-agent': 3.398.0 + '@aws-sdk/types': 3.398.0 + '@aws-sdk/util-endpoints': 3.398.0 + '@aws-sdk/util-user-agent-browser': 3.398.0 + '@aws-sdk/util-user-agent-node': 3.398.0 + '@aws-sdk/xml-builder': 3.310.0 + '@smithy/config-resolver': 2.2.0 + '@smithy/fetch-http-handler': 2.5.0 + '@smithy/hash-node': 2.2.0 + '@smithy/invalid-dependency': 2.2.0 + '@smithy/middleware-content-length': 2.2.0 + '@smithy/middleware-endpoint': 2.5.1 + '@smithy/middleware-retry': 2.3.1 + '@smithy/middleware-serde': 2.3.0 + '@smithy/middleware-stack': 2.2.0 + '@smithy/node-config-provider': 2.3.0 + '@smithy/node-http-handler': 2.5.0 + '@smithy/protocol-http': 2.0.5 + '@smithy/smithy-client': 2.5.1 + '@smithy/types': 2.12.0 + '@smithy/url-parser': 2.2.0 + '@smithy/util-base64': 2.3.0 + '@smithy/util-body-length-browser': 2.2.0 + '@smithy/util-body-length-node': 2.3.0 + '@smithy/util-defaults-mode-browser': 2.2.1 + '@smithy/util-defaults-mode-node': 2.3.1 + '@smithy/util-retry': 2.2.0 + '@smithy/util-stream': 2.2.0 + '@smithy/util-utf8': 2.3.0 + '@smithy/util-waiter': 2.2.0 + fast-xml-parser: 4.2.5 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/client-dynamodb@3.868.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.864.0 + '@aws-sdk/credential-provider-node': 3.864.0 + '@aws-sdk/middleware-endpoint-discovery': 3.862.0 + '@aws-sdk/middleware-host-header': 3.862.0 + '@aws-sdk/middleware-logger': 3.862.0 + '@aws-sdk/middleware-recursion-detection': 3.862.0 + '@aws-sdk/middleware-user-agent': 3.864.0 + '@aws-sdk/region-config-resolver': 3.862.0 + '@aws-sdk/types': 3.862.0 + '@aws-sdk/util-endpoints': 3.862.0 + '@aws-sdk/util-user-agent-browser': 3.862.0 + '@aws-sdk/util-user-agent-node': 3.864.0 + '@smithy/config-resolver': 4.1.5 + '@smithy/core': 3.8.0 + '@smithy/fetch-http-handler': 5.1.1 + '@smithy/hash-node': 4.0.5 + '@smithy/invalid-dependency': 4.0.5 + '@smithy/middleware-content-length': 4.0.5 + '@smithy/middleware-endpoint': 4.1.18 + '@smithy/middleware-retry': 4.1.19 + '@smithy/middleware-serde': 4.0.9 + '@smithy/middleware-stack': 4.0.5 + '@smithy/node-config-provider': 4.1.4 + '@smithy/node-http-handler': 4.1.1 + '@smithy/protocol-http': 5.1.3 + '@smithy/smithy-client': 4.4.10 + '@smithy/types': 4.3.2 + '@smithy/url-parser': 4.0.5 + '@smithy/util-base64': 4.0.0 + '@smithy/util-body-length-browser': 4.0.0 + '@smithy/util-body-length-node': 4.0.0 + '@smithy/util-defaults-mode-browser': 4.0.26 + '@smithy/util-defaults-mode-node': 4.0.26 + '@smithy/util-endpoints': 3.0.7 + '@smithy/util-middleware': 4.0.5 + '@smithy/util-retry': 4.0.7 + '@smithy/util-utf8': 4.0.0 + '@smithy/util-waiter': 4.0.7 + '@types/uuid': 9.0.8 + tslib: 2.8.1 + uuid: 9.0.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/client-lambda@3.865.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.864.0 + '@aws-sdk/credential-provider-node': 3.864.0 + '@aws-sdk/middleware-host-header': 3.862.0 + '@aws-sdk/middleware-logger': 3.862.0 + '@aws-sdk/middleware-recursion-detection': 3.862.0 + '@aws-sdk/middleware-user-agent': 3.864.0 + '@aws-sdk/region-config-resolver': 3.862.0 + '@aws-sdk/types': 3.862.0 + '@aws-sdk/util-endpoints': 3.862.0 + '@aws-sdk/util-user-agent-browser': 3.862.0 + '@aws-sdk/util-user-agent-node': 3.864.0 + '@smithy/config-resolver': 4.1.5 + '@smithy/core': 3.8.0 + '@smithy/eventstream-serde-browser': 4.0.5 + '@smithy/eventstream-serde-config-resolver': 4.1.3 + '@smithy/eventstream-serde-node': 4.0.5 + '@smithy/fetch-http-handler': 5.1.1 + '@smithy/hash-node': 4.0.5 + '@smithy/invalid-dependency': 4.0.5 + '@smithy/middleware-content-length': 4.0.5 + '@smithy/middleware-endpoint': 4.1.18 + '@smithy/middleware-retry': 4.1.19 + '@smithy/middleware-serde': 4.0.9 + '@smithy/middleware-stack': 4.0.5 + '@smithy/node-config-provider': 4.1.4 + '@smithy/node-http-handler': 4.1.1 + '@smithy/protocol-http': 5.1.3 + '@smithy/smithy-client': 4.4.10 + '@smithy/types': 4.3.2 + '@smithy/url-parser': 4.0.5 + '@smithy/util-base64': 4.0.0 + '@smithy/util-body-length-browser': 4.0.0 + '@smithy/util-body-length-node': 4.0.0 + '@smithy/util-defaults-mode-browser': 4.0.26 + '@smithy/util-defaults-mode-node': 4.0.26 + '@smithy/util-endpoints': 3.0.7 + '@smithy/util-middleware': 4.0.5 + '@smithy/util-retry': 4.0.7 + '@smithy/util-stream': 4.2.4 + '@smithy/util-utf8': 4.0.0 + '@smithy/util-waiter': 4.0.7 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/client-s3@3.864.0': + dependencies: + '@aws-crypto/sha1-browser': 5.2.0 + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.864.0 + '@aws-sdk/credential-provider-node': 3.864.0 + '@aws-sdk/middleware-bucket-endpoint': 3.862.0 + '@aws-sdk/middleware-expect-continue': 3.862.0 + '@aws-sdk/middleware-flexible-checksums': 3.864.0 + '@aws-sdk/middleware-host-header': 3.862.0 + '@aws-sdk/middleware-location-constraint': 3.862.0 + '@aws-sdk/middleware-logger': 3.862.0 + '@aws-sdk/middleware-recursion-detection': 3.862.0 + '@aws-sdk/middleware-sdk-s3': 3.864.0 + '@aws-sdk/middleware-ssec': 3.862.0 + '@aws-sdk/middleware-user-agent': 3.864.0 + '@aws-sdk/region-config-resolver': 3.862.0 + '@aws-sdk/signature-v4-multi-region': 3.864.0 + '@aws-sdk/types': 3.862.0 + '@aws-sdk/util-endpoints': 3.862.0 + '@aws-sdk/util-user-agent-browser': 3.862.0 + '@aws-sdk/util-user-agent-node': 3.864.0 + '@aws-sdk/xml-builder': 3.862.0 + '@smithy/config-resolver': 4.1.5 + '@smithy/core': 3.8.0 + '@smithy/eventstream-serde-browser': 4.0.5 + '@smithy/eventstream-serde-config-resolver': 4.1.3 + '@smithy/eventstream-serde-node': 4.0.5 + '@smithy/fetch-http-handler': 5.1.1 + '@smithy/hash-blob-browser': 4.0.5 + '@smithy/hash-node': 4.0.5 + '@smithy/hash-stream-node': 4.0.5 + '@smithy/invalid-dependency': 4.0.5 + '@smithy/md5-js': 4.0.5 + '@smithy/middleware-content-length': 4.0.5 + '@smithy/middleware-endpoint': 4.1.18 + '@smithy/middleware-retry': 4.1.19 + '@smithy/middleware-serde': 4.0.9 + '@smithy/middleware-stack': 4.0.5 + '@smithy/node-config-provider': 4.1.4 + '@smithy/node-http-handler': 4.1.1 + '@smithy/protocol-http': 5.1.3 + '@smithy/smithy-client': 4.4.10 + '@smithy/types': 4.3.2 + '@smithy/url-parser': 4.0.5 + '@smithy/util-base64': 4.0.0 + '@smithy/util-body-length-browser': 4.0.0 + '@smithy/util-body-length-node': 4.0.0 + '@smithy/util-defaults-mode-browser': 4.0.26 + '@smithy/util-defaults-mode-node': 4.0.26 + '@smithy/util-endpoints': 3.0.7 + '@smithy/util-middleware': 4.0.5 + '@smithy/util-retry': 4.0.7 + '@smithy/util-stream': 4.2.4 + '@smithy/util-utf8': 4.0.0 + '@smithy/util-waiter': 4.0.7 + '@types/uuid': 9.0.8 + tslib: 2.8.1 + uuid: 9.0.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/client-sqs@3.864.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.864.0 + '@aws-sdk/credential-provider-node': 3.864.0 + '@aws-sdk/middleware-host-header': 3.862.0 + '@aws-sdk/middleware-logger': 3.862.0 + '@aws-sdk/middleware-recursion-detection': 3.862.0 + '@aws-sdk/middleware-sdk-sqs': 3.862.0 + '@aws-sdk/middleware-user-agent': 3.864.0 + '@aws-sdk/region-config-resolver': 3.862.0 + '@aws-sdk/types': 3.862.0 + '@aws-sdk/util-endpoints': 3.862.0 + '@aws-sdk/util-user-agent-browser': 3.862.0 + '@aws-sdk/util-user-agent-node': 3.864.0 + '@smithy/config-resolver': 4.1.5 + '@smithy/core': 3.8.0 + '@smithy/fetch-http-handler': 5.1.1 + '@smithy/hash-node': 4.0.5 + '@smithy/invalid-dependency': 4.0.5 + '@smithy/md5-js': 4.0.5 + '@smithy/middleware-content-length': 4.0.5 + '@smithy/middleware-endpoint': 4.1.18 + '@smithy/middleware-retry': 4.1.19 + '@smithy/middleware-serde': 4.0.9 + '@smithy/middleware-stack': 4.0.5 + '@smithy/node-config-provider': 4.1.4 + '@smithy/node-http-handler': 4.1.1 + '@smithy/protocol-http': 5.1.3 + '@smithy/smithy-client': 4.4.10 + '@smithy/types': 4.3.2 + '@smithy/url-parser': 4.0.5 + '@smithy/util-base64': 4.0.0 + '@smithy/util-body-length-browser': 4.0.0 + '@smithy/util-body-length-node': 4.0.0 + '@smithy/util-defaults-mode-browser': 4.0.26 + '@smithy/util-defaults-mode-node': 4.0.26 + '@smithy/util-endpoints': 3.0.7 + '@smithy/util-middleware': 4.0.5 + '@smithy/util-retry': 4.0.7 + '@smithy/util-utf8': 4.0.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/client-sso@3.398.0': + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/middleware-host-header': 3.398.0 + '@aws-sdk/middleware-logger': 3.398.0 + '@aws-sdk/middleware-recursion-detection': 3.398.0 + '@aws-sdk/middleware-user-agent': 3.398.0 + '@aws-sdk/types': 3.398.0 + '@aws-sdk/util-endpoints': 3.398.0 + '@aws-sdk/util-user-agent-browser': 3.398.0 + '@aws-sdk/util-user-agent-node': 3.398.0 + '@smithy/config-resolver': 2.2.0 + '@smithy/fetch-http-handler': 2.5.0 + '@smithy/hash-node': 2.2.0 + '@smithy/invalid-dependency': 2.2.0 + '@smithy/middleware-content-length': 2.2.0 + '@smithy/middleware-endpoint': 2.5.1 + '@smithy/middleware-retry': 2.3.1 + '@smithy/middleware-serde': 2.3.0 + '@smithy/middleware-stack': 2.2.0 + '@smithy/node-config-provider': 2.3.0 + '@smithy/node-http-handler': 2.5.0 + '@smithy/protocol-http': 2.0.5 + '@smithy/smithy-client': 2.5.1 + '@smithy/types': 2.12.0 + '@smithy/url-parser': 2.2.0 + '@smithy/util-base64': 2.3.0 + '@smithy/util-body-length-browser': 2.2.0 + '@smithy/util-body-length-node': 2.3.0 + '@smithy/util-defaults-mode-browser': 2.2.1 + '@smithy/util-defaults-mode-node': 2.3.1 + '@smithy/util-retry': 2.2.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/client-sso@3.864.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.864.0 + '@aws-sdk/middleware-host-header': 3.862.0 + '@aws-sdk/middleware-logger': 3.862.0 + '@aws-sdk/middleware-recursion-detection': 3.862.0 + '@aws-sdk/middleware-user-agent': 3.864.0 + '@aws-sdk/region-config-resolver': 3.862.0 + '@aws-sdk/types': 3.862.0 + '@aws-sdk/util-endpoints': 3.862.0 + '@aws-sdk/util-user-agent-browser': 3.862.0 + '@aws-sdk/util-user-agent-node': 3.864.0 + '@smithy/config-resolver': 4.1.5 + '@smithy/core': 3.8.0 + '@smithy/fetch-http-handler': 5.1.1 + '@smithy/hash-node': 4.0.5 + '@smithy/invalid-dependency': 4.0.5 + '@smithy/middleware-content-length': 4.0.5 + '@smithy/middleware-endpoint': 4.1.18 + '@smithy/middleware-retry': 4.1.19 + '@smithy/middleware-serde': 4.0.9 + '@smithy/middleware-stack': 4.0.5 + '@smithy/node-config-provider': 4.1.4 + '@smithy/node-http-handler': 4.1.1 + '@smithy/protocol-http': 5.1.3 + '@smithy/smithy-client': 4.4.10 + '@smithy/types': 4.3.2 + '@smithy/url-parser': 4.0.5 + '@smithy/util-base64': 4.0.0 + '@smithy/util-body-length-browser': 4.0.0 + '@smithy/util-body-length-node': 4.0.0 + '@smithy/util-defaults-mode-browser': 4.0.26 + '@smithy/util-defaults-mode-node': 4.0.26 + '@smithy/util-endpoints': 3.0.7 + '@smithy/util-middleware': 4.0.5 + '@smithy/util-retry': 4.0.7 + '@smithy/util-utf8': 4.0.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/client-sts@3.398.0': + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/credential-provider-node': 3.398.0 + '@aws-sdk/middleware-host-header': 3.398.0 + '@aws-sdk/middleware-logger': 3.398.0 + '@aws-sdk/middleware-recursion-detection': 3.398.0 + '@aws-sdk/middleware-sdk-sts': 3.398.0 + '@aws-sdk/middleware-signing': 3.398.0 + '@aws-sdk/middleware-user-agent': 3.398.0 + '@aws-sdk/types': 3.398.0 + '@aws-sdk/util-endpoints': 3.398.0 + '@aws-sdk/util-user-agent-browser': 3.398.0 + '@aws-sdk/util-user-agent-node': 3.398.0 + '@smithy/config-resolver': 2.2.0 + '@smithy/fetch-http-handler': 2.5.0 + '@smithy/hash-node': 2.2.0 + '@smithy/invalid-dependency': 2.2.0 + '@smithy/middleware-content-length': 2.2.0 + '@smithy/middleware-endpoint': 2.5.1 + '@smithy/middleware-retry': 2.3.1 + '@smithy/middleware-serde': 2.3.0 + '@smithy/middleware-stack': 2.2.0 + '@smithy/node-config-provider': 2.3.0 + '@smithy/node-http-handler': 2.5.0 + '@smithy/protocol-http': 2.0.5 + '@smithy/smithy-client': 2.5.1 + '@smithy/types': 2.12.0 + '@smithy/url-parser': 2.2.0 + '@smithy/util-base64': 2.3.0 + '@smithy/util-body-length-browser': 2.2.0 + '@smithy/util-body-length-node': 2.3.0 + '@smithy/util-defaults-mode-browser': 2.2.1 + '@smithy/util-defaults-mode-node': 2.3.1 + '@smithy/util-retry': 2.2.0 + '@smithy/util-utf8': 2.3.0 + fast-xml-parser: 4.2.5 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/core@3.864.0': + dependencies: + '@aws-sdk/types': 3.862.0 + '@aws-sdk/xml-builder': 3.862.0 + '@smithy/core': 3.8.0 + '@smithy/node-config-provider': 4.1.4 + '@smithy/property-provider': 4.0.5 + '@smithy/protocol-http': 5.1.3 + '@smithy/signature-v4': 5.1.3 + '@smithy/smithy-client': 4.4.10 + '@smithy/types': 4.3.2 + '@smithy/util-base64': 4.0.0 + '@smithy/util-body-length-browser': 4.0.0 + '@smithy/util-middleware': 4.0.5 + '@smithy/util-utf8': 4.0.0 + fast-xml-parser: 5.2.5 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-env@3.398.0': + dependencies: + '@aws-sdk/types': 3.398.0 + '@smithy/property-provider': 2.2.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-env@3.864.0': + dependencies: + '@aws-sdk/core': 3.864.0 + '@aws-sdk/types': 3.862.0 + '@smithy/property-provider': 4.0.5 + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-http@3.864.0': + dependencies: + '@aws-sdk/core': 3.864.0 + '@aws-sdk/types': 3.862.0 + '@smithy/fetch-http-handler': 5.1.1 + '@smithy/node-http-handler': 4.1.1 + '@smithy/property-provider': 4.0.5 + '@smithy/protocol-http': 5.1.3 + '@smithy/smithy-client': 4.4.10 + '@smithy/types': 4.3.2 + '@smithy/util-stream': 4.2.4 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-ini@3.398.0': + dependencies: + '@aws-sdk/credential-provider-env': 3.398.0 + '@aws-sdk/credential-provider-process': 3.398.0 + '@aws-sdk/credential-provider-sso': 3.398.0 + '@aws-sdk/credential-provider-web-identity': 3.398.0 + '@aws-sdk/types': 3.398.0 + '@smithy/credential-provider-imds': 2.3.0 + '@smithy/property-provider': 2.2.0 + '@smithy/shared-ini-file-loader': 2.4.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-provider-ini@3.864.0': + dependencies: + '@aws-sdk/core': 3.864.0 + '@aws-sdk/credential-provider-env': 3.864.0 + '@aws-sdk/credential-provider-http': 3.864.0 + '@aws-sdk/credential-provider-process': 3.864.0 + '@aws-sdk/credential-provider-sso': 3.864.0 + '@aws-sdk/credential-provider-web-identity': 3.864.0 + '@aws-sdk/nested-clients': 3.864.0 + '@aws-sdk/types': 3.862.0 + '@smithy/credential-provider-imds': 4.0.7 + '@smithy/property-provider': 4.0.5 + '@smithy/shared-ini-file-loader': 4.0.5 + '@smithy/types': 4.3.2 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-provider-node@3.398.0': + dependencies: + '@aws-sdk/credential-provider-env': 3.398.0 + '@aws-sdk/credential-provider-ini': 3.398.0 + '@aws-sdk/credential-provider-process': 3.398.0 + '@aws-sdk/credential-provider-sso': 3.398.0 + '@aws-sdk/credential-provider-web-identity': 3.398.0 + '@aws-sdk/types': 3.398.0 + '@smithy/credential-provider-imds': 2.3.0 + '@smithy/property-provider': 2.2.0 + '@smithy/shared-ini-file-loader': 2.4.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-provider-node@3.864.0': + dependencies: + '@aws-sdk/credential-provider-env': 3.864.0 + '@aws-sdk/credential-provider-http': 3.864.0 + '@aws-sdk/credential-provider-ini': 3.864.0 + '@aws-sdk/credential-provider-process': 3.864.0 + '@aws-sdk/credential-provider-sso': 3.864.0 + '@aws-sdk/credential-provider-web-identity': 3.864.0 + '@aws-sdk/types': 3.862.0 + '@smithy/credential-provider-imds': 4.0.7 + '@smithy/property-provider': 4.0.5 + '@smithy/shared-ini-file-loader': 4.0.5 + '@smithy/types': 4.3.2 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-provider-process@3.398.0': + dependencies: + '@aws-sdk/types': 3.398.0 + '@smithy/property-provider': 2.2.0 + '@smithy/shared-ini-file-loader': 2.4.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-process@3.864.0': + dependencies: + '@aws-sdk/core': 3.864.0 + '@aws-sdk/types': 3.862.0 + '@smithy/property-provider': 4.0.5 + '@smithy/shared-ini-file-loader': 4.0.5 + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-sso@3.398.0': + dependencies: + '@aws-sdk/client-sso': 3.398.0 + '@aws-sdk/token-providers': 3.398.0 + '@aws-sdk/types': 3.398.0 + '@smithy/property-provider': 2.2.0 + '@smithy/shared-ini-file-loader': 2.4.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-provider-sso@3.864.0': + dependencies: + '@aws-sdk/client-sso': 3.864.0 + '@aws-sdk/core': 3.864.0 + '@aws-sdk/token-providers': 3.864.0 + '@aws-sdk/types': 3.862.0 + '@smithy/property-provider': 4.0.5 + '@smithy/shared-ini-file-loader': 4.0.5 + '@smithy/types': 4.3.2 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-provider-web-identity@3.398.0': + dependencies: + '@aws-sdk/types': 3.398.0 + '@smithy/property-provider': 2.2.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-web-identity@3.864.0': + dependencies: + '@aws-sdk/core': 3.864.0 + '@aws-sdk/nested-clients': 3.864.0 + '@aws-sdk/types': 3.862.0 + '@smithy/property-provider': 4.0.5 + '@smithy/types': 4.3.2 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/endpoint-cache@3.804.0': + dependencies: + mnemonist: 0.38.3 + tslib: 2.8.1 + + '@aws-sdk/middleware-bucket-endpoint@3.862.0': + dependencies: + '@aws-sdk/types': 3.862.0 + '@aws-sdk/util-arn-parser': 3.804.0 + '@smithy/node-config-provider': 4.1.4 + '@smithy/protocol-http': 5.1.3 + '@smithy/types': 4.3.2 + '@smithy/util-config-provider': 4.0.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-endpoint-discovery@3.862.0': + dependencies: + '@aws-sdk/endpoint-cache': 3.804.0 + '@aws-sdk/types': 3.862.0 + '@smithy/node-config-provider': 4.1.4 + '@smithy/protocol-http': 5.1.3 + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@aws-sdk/middleware-expect-continue@3.862.0': + dependencies: + '@aws-sdk/types': 3.862.0 + '@smithy/protocol-http': 5.1.3 + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@aws-sdk/middleware-flexible-checksums@3.864.0': + dependencies: + '@aws-crypto/crc32': 5.2.0 + '@aws-crypto/crc32c': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/core': 3.864.0 + '@aws-sdk/types': 3.862.0 + '@smithy/is-array-buffer': 4.0.0 + '@smithy/node-config-provider': 4.1.4 + '@smithy/protocol-http': 5.1.3 + '@smithy/types': 4.3.2 + '@smithy/util-middleware': 4.0.5 + '@smithy/util-stream': 4.2.4 + '@smithy/util-utf8': 4.0.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-host-header@3.398.0': + dependencies: + '@aws-sdk/types': 3.398.0 + '@smithy/protocol-http': 2.0.5 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-host-header@3.862.0': + dependencies: + '@aws-sdk/types': 3.862.0 + '@smithy/protocol-http': 5.1.3 + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@aws-sdk/middleware-location-constraint@3.862.0': + dependencies: + '@aws-sdk/types': 3.862.0 + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@aws-sdk/middleware-logger@3.398.0': + dependencies: + '@aws-sdk/types': 3.398.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-logger@3.862.0': + dependencies: + '@aws-sdk/types': 3.862.0 + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@aws-sdk/middleware-recursion-detection@3.398.0': + dependencies: + '@aws-sdk/types': 3.398.0 + '@smithy/protocol-http': 2.0.5 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-recursion-detection@3.862.0': + dependencies: + '@aws-sdk/types': 3.862.0 + '@smithy/protocol-http': 5.1.3 + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@aws-sdk/middleware-sdk-s3@3.864.0': + dependencies: + '@aws-sdk/core': 3.864.0 + '@aws-sdk/types': 3.862.0 + '@aws-sdk/util-arn-parser': 3.804.0 + '@smithy/core': 3.8.0 + '@smithy/node-config-provider': 4.1.4 + '@smithy/protocol-http': 5.1.3 + '@smithy/signature-v4': 5.1.3 + '@smithy/smithy-client': 4.4.10 + '@smithy/types': 4.3.2 + '@smithy/util-config-provider': 4.0.0 + '@smithy/util-middleware': 4.0.5 + '@smithy/util-stream': 4.2.4 + '@smithy/util-utf8': 4.0.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-sdk-sqs@3.862.0': + dependencies: + '@aws-sdk/types': 3.862.0 + '@smithy/smithy-client': 4.4.10 + '@smithy/types': 4.3.2 + '@smithy/util-hex-encoding': 4.0.0 + '@smithy/util-utf8': 4.0.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-sdk-sts@3.398.0': + dependencies: + '@aws-sdk/middleware-signing': 3.398.0 + '@aws-sdk/types': 3.398.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-signing@3.398.0': + dependencies: + '@aws-sdk/types': 3.398.0 + '@smithy/property-provider': 2.2.0 + '@smithy/protocol-http': 2.0.5 + '@smithy/signature-v4': 2.3.0 + '@smithy/types': 2.12.0 + '@smithy/util-middleware': 2.2.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-ssec@3.862.0': + dependencies: + '@aws-sdk/types': 3.862.0 + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@aws-sdk/middleware-user-agent@3.398.0': + dependencies: + '@aws-sdk/types': 3.398.0 + '@aws-sdk/util-endpoints': 3.398.0 + '@smithy/protocol-http': 2.0.5 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-user-agent@3.864.0': + dependencies: + '@aws-sdk/core': 3.864.0 + '@aws-sdk/types': 3.862.0 + '@aws-sdk/util-endpoints': 3.862.0 + '@smithy/core': 3.8.0 + '@smithy/protocol-http': 5.1.3 + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@aws-sdk/nested-clients@3.864.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.864.0 + '@aws-sdk/middleware-host-header': 3.862.0 + '@aws-sdk/middleware-logger': 3.862.0 + '@aws-sdk/middleware-recursion-detection': 3.862.0 + '@aws-sdk/middleware-user-agent': 3.864.0 + '@aws-sdk/region-config-resolver': 3.862.0 + '@aws-sdk/types': 3.862.0 + '@aws-sdk/util-endpoints': 3.862.0 + '@aws-sdk/util-user-agent-browser': 3.862.0 + '@aws-sdk/util-user-agent-node': 3.864.0 + '@smithy/config-resolver': 4.1.5 + '@smithy/core': 3.8.0 + '@smithy/fetch-http-handler': 5.1.1 + '@smithy/hash-node': 4.0.5 + '@smithy/invalid-dependency': 4.0.5 + '@smithy/middleware-content-length': 4.0.5 + '@smithy/middleware-endpoint': 4.1.18 + '@smithy/middleware-retry': 4.1.19 + '@smithy/middleware-serde': 4.0.9 + '@smithy/middleware-stack': 4.0.5 + '@smithy/node-config-provider': 4.1.4 + '@smithy/node-http-handler': 4.1.1 + '@smithy/protocol-http': 5.1.3 + '@smithy/smithy-client': 4.4.10 + '@smithy/types': 4.3.2 + '@smithy/url-parser': 4.0.5 + '@smithy/util-base64': 4.0.0 + '@smithy/util-body-length-browser': 4.0.0 + '@smithy/util-body-length-node': 4.0.0 + '@smithy/util-defaults-mode-browser': 4.0.26 + '@smithy/util-defaults-mode-node': 4.0.26 + '@smithy/util-endpoints': 3.0.7 + '@smithy/util-middleware': 4.0.5 + '@smithy/util-retry': 4.0.7 + '@smithy/util-utf8': 4.0.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/region-config-resolver@3.862.0': + dependencies: + '@aws-sdk/types': 3.862.0 + '@smithy/node-config-provider': 4.1.4 + '@smithy/types': 4.3.2 + '@smithy/util-config-provider': 4.0.0 + '@smithy/util-middleware': 4.0.5 + tslib: 2.8.1 + + '@aws-sdk/signature-v4-multi-region@3.864.0': + dependencies: + '@aws-sdk/middleware-sdk-s3': 3.864.0 + '@aws-sdk/types': 3.862.0 + '@smithy/protocol-http': 5.1.3 + '@smithy/signature-v4': 5.1.3 + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@aws-sdk/token-providers@3.398.0': + dependencies: + '@aws-crypto/sha256-browser': 3.0.0 + '@aws-crypto/sha256-js': 3.0.0 + '@aws-sdk/middleware-host-header': 3.398.0 + '@aws-sdk/middleware-logger': 3.398.0 + '@aws-sdk/middleware-recursion-detection': 3.398.0 + '@aws-sdk/middleware-user-agent': 3.398.0 + '@aws-sdk/types': 3.398.0 + '@aws-sdk/util-endpoints': 3.398.0 + '@aws-sdk/util-user-agent-browser': 3.398.0 + '@aws-sdk/util-user-agent-node': 3.398.0 + '@smithy/config-resolver': 2.2.0 + '@smithy/fetch-http-handler': 2.5.0 + '@smithy/hash-node': 2.2.0 + '@smithy/invalid-dependency': 2.2.0 + '@smithy/middleware-content-length': 2.2.0 + '@smithy/middleware-endpoint': 2.5.1 + '@smithy/middleware-retry': 2.3.1 + '@smithy/middleware-serde': 2.3.0 + '@smithy/middleware-stack': 2.2.0 + '@smithy/node-config-provider': 2.3.0 + '@smithy/node-http-handler': 2.5.0 + '@smithy/property-provider': 2.2.0 + '@smithy/protocol-http': 2.0.5 + '@smithy/shared-ini-file-loader': 2.4.0 + '@smithy/smithy-client': 2.5.1 + '@smithy/types': 2.12.0 + '@smithy/url-parser': 2.2.0 + '@smithy/util-base64': 2.3.0 + '@smithy/util-body-length-browser': 2.2.0 + '@smithy/util-body-length-node': 2.3.0 + '@smithy/util-defaults-mode-browser': 2.2.1 + '@smithy/util-defaults-mode-node': 2.3.1 + '@smithy/util-retry': 2.2.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/token-providers@3.864.0': + dependencies: + '@aws-sdk/core': 3.864.0 + '@aws-sdk/nested-clients': 3.864.0 + '@aws-sdk/types': 3.862.0 + '@smithy/property-provider': 4.0.5 + '@smithy/shared-ini-file-loader': 4.0.5 + '@smithy/types': 4.3.2 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/types@3.398.0': + dependencies: + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@aws-sdk/types@3.862.0': + dependencies: + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@aws-sdk/util-arn-parser@3.804.0': + dependencies: + tslib: 2.8.1 + + '@aws-sdk/util-endpoints@3.398.0': + dependencies: + '@aws-sdk/types': 3.398.0 + tslib: 2.8.1 + + '@aws-sdk/util-endpoints@3.862.0': + dependencies: + '@aws-sdk/types': 3.862.0 + '@smithy/types': 4.3.2 + '@smithy/url-parser': 4.0.5 + '@smithy/util-endpoints': 3.0.7 + tslib: 2.8.1 + + '@aws-sdk/util-locate-window@3.804.0': + dependencies: + tslib: 2.8.1 + + '@aws-sdk/util-user-agent-browser@3.398.0': + dependencies: + '@aws-sdk/types': 3.398.0 + '@smithy/types': 2.12.0 + bowser: 2.12.0 + tslib: 2.8.1 + + '@aws-sdk/util-user-agent-browser@3.862.0': + dependencies: + '@aws-sdk/types': 3.862.0 + '@smithy/types': 4.3.2 + bowser: 2.12.0 + tslib: 2.8.1 + + '@aws-sdk/util-user-agent-node@3.398.0': + dependencies: + '@aws-sdk/types': 3.398.0 + '@smithy/node-config-provider': 2.3.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@aws-sdk/util-user-agent-node@3.864.0': + dependencies: + '@aws-sdk/middleware-user-agent': 3.864.0 + '@aws-sdk/types': 3.862.0 + '@smithy/node-config-provider': 4.1.4 + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@aws-sdk/util-utf8-browser@3.259.0': + dependencies: + tslib: 2.8.1 + + '@aws-sdk/xml-builder@3.310.0': + dependencies: + tslib: 2.8.1 + + '@aws-sdk/xml-builder@3.862.0': + dependencies: + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@babel/code-frame@7.27.1': + dependencies: + '@babel/helper-validator-identifier': 7.27.1 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.27.5': {} + + '@babel/core@7.27.4': + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.27.5 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.27.3(@babel/core@7.27.4) + '@babel/helpers': 7.27.4 + '@babel/parser': 7.28.0 + '@babel/template': 7.27.2 + '@babel/traverse': 7.27.4 + '@babel/types': 7.28.0 + convert-source-map: 2.0.0 + debug: 4.4.1 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.27.5': + dependencies: + '@babel/parser': 7.28.0 + '@babel/types': 7.28.0 + '@jridgewell/gen-mapping': 0.3.12 + '@jridgewell/trace-mapping': 0.3.29 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.27.2': + dependencies: + '@babel/compat-data': 7.27.5 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.25.0 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-module-imports@7.27.1': + dependencies: + '@babel/traverse': 7.27.4 + '@babel/types': 7.28.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.27.3(@babel/core@7.27.4)': + dependencies: + '@babel/core': 7.27.4 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@babel/traverse': 7.27.4 + transitivePeerDependencies: + - supports-color '@babel/helper-plugin-utils@7.24.7': {} @@ -8132,9 +10512,9 @@ snapshots: '@typescript-eslint/parser': 8.28.0(eslint@8.57.1)(typescript@5.8.3) eslint: 8.57.1 eslint-config-prettier: 9.1.0(eslint@8.57.1) - eslint-import-resolver-typescript: 3.9.1(eslint-plugin-import@2.31.0)(eslint@8.57.1) + eslint-import-resolver-typescript: 3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1) eslint-plugin-gettext: 1.2.0 - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1)(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) eslint-plugin-jest: 28.11.0(@typescript-eslint/eslint-plugin@8.28.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1)(jest@29.7.0(@types/node@22.15.30)(ts-node@10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3)))(typescript@5.8.3) eslint-plugin-jest-dom: 5.5.0(eslint@8.57.1) eslint-plugin-jest-formatting: 3.1.0(eslint@8.57.1) @@ -8333,6 +10713,31 @@ snapshots: human-id: 4.1.1 prettier: 2.8.8 + '@cloudflare/kv-asset-handler@0.4.0': + dependencies: + mime: 3.0.0 + + '@cloudflare/unenv-preset@2.6.2(unenv@2.0.0-rc.19)(workerd@1.20250816.0)': + dependencies: + unenv: 2.0.0-rc.19 + optionalDependencies: + workerd: 1.20250816.0 + + '@cloudflare/workerd-darwin-64@1.20250816.0': + optional: true + + '@cloudflare/workerd-darwin-arm64@1.20250816.0': + optional: true + + '@cloudflare/workerd-linux-64@1.20250816.0': + optional: true + + '@cloudflare/workerd-linux-arm64@1.20250816.0': + optional: true + + '@cloudflare/workerd-windows-64@1.20250816.0': + optional: true + '@commander-js/extra-typings@14.0.0(commander@14.0.0)': dependencies: commander: 14.0.0 @@ -8352,7 +10757,6 @@ snapshots: '@cspotcode/source-map-support@0.8.1': dependencies: '@jridgewell/trace-mapping': 0.3.9 - optional: true '@csstools/cascade-layer-name-parser@2.0.5(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': dependencies: @@ -8619,6 +11023,22 @@ snapshots: '@discoveryjs/json-ext@0.5.7': {} + '@dotenvx/dotenvx@1.31.0': + dependencies: + commander: 11.1.0 + dotenv: 16.5.0 + eciesjs: 0.4.15 + execa: 5.1.1 + fdir: 6.4.6(picomatch@4.0.2) + ignore: 5.3.2 + object-treeify: 1.1.33 + picomatch: 4.0.2 + which: 4.0.0 + + '@ecies/ciphers@0.2.4(@noble/ciphers@1.3.0)': + dependencies: + '@noble/ciphers': 1.3.0 + '@emnapi/core@1.3.1': dependencies: '@emnapi/wasi-threads': 1.0.1 @@ -8646,81 +11066,156 @@ snapshots: esquery: 1.6.0 jsdoc-type-pratt-parser: 4.1.0 + '@esbuild/aix-ppc64@0.25.4': + optional: true + '@esbuild/aix-ppc64@0.25.6': optional: true + '@esbuild/android-arm64@0.25.4': + optional: true + '@esbuild/android-arm64@0.25.6': optional: true + '@esbuild/android-arm@0.25.4': + optional: true + '@esbuild/android-arm@0.25.6': optional: true + '@esbuild/android-x64@0.25.4': + optional: true + '@esbuild/android-x64@0.25.6': optional: true + '@esbuild/darwin-arm64@0.25.4': + optional: true + '@esbuild/darwin-arm64@0.25.6': optional: true + '@esbuild/darwin-x64@0.25.4': + optional: true + '@esbuild/darwin-x64@0.25.6': optional: true + '@esbuild/freebsd-arm64@0.25.4': + optional: true + '@esbuild/freebsd-arm64@0.25.6': optional: true + '@esbuild/freebsd-x64@0.25.4': + optional: true + '@esbuild/freebsd-x64@0.25.6': optional: true + '@esbuild/linux-arm64@0.25.4': + optional: true + '@esbuild/linux-arm64@0.25.6': optional: true + '@esbuild/linux-arm@0.25.4': + optional: true + '@esbuild/linux-arm@0.25.6': optional: true + '@esbuild/linux-ia32@0.25.4': + optional: true + '@esbuild/linux-ia32@0.25.6': optional: true + '@esbuild/linux-loong64@0.25.4': + optional: true + '@esbuild/linux-loong64@0.25.6': optional: true + '@esbuild/linux-mips64el@0.25.4': + optional: true + '@esbuild/linux-mips64el@0.25.6': optional: true + '@esbuild/linux-ppc64@0.25.4': + optional: true + '@esbuild/linux-ppc64@0.25.6': optional: true + '@esbuild/linux-riscv64@0.25.4': + optional: true + '@esbuild/linux-riscv64@0.25.6': optional: true + '@esbuild/linux-s390x@0.25.4': + optional: true + '@esbuild/linux-s390x@0.25.6': optional: true + '@esbuild/linux-x64@0.25.4': + optional: true + '@esbuild/linux-x64@0.25.6': optional: true + '@esbuild/netbsd-arm64@0.25.4': + optional: true + '@esbuild/netbsd-arm64@0.25.6': optional: true + '@esbuild/netbsd-x64@0.25.4': + optional: true + '@esbuild/netbsd-x64@0.25.6': optional: true + '@esbuild/openbsd-arm64@0.25.4': + optional: true + '@esbuild/openbsd-arm64@0.25.6': optional: true + '@esbuild/openbsd-x64@0.25.4': + optional: true + '@esbuild/openbsd-x64@0.25.6': optional: true '@esbuild/openharmony-arm64@0.25.6': optional: true + '@esbuild/sunos-x64@0.25.4': + optional: true + '@esbuild/sunos-x64@0.25.6': optional: true + '@esbuild/win32-arm64@0.25.4': + optional: true + '@esbuild/win32-arm64@0.25.6': optional: true + '@esbuild/win32-ia32@0.25.4': + optional: true + '@esbuild/win32-ia32@0.25.6': optional: true + '@esbuild/win32-x64@0.25.4': + optional: true + '@esbuild/win32-x64@0.25.6': optional: true @@ -9109,6 +11604,12 @@ snapshots: optionalDependencies: '@types/node': 22.15.30 + '@isaacs/balanced-match@4.0.1': {} + + '@isaacs/brace-expansion@5.0.0': + dependencies: + '@isaacs/balanced-match': 4.0.1 + '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -9301,6 +11802,11 @@ snapshots: '@jridgewell/resolve-uri@3.1.2': {} + '@jridgewell/source-map@0.3.11': + dependencies: + '@jridgewell/gen-mapping': 0.3.12 + '@jridgewell/trace-mapping': 0.3.29 + '@jridgewell/sourcemap-codec@1.5.4': {} '@jridgewell/trace-mapping@0.3.29': @@ -9312,7 +11818,6 @@ snapshots: dependencies: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.4 - optional: true '@lhci/utils@0.14.0(encoding@0.1.13)': dependencies: @@ -9407,6 +11912,29 @@ snapshots: '@next/swc-win32-x64-msvc@15.4.2-canary.10': optional: true + '@noble/ciphers@1.3.0': {} + + '@noble/curves@1.9.7': + dependencies: + '@noble/hashes': 1.8.0 + + '@noble/hashes@1.8.0': {} + + '@node-minify/core@8.0.6': + dependencies: + '@node-minify/utils': 8.0.6 + glob: 9.3.5 + mkdirp: 1.0.4 + + '@node-minify/terser@8.0.6': + dependencies: + '@node-minify/utils': 8.0.6 + terser: 5.16.9 + + '@node-minify/utils@8.0.6': + dependencies: + gzip-size: 6.0.0 + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -9430,6 +11958,44 @@ snapshots: '@open-draft/until@2.1.0': {} + '@opennextjs/aws@3.7.4': + dependencies: + '@ast-grep/napi': 0.35.0 + '@aws-sdk/client-cloudfront': 3.398.0 + '@aws-sdk/client-dynamodb': 3.868.0 + '@aws-sdk/client-lambda': 3.865.0 + '@aws-sdk/client-s3': 3.864.0 + '@aws-sdk/client-sqs': 3.864.0 + '@node-minify/core': 8.0.6 + '@node-minify/terser': 8.0.6 + '@tsconfig/node18': 1.0.3 + aws4fetch: 1.0.20 + chalk: 5.4.1 + cookie: 1.0.2 + esbuild: 0.25.4 + express: 5.0.1 + path-to-regexp: 6.3.0 + urlpattern-polyfill: 10.0.0 + yaml: 2.8.1 + transitivePeerDependencies: + - aws-crt + - supports-color + + '@opennextjs/cloudflare@1.6.5(encoding@0.1.13)(wrangler@4.31.0)': + dependencies: + '@dotenvx/dotenvx': 1.31.0 + '@opennextjs/aws': 3.7.4 + cloudflare: 4.5.0(encoding@0.1.13) + enquirer: 2.4.1 + glob: 11.0.3 + ts-tqdm: 0.8.6 + wrangler: 4.31.0 + yargs: 18.0.0 + transitivePeerDependencies: + - aws-crt + - encoding + - supports-color + '@panva/hkdf@1.2.1': {} '@parcel/watcher-android-arm64@2.5.1': @@ -9517,6 +12083,18 @@ snapshots: '@polka/url@1.0.0-next.29': {} + '@poppinss/colors@4.1.5': + dependencies: + kleur: 4.1.5 + + '@poppinss/dumper@0.6.4': + dependencies: + '@poppinss/colors': 4.1.5 + '@sindresorhus/is': 7.0.2 + supports-color: 10.2.0 + + '@poppinss/exception@1.2.2': {} + '@puppeteer/browsers@2.10.5': dependencies: debug: 4.4.1 @@ -10205,25 +12783,595 @@ snapshots: '@sentry/types': 6.19.7 tslib: 1.14.1 - '@sentry/utils@7.120.3': + '@sentry/utils@7.120.3': + dependencies: + '@sentry/types': 7.120.3 + + '@sinclair/typebox@0.27.8': {} + + '@sindresorhus/is@4.6.0': {} + + '@sindresorhus/is@7.0.2': {} + + '@sindresorhus/merge-streams@2.3.0': {} + + '@sindresorhus/merge-streams@4.0.0': {} + + '@sinonjs/commons@3.0.1': + dependencies: + type-detect: 4.0.8 + + '@sinonjs/fake-timers@10.3.0': + dependencies: + '@sinonjs/commons': 3.0.1 + + '@smithy/abort-controller@2.2.0': + dependencies: + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@smithy/abort-controller@4.0.5': + dependencies: + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@smithy/chunked-blob-reader-native@4.0.0': + dependencies: + '@smithy/util-base64': 4.0.0 + tslib: 2.8.1 + + '@smithy/chunked-blob-reader@5.0.0': + dependencies: + tslib: 2.8.1 + + '@smithy/config-resolver@2.2.0': + dependencies: + '@smithy/node-config-provider': 2.3.0 + '@smithy/types': 2.12.0 + '@smithy/util-config-provider': 2.3.0 + '@smithy/util-middleware': 2.2.0 + tslib: 2.8.1 + + '@smithy/config-resolver@4.1.5': + dependencies: + '@smithy/node-config-provider': 4.1.4 + '@smithy/types': 4.3.2 + '@smithy/util-config-provider': 4.0.0 + '@smithy/util-middleware': 4.0.5 + tslib: 2.8.1 + + '@smithy/core@3.8.0': + dependencies: + '@smithy/middleware-serde': 4.0.9 + '@smithy/protocol-http': 5.1.3 + '@smithy/types': 4.3.2 + '@smithy/util-base64': 4.0.0 + '@smithy/util-body-length-browser': 4.0.0 + '@smithy/util-middleware': 4.0.5 + '@smithy/util-stream': 4.2.4 + '@smithy/util-utf8': 4.0.0 + '@types/uuid': 9.0.8 + tslib: 2.8.1 + uuid: 9.0.1 + + '@smithy/credential-provider-imds@2.3.0': + dependencies: + '@smithy/node-config-provider': 2.3.0 + '@smithy/property-provider': 2.2.0 + '@smithy/types': 2.12.0 + '@smithy/url-parser': 2.2.0 + tslib: 2.8.1 + + '@smithy/credential-provider-imds@4.0.7': + dependencies: + '@smithy/node-config-provider': 4.1.4 + '@smithy/property-provider': 4.0.5 + '@smithy/types': 4.3.2 + '@smithy/url-parser': 4.0.5 + tslib: 2.8.1 + + '@smithy/eventstream-codec@4.0.5': + dependencies: + '@aws-crypto/crc32': 5.2.0 + '@smithy/types': 4.3.2 + '@smithy/util-hex-encoding': 4.0.0 + tslib: 2.8.1 + + '@smithy/eventstream-serde-browser@4.0.5': + dependencies: + '@smithy/eventstream-serde-universal': 4.0.5 + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@smithy/eventstream-serde-config-resolver@4.1.3': + dependencies: + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@smithy/eventstream-serde-node@4.0.5': + dependencies: + '@smithy/eventstream-serde-universal': 4.0.5 + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@smithy/eventstream-serde-universal@4.0.5': + dependencies: + '@smithy/eventstream-codec': 4.0.5 + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@smithy/fetch-http-handler@2.5.0': + dependencies: + '@smithy/protocol-http': 3.3.0 + '@smithy/querystring-builder': 2.2.0 + '@smithy/types': 2.12.0 + '@smithy/util-base64': 2.3.0 + tslib: 2.8.1 + + '@smithy/fetch-http-handler@5.1.1': + dependencies: + '@smithy/protocol-http': 5.1.3 + '@smithy/querystring-builder': 4.0.5 + '@smithy/types': 4.3.2 + '@smithy/util-base64': 4.0.0 + tslib: 2.8.1 + + '@smithy/hash-blob-browser@4.0.5': + dependencies: + '@smithy/chunked-blob-reader': 5.0.0 + '@smithy/chunked-blob-reader-native': 4.0.0 + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@smithy/hash-node@2.2.0': + dependencies: + '@smithy/types': 2.12.0 + '@smithy/util-buffer-from': 2.2.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@smithy/hash-node@4.0.5': + dependencies: + '@smithy/types': 4.3.2 + '@smithy/util-buffer-from': 4.0.0 + '@smithy/util-utf8': 4.0.0 + tslib: 2.8.1 + + '@smithy/hash-stream-node@4.0.5': + dependencies: + '@smithy/types': 4.3.2 + '@smithy/util-utf8': 4.0.0 + tslib: 2.8.1 + + '@smithy/invalid-dependency@2.2.0': + dependencies: + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@smithy/invalid-dependency@4.0.5': + dependencies: + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@smithy/is-array-buffer@2.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/is-array-buffer@4.0.0': + dependencies: + tslib: 2.8.1 + + '@smithy/md5-js@4.0.5': + dependencies: + '@smithy/types': 4.3.2 + '@smithy/util-utf8': 4.0.0 + tslib: 2.8.1 + + '@smithy/middleware-content-length@2.2.0': + dependencies: + '@smithy/protocol-http': 3.3.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@smithy/middleware-content-length@4.0.5': + dependencies: + '@smithy/protocol-http': 5.1.3 + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@smithy/middleware-endpoint@2.5.1': + dependencies: + '@smithy/middleware-serde': 2.3.0 + '@smithy/node-config-provider': 2.3.0 + '@smithy/shared-ini-file-loader': 2.4.0 + '@smithy/types': 2.12.0 + '@smithy/url-parser': 2.2.0 + '@smithy/util-middleware': 2.2.0 + tslib: 2.8.1 + + '@smithy/middleware-endpoint@4.1.18': + dependencies: + '@smithy/core': 3.8.0 + '@smithy/middleware-serde': 4.0.9 + '@smithy/node-config-provider': 4.1.4 + '@smithy/shared-ini-file-loader': 4.0.5 + '@smithy/types': 4.3.2 + '@smithy/url-parser': 4.0.5 + '@smithy/util-middleware': 4.0.5 + tslib: 2.8.1 + + '@smithy/middleware-retry@2.3.1': + dependencies: + '@smithy/node-config-provider': 2.3.0 + '@smithy/protocol-http': 3.3.0 + '@smithy/service-error-classification': 2.1.5 + '@smithy/smithy-client': 2.5.1 + '@smithy/types': 2.12.0 + '@smithy/util-middleware': 2.2.0 + '@smithy/util-retry': 2.2.0 + tslib: 2.8.1 + uuid: 9.0.1 + + '@smithy/middleware-retry@4.1.19': + dependencies: + '@smithy/node-config-provider': 4.1.4 + '@smithy/protocol-http': 5.1.3 + '@smithy/service-error-classification': 4.0.7 + '@smithy/smithy-client': 4.4.10 + '@smithy/types': 4.3.2 + '@smithy/util-middleware': 4.0.5 + '@smithy/util-retry': 4.0.7 + '@types/uuid': 9.0.8 + tslib: 2.8.1 + uuid: 9.0.1 + + '@smithy/middleware-serde@2.3.0': + dependencies: + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@smithy/middleware-serde@4.0.9': + dependencies: + '@smithy/protocol-http': 5.1.3 + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@smithy/middleware-stack@2.2.0': + dependencies: + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@smithy/middleware-stack@4.0.5': + dependencies: + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@smithy/node-config-provider@2.3.0': + dependencies: + '@smithy/property-provider': 2.2.0 + '@smithy/shared-ini-file-loader': 2.4.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@smithy/node-config-provider@4.1.4': + dependencies: + '@smithy/property-provider': 4.0.5 + '@smithy/shared-ini-file-loader': 4.0.5 + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@smithy/node-http-handler@2.5.0': + dependencies: + '@smithy/abort-controller': 2.2.0 + '@smithy/protocol-http': 3.3.0 + '@smithy/querystring-builder': 2.2.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@smithy/node-http-handler@4.1.1': + dependencies: + '@smithy/abort-controller': 4.0.5 + '@smithy/protocol-http': 5.1.3 + '@smithy/querystring-builder': 4.0.5 + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@smithy/property-provider@2.2.0': + dependencies: + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@smithy/property-provider@4.0.5': + dependencies: + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@smithy/protocol-http@2.0.5': + dependencies: + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@smithy/protocol-http@3.3.0': + dependencies: + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@smithy/protocol-http@5.1.3': + dependencies: + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@smithy/querystring-builder@2.2.0': + dependencies: + '@smithy/types': 2.12.0 + '@smithy/util-uri-escape': 2.2.0 + tslib: 2.8.1 + + '@smithy/querystring-builder@4.0.5': + dependencies: + '@smithy/types': 4.3.2 + '@smithy/util-uri-escape': 4.0.0 + tslib: 2.8.1 + + '@smithy/querystring-parser@2.2.0': + dependencies: + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@smithy/querystring-parser@4.0.5': + dependencies: + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@smithy/service-error-classification@2.1.5': + dependencies: + '@smithy/types': 2.12.0 + + '@smithy/service-error-classification@4.0.7': + dependencies: + '@smithy/types': 4.3.2 + + '@smithy/shared-ini-file-loader@2.4.0': + dependencies: + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@smithy/shared-ini-file-loader@4.0.5': + dependencies: + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@smithy/signature-v4@2.3.0': + dependencies: + '@smithy/is-array-buffer': 2.2.0 + '@smithy/types': 2.12.0 + '@smithy/util-hex-encoding': 2.2.0 + '@smithy/util-middleware': 2.2.0 + '@smithy/util-uri-escape': 2.2.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@smithy/signature-v4@5.1.3': + dependencies: + '@smithy/is-array-buffer': 4.0.0 + '@smithy/protocol-http': 5.1.3 + '@smithy/types': 4.3.2 + '@smithy/util-hex-encoding': 4.0.0 + '@smithy/util-middleware': 4.0.5 + '@smithy/util-uri-escape': 4.0.0 + '@smithy/util-utf8': 4.0.0 + tslib: 2.8.1 + + '@smithy/smithy-client@2.5.1': + dependencies: + '@smithy/middleware-endpoint': 2.5.1 + '@smithy/middleware-stack': 2.2.0 + '@smithy/protocol-http': 3.3.0 + '@smithy/types': 2.12.0 + '@smithy/util-stream': 2.2.0 + tslib: 2.8.1 + + '@smithy/smithy-client@4.4.10': + dependencies: + '@smithy/core': 3.8.0 + '@smithy/middleware-endpoint': 4.1.18 + '@smithy/middleware-stack': 4.0.5 + '@smithy/protocol-http': 5.1.3 + '@smithy/types': 4.3.2 + '@smithy/util-stream': 4.2.4 + tslib: 2.8.1 + + '@smithy/types@2.12.0': + dependencies: + tslib: 2.8.1 + + '@smithy/types@4.3.2': + dependencies: + tslib: 2.8.1 + + '@smithy/url-parser@2.2.0': + dependencies: + '@smithy/querystring-parser': 2.2.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@smithy/url-parser@4.0.5': + dependencies: + '@smithy/querystring-parser': 4.0.5 + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@smithy/util-base64@2.3.0': + dependencies: + '@smithy/util-buffer-from': 2.2.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@smithy/util-base64@4.0.0': + dependencies: + '@smithy/util-buffer-from': 4.0.0 + '@smithy/util-utf8': 4.0.0 + tslib: 2.8.1 + + '@smithy/util-body-length-browser@2.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-body-length-browser@4.0.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-body-length-node@2.3.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-body-length-node@4.0.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-buffer-from@2.2.0': + dependencies: + '@smithy/is-array-buffer': 2.2.0 + tslib: 2.8.1 + + '@smithy/util-buffer-from@4.0.0': + dependencies: + '@smithy/is-array-buffer': 4.0.0 + tslib: 2.8.1 + + '@smithy/util-config-provider@2.3.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-config-provider@4.0.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-defaults-mode-browser@2.2.1': + dependencies: + '@smithy/property-provider': 2.2.0 + '@smithy/smithy-client': 2.5.1 + '@smithy/types': 2.12.0 + bowser: 2.12.0 + tslib: 2.8.1 + + '@smithy/util-defaults-mode-browser@4.0.26': + dependencies: + '@smithy/property-provider': 4.0.5 + '@smithy/smithy-client': 4.4.10 + '@smithy/types': 4.3.2 + bowser: 2.12.0 + tslib: 2.8.1 + + '@smithy/util-defaults-mode-node@2.3.1': + dependencies: + '@smithy/config-resolver': 2.2.0 + '@smithy/credential-provider-imds': 2.3.0 + '@smithy/node-config-provider': 2.3.0 + '@smithy/property-provider': 2.2.0 + '@smithy/smithy-client': 2.5.1 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@smithy/util-defaults-mode-node@4.0.26': + dependencies: + '@smithy/config-resolver': 4.1.5 + '@smithy/credential-provider-imds': 4.0.7 + '@smithy/node-config-provider': 4.1.4 + '@smithy/property-provider': 4.0.5 + '@smithy/smithy-client': 4.4.10 + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@smithy/util-endpoints@3.0.7': + dependencies: + '@smithy/node-config-provider': 4.1.4 + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@smithy/util-hex-encoding@2.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-hex-encoding@4.0.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-middleware@2.2.0': + dependencies: + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@smithy/util-middleware@4.0.5': + dependencies: + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@smithy/util-retry@2.2.0': + dependencies: + '@smithy/service-error-classification': 2.1.5 + '@smithy/types': 2.12.0 + tslib: 2.8.1 + + '@smithy/util-retry@4.0.7': + dependencies: + '@smithy/service-error-classification': 4.0.7 + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@smithy/util-stream@2.2.0': + dependencies: + '@smithy/fetch-http-handler': 2.5.0 + '@smithy/node-http-handler': 2.5.0 + '@smithy/types': 2.12.0 + '@smithy/util-base64': 2.3.0 + '@smithy/util-buffer-from': 2.2.0 + '@smithy/util-hex-encoding': 2.2.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@smithy/util-stream@4.2.4': dependencies: - '@sentry/types': 7.120.3 + '@smithy/fetch-http-handler': 5.1.1 + '@smithy/node-http-handler': 4.1.1 + '@smithy/types': 4.3.2 + '@smithy/util-base64': 4.0.0 + '@smithy/util-buffer-from': 4.0.0 + '@smithy/util-hex-encoding': 4.0.0 + '@smithy/util-utf8': 4.0.0 + tslib: 2.8.1 - '@sinclair/typebox@0.27.8': {} + '@smithy/util-uri-escape@2.2.0': + dependencies: + tslib: 2.8.1 - '@sindresorhus/is@4.6.0': {} + '@smithy/util-uri-escape@4.0.0': + dependencies: + tslib: 2.8.1 - '@sindresorhus/merge-streams@2.3.0': {} + '@smithy/util-utf8@2.3.0': + dependencies: + '@smithy/util-buffer-from': 2.2.0 + tslib: 2.8.1 - '@sindresorhus/merge-streams@4.0.0': {} + '@smithy/util-utf8@4.0.0': + dependencies: + '@smithy/util-buffer-from': 4.0.0 + tslib: 2.8.1 - '@sinonjs/commons@3.0.1': + '@smithy/util-waiter@2.2.0': dependencies: - type-detect: 4.0.8 + '@smithy/abort-controller': 2.2.0 + '@smithy/types': 2.12.0 + tslib: 2.8.1 - '@sinonjs/fake-timers@10.3.0': + '@smithy/util-waiter@4.0.7': dependencies: - '@sinonjs/commons': 3.0.1 + '@smithy/abort-controller': 4.0.5 + '@smithy/types': 4.3.2 + tslib: 2.8.1 + + '@speed-highlight/core@1.2.7': {} '@stylistic/eslint-plugin@2.7.2(eslint@8.57.1)(typescript@5.8.3)': dependencies: @@ -10343,6 +13491,8 @@ snapshots: '@tsconfig/node16@1.0.4': optional: true + '@tsconfig/node18@1.0.3': {} + '@tybys/wasm-util@0.9.0': dependencies: tslib: 2.8.1 @@ -10449,8 +13599,17 @@ snapshots: '@types/lodash@4.17.5': {} + '@types/node-fetch@2.6.13': + dependencies: + '@types/node': 22.15.30 + form-data: 4.0.4 + '@types/node@12.20.55': {} + '@types/node@18.19.123': + dependencies: + undici-types: 5.26.5 + '@types/node@22.15.30': dependencies: undici-types: 6.21.0 @@ -10493,6 +13652,8 @@ snapshots: '@types/uuid@10.0.0': {} + '@types/uuid@9.0.8': {} + '@types/yargs-parser@21.0.3': {} '@types/yargs@17.0.32': @@ -10810,7 +13971,7 @@ snapshots: std-env: 3.9.0 test-exclude: 7.0.1 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/node@22.15.30)(@vitest/ui@3.2.4)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.29.2)(msw@2.9.0(@types/node@22.15.30)(typescript@5.8.3))(yaml@2.6.0) + vitest: 3.2.4(@types/node@22.15.30)(@vitest/ui@3.2.4)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.29.2)(msw@2.9.0(@types/node@22.15.30)(typescript@5.8.3))(terser@5.16.9)(yaml@2.8.1) transitivePeerDependencies: - supports-color @@ -10822,14 +13983,14 @@ snapshots: chai: 5.2.0 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.4(msw@2.9.0(@types/node@22.15.30)(typescript@5.8.3))(vite@7.0.3(@types/node@22.15.30)(jiti@2.4.2)(lightningcss@1.29.2)(yaml@2.6.0))': + '@vitest/mocker@3.2.4(msw@2.9.0(@types/node@22.15.30)(typescript@5.8.3))(vite@7.0.3(@types/node@22.15.30)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.16.9)(yaml@2.8.1))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: msw: 2.9.0(@types/node@22.15.30)(typescript@5.8.3) - vite: 7.0.3(@types/node@22.15.30)(jiti@2.4.2)(lightningcss@1.29.2)(yaml@2.6.0) + vite: 7.0.3(@types/node@22.15.30)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.16.9)(yaml@2.8.1) '@vitest/pretty-format@3.2.4': dependencies: @@ -10860,7 +14021,7 @@ snapshots: sirv: 3.0.1 tinyglobby: 0.2.14 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/node@22.15.30)(@vitest/ui@3.2.4)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.29.2)(msw@2.9.0(@types/node@22.15.30)(typescript@5.8.3))(yaml@2.6.0) + vitest: 3.2.4(@types/node@22.15.30)(@vitest/ui@3.2.4)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.29.2)(msw@2.9.0(@types/node@22.15.30)(typescript@5.8.3))(terser@5.16.9)(yaml@2.8.1) '@vitest/utils@3.2.4': dependencies: @@ -10922,6 +14083,15 @@ snapshots: '@vue/shared@3.5.16': {} + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 + + accepts@2.0.0: + dependencies: + mime-types: 3.0.1 + negotiator: 1.0.0 + acorn-jsx@5.3.2(acorn@8.15.0): dependencies: acorn: 8.15.0 @@ -10931,10 +14101,14 @@ snapshots: acorn: 8.15.0 optional: true + acorn-walk@8.3.2: {} + acorn-walk@8.3.4: dependencies: acorn: 8.15.0 + acorn@8.14.0: {} + acorn@8.15.0: {} adm-zip@0.5.16: {} @@ -10947,6 +14121,10 @@ snapshots: agent-base@7.1.3: {} + agentkeepalive@4.6.0: + dependencies: + humanize-ms: 1.2.1 + ajv-formats@3.0.1(ajv@8.17.1): optionalDependencies: ajv: 8.17.1 @@ -11117,6 +14295,8 @@ snapshots: dependencies: possible-typed-array-names: 1.0.0 + aws4fetch@1.0.20: {} + axe-core@4.10.3: {} axios@1.9.0: @@ -11224,8 +14404,26 @@ snapshots: binary-extensions@2.3.0: {} + blake3-wasm@2.1.5: {} + + body-parser@2.2.0: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 4.4.1 + http-errors: 2.0.0 + iconv-lite: 0.6.3 + on-finished: 2.4.1 + qs: 6.14.0 + raw-body: 3.0.0 + type-is: 2.0.1 + transitivePeerDependencies: + - supports-color + boolbase@1.0.0: {} + bowser@2.12.0: {} + brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 @@ -11447,10 +14645,28 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 7.0.0 + cliui@9.0.1: + dependencies: + string-width: 7.2.0 + strip-ansi: 7.1.0 + wrap-ansi: 9.0.0 + clone-response@1.0.3: dependencies: mimic-response: 1.0.1 + cloudflare@4.5.0(encoding@0.1.13): + dependencies: + '@types/node': 18.19.123 + '@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(encoding@0.1.13) + transitivePeerDependencies: + - encoding + clsx@2.1.1: {} co@4.6.0: {} @@ -11477,8 +14693,12 @@ snapshots: dependencies: delayed-stream: 1.0.0 + commander@11.1.0: {} + commander@14.0.0: {} + commander@2.20.3: {} + commander@4.1.1: {} commander@7.2.0: {} @@ -11530,6 +14750,10 @@ snapshots: consola@3.4.2: {} + content-disposition@1.0.0: + dependencies: + safe-buffer: 5.2.1 + content-security-policy-builder@2.3.0: {} content-type@1.0.5: {} @@ -11538,12 +14762,16 @@ snapshots: cookie-es@1.2.2: {} + cookie-signature@1.2.2: {} + cookie@0.4.2: {} cookie@0.7.1: {} cookie@0.7.2: {} + cookie@1.0.2: {} + cors@2.8.5: dependencies: object-assign: 4.1.1 @@ -11678,6 +14906,10 @@ snapshots: dependencies: ms: 2.1.3 + debug@4.3.6: + dependencies: + ms: 2.1.2 + debug@4.4.1: dependencies: ms: 2.1.3 @@ -11731,6 +14963,8 @@ snapshots: delayed-stream@1.0.0: {} + depd@2.0.0: {} + destr@2.0.5: {} detect-indent@6.1.0: {} @@ -11825,6 +15059,15 @@ snapshots: eastasianwidth@0.2.0: {} + eciesjs@0.4.15: + dependencies: + '@ecies/ciphers': 0.2.4(@noble/ciphers@1.3.0) + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.7 + '@noble/hashes': 1.8.0 + + ee-first@1.1.1: {} + electron-to-chromium@1.5.165: {} embla-carousel-autoplay@8.5.2(embla-carousel@8.5.2): @@ -11855,6 +15098,8 @@ snapshots: emoji-regex@9.2.2: {} + encodeurl@2.0.0: {} + encoding-sniffer@0.2.0: dependencies: iconv-lite: 0.6.3 @@ -11887,6 +15132,8 @@ snapshots: dependencies: is-arrayish: 0.2.1 + error-stack-parser-es@1.0.5: {} + es-abstract@1.23.9: dependencies: array-buffer-byte-length: 1.0.2 @@ -11987,6 +15234,34 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 + esbuild@0.25.4: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.4 + '@esbuild/android-arm': 0.25.4 + '@esbuild/android-arm64': 0.25.4 + '@esbuild/android-x64': 0.25.4 + '@esbuild/darwin-arm64': 0.25.4 + '@esbuild/darwin-x64': 0.25.4 + '@esbuild/freebsd-arm64': 0.25.4 + '@esbuild/freebsd-x64': 0.25.4 + '@esbuild/linux-arm': 0.25.4 + '@esbuild/linux-arm64': 0.25.4 + '@esbuild/linux-ia32': 0.25.4 + '@esbuild/linux-loong64': 0.25.4 + '@esbuild/linux-mips64el': 0.25.4 + '@esbuild/linux-ppc64': 0.25.4 + '@esbuild/linux-riscv64': 0.25.4 + '@esbuild/linux-s390x': 0.25.4 + '@esbuild/linux-x64': 0.25.4 + '@esbuild/netbsd-arm64': 0.25.4 + '@esbuild/netbsd-x64': 0.25.4 + '@esbuild/openbsd-arm64': 0.25.4 + '@esbuild/openbsd-x64': 0.25.4 + '@esbuild/sunos-x64': 0.25.4 + '@esbuild/win32-arm64': 0.25.4 + '@esbuild/win32-ia32': 0.25.4 + '@esbuild/win32-x64': 0.25.4 + esbuild@0.25.6: optionalDependencies: '@esbuild/aix-ppc64': 0.25.6 @@ -12018,6 +15293,8 @@ snapshots: escalade@3.2.0: {} + escape-html@1.0.3: {} + escape-string-regexp@2.0.0: {} escape-string-regexp@4.0.0: {} @@ -12040,8 +15317,8 @@ snapshots: '@typescript-eslint/parser': 8.28.0(eslint@8.57.1)(typescript@5.8.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.9.1(eslint-plugin-import@2.31.0)(eslint@8.57.1) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1)(eslint@8.57.1) + eslint-import-resolver-typescript: 3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1) eslint-plugin-react: 7.37.4(eslint@8.57.1) eslint-plugin-react-hooks: 5.2.0(eslint@8.57.1) @@ -12068,7 +15345,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0)(eslint@8.57.1): + eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.1 @@ -12079,18 +15356,18 @@ snapshots: stable-hash: 0.0.5 tinyglobby: 0.2.14 optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1)(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.9.1)(eslint@8.57.1): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 8.28.0(eslint@8.57.1)(typescript@5.8.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.9.1(eslint-plugin-import@2.31.0)(eslint@8.57.1) + eslint-import-resolver-typescript: 3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1) transitivePeerDependencies: - supports-color @@ -12104,7 +15381,7 @@ snapshots: dependencies: gettext-parser: 4.2.0 - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1)(eslint@8.57.1): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -12115,7 +15392,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.9.1)(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.9.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.28.0(eslint@8.57.1)(typescript@5.8.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -12342,6 +15619,10 @@ snapshots: esutils@2.0.3: {} + etag@1.8.1: {} + + event-target-shim@5.0.1: {} + execa@5.1.1: dependencies: cross-spawn: 7.0.6 @@ -12381,6 +15662,8 @@ snapshots: strip-final-newline: 4.0.0 yoctocolors: 2.1.1 + exit-hook@2.2.1: {} + exit@0.1.2: {} expect-type@1.2.2: {} @@ -12393,6 +15676,43 @@ snapshots: jest-message-util: 29.7.0 jest-util: 29.7.0 + express@5.0.1: + dependencies: + accepts: 2.0.0 + body-parser: 2.2.0 + content-disposition: 1.0.0 + content-type: 1.0.5 + cookie: 0.7.1 + cookie-signature: 1.2.2 + debug: 4.3.6 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.0 + fresh: 2.0.0 + http-errors: 2.0.0 + merge-descriptors: 2.0.0 + methods: 1.1.2 + mime-types: 3.0.1 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.13.0 + range-parser: 1.2.1 + router: 2.2.0 + safe-buffer: 5.2.1 + send: 1.2.0 + serve-static: 2.2.0 + setprototypeof: 1.2.0 + statuses: 2.0.1 + type-is: 2.0.1 + utils-merge: 1.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + exsolve@1.0.5: {} exsolve@1.0.7: {} @@ -12445,10 +15765,18 @@ snapshots: fast-uri@3.0.3: {} + fast-xml-parser@4.2.5: + dependencies: + strnum: 1.1.2 + fast-xml-parser@4.5.3: dependencies: strnum: 1.1.2 + fast-xml-parser@5.2.5: + dependencies: + strnum: 2.1.1 + fastq@1.17.1: dependencies: reusify: 1.0.4 @@ -12479,6 +15807,17 @@ snapshots: dependencies: to-regex-range: 5.0.1 + finalhandler@2.1.0: + dependencies: + debug: 4.4.1 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + find-up@4.1.0: dependencies: locate-path: 5.0.0 @@ -12514,6 +15853,13 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + form-data-encoder@1.7.2: {} + form-data@4.0.2: dependencies: asynckit: 0.4.0 @@ -12521,8 +15867,25 @@ snapshots: es-set-tostringtag: 2.1.0 mime-types: 2.1.35 + form-data@4.0.4: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 + mime-types: 2.1.35 + + formdata-node@4.4.1: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 4.0.0-beta.3 + + forwarded@0.2.0: {} + fraction.js@4.3.7: {} + fresh@2.0.0: {} + fs-extra@11.3.0: dependencies: graceful-fs: 4.2.11 @@ -12663,6 +16026,8 @@ snapshots: dependencies: is-glob: 4.0.3 + glob-to-regexp@0.4.1: {} + glob@10.4.5: dependencies: foreground-child: 3.3.0 @@ -12672,6 +16037,15 @@ snapshots: package-json-from-dist: 1.0.1 path-scurry: 1.11.1 + glob@11.0.3: + dependencies: + foreground-child: 3.3.1 + jackspeak: 4.1.1 + minimatch: 10.0.3 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 2.0.0 + glob@7.2.3: dependencies: fs.realpath: 1.0.0 @@ -12681,6 +16055,13 @@ snapshots: once: 1.4.0 path-is-absolute: 1.0.1 + glob@9.3.5: + dependencies: + fs.realpath: 1.0.0 + minimatch: 8.0.4 + minipass: 4.2.8 + path-scurry: 1.11.1 + globals@11.12.0: {} globals@13.24.0: @@ -12805,6 +16186,14 @@ snapshots: http-cache-semantics@4.2.0: {} + http-errors@2.0.0: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.1 + toidentifier: 1.0.1 + http-link-header@1.1.3: {} http-proxy-agent@7.0.2: @@ -12843,6 +16232,10 @@ snapshots: human-signals@8.0.1: {} + humanize-ms@1.2.1: + dependencies: + ms: 2.1.3 + iconv-lite@0.4.24: dependencies: safer-buffer: 2.1.2 @@ -12898,6 +16291,8 @@ snapshots: jsbn: 1.1.0 sprintf-js: 1.1.3 + ipaddr.js@1.9.1: {} + iron-webcrypto@1.2.1: {} is-array-buffer@3.0.5: @@ -13006,6 +16401,8 @@ snapshots: is-potential-custom-element-name@1.0.1: {} + is-promise@4.0.0: {} + is-reference@3.0.3: dependencies: '@types/estree': 1.0.8 @@ -13084,6 +16481,8 @@ snapshots: isexe@2.0.0: {} + isexe@3.1.1: {} + isomorphic-dompurify@2.25.0: dependencies: dompurify: 3.2.6 @@ -13165,6 +16564,10 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 + jackspeak@4.1.1: + dependencies: + '@isaacs/cliui': 8.0.2 + jest-changed-files@29.7.0: dependencies: execa: 5.1.1 @@ -13575,6 +16978,8 @@ snapshots: kleur@3.0.3: {} + kleur@4.1.5: {} + knitwork@1.2.0: {} language-subtag-registry@0.3.23: {} @@ -13864,12 +17269,18 @@ snapshots: math-intrinsics@1.1.0: {} + media-typer@1.1.0: {} + + merge-descriptors@2.0.0: {} + merge-stream@2.0.0: {} merge2@1.4.1: {} metaviewport-parser@0.3.0: {} + methods@1.1.2: {} + micromatch@4.0.8: dependencies: braces: 3.0.3 @@ -13883,6 +17294,12 @@ snapshots: dependencies: mime-db: 1.52.0 + mime-types@3.0.1: + dependencies: + mime-db: 1.54.0 + + mime@3.0.0: {} + mimic-fn@2.1.0: {} mimic-fn@4.0.0: {} @@ -13893,10 +17310,36 @@ snapshots: mimic-response@3.1.0: {} + miniflare@4.20250816.0: + dependencies: + '@cspotcode/source-map-support': 0.8.1 + acorn: 8.14.0 + acorn-walk: 8.3.2 + exit-hook: 2.2.1 + glob-to-regexp: 0.4.1 + sharp: 0.33.5 + stoppable: 1.1.0 + undici: 7.14.0 + workerd: 1.20250816.0 + ws: 8.18.0 + youch: 4.1.0-beta.10 + zod: 3.22.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + minimatch@10.0.3: + dependencies: + '@isaacs/brace-expansion': 5.0.0 + minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 + minimatch@8.0.4: + dependencies: + brace-expansion: 2.0.1 + minimatch@9.0.5: dependencies: brace-expansion: 2.0.1 @@ -13907,6 +17350,8 @@ snapshots: dependencies: yallist: 4.0.0 + minipass@4.2.8: {} + minipass@5.0.0: {} minipass@7.1.2: {} @@ -13927,12 +17372,18 @@ snapshots: pkg-types: 1.3.1 ufo: 1.6.1 + mnemonist@0.38.3: + dependencies: + obliterator: 1.6.1 + mri@1.2.0: {} mrmime@2.0.1: {} ms@2.0.0: {} + ms@2.1.2: {} + ms@2.1.3: {} msw@2.9.0(@types/node@22.15.30)(typescript@5.8.3): @@ -14022,6 +17473,8 @@ snapshots: node-addon-api@7.1.1: {} + node-domexception@1.0.0: {} + node-fetch-native@1.6.6: {} node-fetch@2.7.0(encoding@0.1.13): @@ -14100,6 +17553,8 @@ snapshots: object-keys@1.1.1: {} + object-treeify@1.1.33: {} + object.assign@4.1.7: dependencies: call-bind: 1.0.8 @@ -14136,6 +17591,8 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.1.1 + obliterator@1.6.1: {} + ofetch@1.4.1: dependencies: destr: 2.0.5 @@ -14146,6 +17603,10 @@ snapshots: ohash@2.0.11: {} + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + on-headers@1.0.2: {} once@1.4.0: @@ -14295,6 +17756,8 @@ snapshots: dependencies: entities: 6.0.0 + parseurl@1.3.3: {} + path-exists@4.0.0: {} path-is-absolute@1.0.1: {} @@ -14310,8 +17773,15 @@ snapshots: lru-cache: 10.4.3 minipass: 7.1.2 + path-scurry@2.0.0: + dependencies: + lru-cache: 11.1.0 + minipass: 7.1.2 + path-to-regexp@6.3.0: {} + path-to-regexp@8.2.0: {} + path-type@4.0.0: {} path-type@6.0.0: {} @@ -14487,13 +17957,13 @@ snapshots: postcss: 8.5.6 ts-node: 10.9.2(@swc/core@1.11.31)(@types/node@22.15.30)(typescript@5.8.3) - postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.6)(yaml@2.6.0): + postcss-load-config@6.0.1(jiti@2.4.2)(postcss@8.5.6)(yaml@2.8.1): dependencies: lilconfig: 3.1.3 optionalDependencies: jiti: 2.4.2 postcss: 8.5.6 - yaml: 2.6.0 + yaml: 2.8.1 postcss-logical@8.1.0(postcss@8.5.6): dependencies: @@ -14687,6 +18157,11 @@ snapshots: object-assign: 4.1.1 react-is: 16.13.1 + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + proxy-agent@6.5.0: dependencies: agent-base: 7.1.3 @@ -14764,6 +18239,14 @@ snapshots: pure-rand@6.1.0: {} + qs@6.13.0: + dependencies: + side-channel: 1.1.0 + + qs@6.14.0: + dependencies: + side-channel: 1.1.0 + quansync@0.2.10: {} querystringify@2.2.0: {} @@ -14778,6 +18261,15 @@ snapshots: dependencies: performance-now: 2.1.0 + range-parser@1.2.1: {} + + raw-body@3.0.0: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.6.3 + unpipe: 1.0.0 + rc9@2.1.2: dependencies: defu: 6.1.4 @@ -14971,6 +18463,16 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.44.2 fsevents: 2.3.3 + router@2.2.0: + dependencies: + debug: 4.4.1 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.2.0 + transitivePeerDependencies: + - supports-color + rrweb-cssom@0.8.0: {} rspack-resolver@1.2.2: @@ -15036,6 +18538,31 @@ snapshots: semver@7.7.2: {} + send@1.2.0: + dependencies: + debug: 4.4.1 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.0 + mime-types: 3.0.1 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + + serve-static@2.2.0: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.0 + transitivePeerDependencies: + - supports-color + server-only@0.0.1: {} set-function-length@1.2.2: @@ -15060,6 +18587,8 @@ snapshots: es-errors: 1.3.0 es-object-atoms: 1.1.1 + setprototypeof@1.2.0: {} + shallowequal@1.1.0: {} sharp@0.33.5: @@ -15220,6 +18749,11 @@ snapshots: buffer-from: 1.1.2 source-map: 0.6.1 + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + source-map@0.6.1: {} source-map@0.8.0-beta.0: @@ -15264,6 +18798,8 @@ snapshots: stdin-discarder@0.2.2: {} + stoppable@1.1.0: {} + streamx@2.22.1: dependencies: fast-fifo: 1.3.2 @@ -15380,6 +18916,8 @@ snapshots: strnum@1.1.2: {} + strnum@2.1.1: {} + stubborn-fs@1.2.5: {} styled-jsx@5.1.6(@babel/core@7.27.4)(react@19.1.0): @@ -15399,6 +18937,8 @@ snapshots: pirates: 4.0.6 ts-interface-checker: 0.1.13 + supports-color@10.2.0: {} + supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -15501,6 +19041,13 @@ snapshots: term-size@2.2.1: {} + terser@5.16.9: + dependencies: + '@jridgewell/source-map': 0.3.11 + acorn: 8.15.0 + commander: 2.20.3 + source-map-support: 0.5.21 + test-exclude@6.0.0: dependencies: '@istanbuljs/schema': 0.1.3 @@ -15570,6 +19117,8 @@ snapshots: dependencies: is-number: 7.0.0 + toidentifier@1.0.1: {} + totalist@3.0.1: {} tough-cookie@4.1.4: @@ -15626,6 +19175,8 @@ snapshots: '@swc/core': 1.11.31 optional: true + ts-tqdm@0.8.6: {} + tsconfig-paths@3.15.0: dependencies: '@types/json5': 0.0.29 @@ -15637,7 +19188,7 @@ snapshots: tslib@2.8.1: {} - tsup@8.5.0(@swc/core@1.11.31)(jiti@2.4.2)(postcss@8.5.6)(typescript@5.8.3)(yaml@2.6.0): + tsup@8.5.0(@swc/core@1.11.31)(jiti@2.4.2)(postcss@8.5.6)(typescript@5.8.3)(yaml@2.8.1): dependencies: bundle-require: 5.1.0(esbuild@0.25.6) cac: 6.7.14 @@ -15648,7 +19199,7 @@ snapshots: fix-dts-default-cjs-exports: 1.0.1 joycon: 3.1.1 picocolors: 1.1.1 - postcss-load-config: 6.0.1(jiti@2.4.2)(postcss@8.5.6)(yaml@2.6.0) + postcss-load-config: 6.0.1(jiti@2.4.2)(postcss@8.5.6)(yaml@2.8.1) resolve-from: 5.0.0 rollup: 4.44.2 source-map: 0.8.0-beta.0 @@ -15710,6 +19261,12 @@ snapshots: type-fest@4.33.0: {} + type-is@2.0.1: + dependencies: + content-type: 1.0.5 + media-typer: 1.1.0 + mime-types: 3.0.1 + typed-array-buffer@1.0.3: dependencies: call-bound: 1.0.4 @@ -15783,10 +19340,22 @@ snapshots: magic-string: 0.30.17 unplugin: 2.3.5 + undici-types@5.26.5: {} + undici-types@6.21.0: {} undici@6.21.3: {} + undici@7.14.0: {} + + unenv@2.0.0-rc.19: + dependencies: + defu: 6.1.4 + exsolve: 1.0.7 + ohash: 2.0.11 + pathe: 2.0.3 + ufo: 1.6.1 + unicorn-magic@0.3.0: {} unimport@3.14.6(rollup@4.44.2): @@ -15837,6 +19406,8 @@ snapshots: - typescript - utf-8-validate + unpipe@1.0.0: {} + unplugin@1.16.1: dependencies: acorn: 8.15.0 @@ -15912,8 +19483,12 @@ snapshots: util-deprecate@1.0.2: {} + utils-merge@1.0.1: {} + uuid@11.1.0: {} + uuid@9.0.1: {} + v8-compile-cache-lib@3.0.1: optional: true @@ -15925,13 +19500,13 @@ snapshots: vary@1.1.2: {} - vite-node@3.2.4(@types/node@22.15.30)(jiti@2.4.2)(lightningcss@1.29.2)(yaml@2.6.0): + vite-node@3.2.4(@types/node@22.15.30)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.16.9)(yaml@2.8.1): dependencies: cac: 6.7.14 debug: 4.4.1 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.0.3(@types/node@22.15.30)(jiti@2.4.2)(lightningcss@1.29.2)(yaml@2.6.0) + vite: 7.0.3(@types/node@22.15.30)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.16.9)(yaml@2.8.1) transitivePeerDependencies: - '@types/node' - jiti @@ -15946,7 +19521,7 @@ snapshots: - tsx - yaml - vite@7.0.3(@types/node@22.15.30)(jiti@2.4.2)(lightningcss@1.29.2)(yaml@2.6.0): + vite@7.0.3(@types/node@22.15.30)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.16.9)(yaml@2.8.1): dependencies: esbuild: 0.25.6 fdir: 6.4.6(picomatch@4.0.2) @@ -15959,13 +19534,14 @@ snapshots: fsevents: 2.3.3 jiti: 2.4.2 lightningcss: 1.29.2 - yaml: 2.6.0 + terser: 5.16.9 + yaml: 2.8.1 - vitest@3.2.4(@types/node@22.15.30)(@vitest/ui@3.2.4)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.29.2)(msw@2.9.0(@types/node@22.15.30)(typescript@5.8.3))(yaml@2.6.0): + vitest@3.2.4(@types/node@22.15.30)(@vitest/ui@3.2.4)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.29.2)(msw@2.9.0(@types/node@22.15.30)(typescript@5.8.3))(terser@5.16.9)(yaml@2.8.1): dependencies: '@types/chai': 5.2.2 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(msw@2.9.0(@types/node@22.15.30)(typescript@5.8.3))(vite@7.0.3(@types/node@22.15.30)(jiti@2.4.2)(lightningcss@1.29.2)(yaml@2.6.0)) + '@vitest/mocker': 3.2.4(msw@2.9.0(@types/node@22.15.30)(typescript@5.8.3))(vite@7.0.3(@types/node@22.15.30)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.16.9)(yaml@2.8.1)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 @@ -15983,8 +19559,8 @@ snapshots: tinyglobby: 0.2.14 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 7.0.3(@types/node@22.15.30)(jiti@2.4.2)(lightningcss@1.29.2)(yaml@2.6.0) - vite-node: 3.2.4(@types/node@22.15.30)(jiti@2.4.2)(lightningcss@1.29.2)(yaml@2.6.0) + vite: 7.0.3(@types/node@22.15.30)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.16.9)(yaml@2.8.1) + vite-node: 3.2.4(@types/node@22.15.30)(jiti@2.4.2)(lightningcss@1.29.2)(terser@5.16.9)(yaml@2.8.1) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 22.15.30 @@ -16022,6 +19598,8 @@ snapshots: dependencies: makeerror: 1.0.12 + web-streams-polyfill@4.0.0-beta.3: {} + webidl-conversions@3.0.1: {} webidl-conversions@4.0.2: {} @@ -16119,6 +19697,10 @@ snapshots: dependencies: isexe: 2.0.0 + which@4.0.0: + dependencies: + isexe: 3.1.1 + why-is-node-running@2.3.0: dependencies: siginfo: 2.0.0 @@ -16126,6 +19708,30 @@ snapshots: word-wrap@1.2.5: {} + workerd@1.20250816.0: + optionalDependencies: + '@cloudflare/workerd-darwin-64': 1.20250816.0 + '@cloudflare/workerd-darwin-arm64': 1.20250816.0 + '@cloudflare/workerd-linux-64': 1.20250816.0 + '@cloudflare/workerd-linux-arm64': 1.20250816.0 + '@cloudflare/workerd-windows-64': 1.20250816.0 + + wrangler@4.31.0: + dependencies: + '@cloudflare/kv-asset-handler': 0.4.0 + '@cloudflare/unenv-preset': 2.6.2(unenv@2.0.0-rc.19)(workerd@1.20250816.0) + blake3-wasm: 2.1.5 + esbuild: 0.25.4 + miniflare: 4.20250816.0 + path-to-regexp: 6.3.0 + unenv: 2.0.0-rc.19 + workerd: 1.20250816.0 + optionalDependencies: + fsevents: 2.3.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + wrap-ansi@6.2.0: dependencies: ansi-styles: 4.3.0 @@ -16166,6 +19772,8 @@ snapshots: ws@7.5.10: {} + ws@8.18.0: {} + ws@8.18.2: {} xdg-basedir@4.0.0: {} @@ -16182,8 +19790,12 @@ snapshots: yaml@2.6.0: {} + yaml@2.8.1: {} + yargs-parser@21.1.1: {} + yargs-parser@22.0.0: {} + yargs@17.7.2: dependencies: cliui: 8.0.1 @@ -16194,6 +19806,15 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 + yargs@18.0.0: + dependencies: + cliui: 9.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + string-width: 7.2.0 + y18n: 5.0.8 + yargs-parser: 22.0.0 + yauzl@2.10.0: dependencies: buffer-crc32: 0.2.13 @@ -16212,6 +19833,19 @@ snapshots: yoctocolors@2.1.1: {} + youch-core@0.3.3: + dependencies: + '@poppinss/exception': 1.2.2 + error-stack-parser-es: 1.0.5 + + youch@4.1.0-beta.10: + dependencies: + '@poppinss/colors': 4.1.5 + '@poppinss/dumper': 0.6.4 + '@speed-highlight/core': 1.2.7 + cookie: 1.0.2 + youch-core: 0.3.3 + zimmerframe@1.1.2: optional: true @@ -16219,6 +19853,8 @@ snapshots: dependencies: zod: 3.25.51 + zod@3.22.3: {} + zod@3.23.8: {} zod@3.25.51: {} From 25bc1181e2ddd76e28a6cf6ec917c74a5ecdbac7 Mon Sep 17 00:00:00 2001 From: Matthew Volk Date: Tue, 19 Aug 2025 15:40:52 -0500 Subject: [PATCH 021/245] refactor: organize configuration files for better build output (#2532) --- packages/cli/src/commands/build.ts | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/packages/cli/src/commands/build.ts b/packages/cli/src/commands/build.ts index 958e93b71a..86aa346a19 100644 --- a/packages/cli/src/commands/build.ts +++ b/packages/cli/src/commands/build.ts @@ -1,7 +1,7 @@ import { Command, Option } from 'commander'; import consola from 'consola'; import { execa } from 'execa'; -import { cp } from 'node:fs/promises'; +import { copyFile, cp, rm } from 'node:fs/promises'; import { join } from 'node:path'; import { getModuleCliPath } from '../lib/get-module-cli-path'; @@ -17,17 +17,22 @@ export const build = new Command('build') ]), ) .action(async () => { + const coreDir = process.cwd(); + try { - const coreDir = process.cwd(); const openNextOutDir = join(coreDir, '.open-next'); const bigcommerceDistDir = join(coreDir, '.bigcommerce', 'dist'); consola.start('Copying templates...'); - await cp(join(getModuleCliPath(), 'templates'), coreDir, { - recursive: true, - force: true, - }); + await copyFile( + join(getModuleCliPath(), 'templates', 'open-next.config.ts'), + join(coreDir, 'open-next.config.ts'), + ); + await copyFile( + join(getModuleCliPath(), 'templates', 'wrangler.jsonc'), + join(coreDir, '.bigcommerce', 'wrangler.jsonc'), + ); consola.success('Templates copied'); @@ -63,6 +68,10 @@ export const build = new Command('build') }); } catch (error) { consola.error(error); - process.exit(1); + process.exitCode = 1; + } finally { + await rm(join(coreDir, '.open-next.config.ts')).catch(() => null); + + process.exit(); } }); From f994d6c1c966bb5958951c0eb37ea6f5b7ba3c0f Mon Sep 17 00:00:00 2001 From: Matthew Volk Date: Tue, 19 Aug 2025 16:09:01 -0500 Subject: [PATCH 022/245] refactor: dynamically build wrangler.jsonc and inject project uuid (#2534) --- packages/cli/src/commands/build.ts | 19 +++++-- packages/cli/src/lib/wrangler-config.ts | 56 +++++++++++++++++++ packages/cli/templates/wrangler.jsonc | 54 ------------------ .../cli/tests/lib/wrangler-config.spec.ts | 12 ++++ 4 files changed, 83 insertions(+), 58 deletions(-) create mode 100644 packages/cli/src/lib/wrangler-config.ts delete mode 100644 packages/cli/templates/wrangler.jsonc create mode 100644 packages/cli/tests/lib/wrangler-config.spec.ts diff --git a/packages/cli/src/commands/build.ts b/packages/cli/src/commands/build.ts index 86aa346a19..666b3071fa 100644 --- a/packages/cli/src/commands/build.ts +++ b/packages/cli/src/commands/build.ts @@ -1,10 +1,12 @@ import { Command, Option } from 'commander'; import consola from 'consola'; import { execa } from 'execa'; -import { copyFile, cp, rm } from 'node:fs/promises'; +import { copyFile, cp, rm, writeFile } from 'node:fs/promises'; import { join } from 'node:path'; import { getModuleCliPath } from '../lib/get-module-cli-path'; +import { getProjectConfig } from '../lib/project-config'; +import { getWranglerConfig } from '../lib/wrangler-config'; const WRANGLER_VERSION = '4.24.3'; @@ -16,22 +18,31 @@ export const build = new Command('build') 'catalyst', ]), ) - .action(async () => { + .action(async (options) => { const coreDir = process.cwd(); try { const openNextOutDir = join(coreDir, '.open-next'); const bigcommerceDistDir = join(coreDir, '.bigcommerce', 'dist'); + const config = getProjectConfig(); + const projectUuid = options.projectUuid ?? config.get('projectUuid'); + + if (!projectUuid) { + throw new Error('Project UUID is required. Please run `link` or provide `--project-uuid`'); + } + + const wranglerConfig = getWranglerConfig(projectUuid, 'PLACEHOLDER_KV_ID'); + consola.start('Copying templates...'); await copyFile( join(getModuleCliPath(), 'templates', 'open-next.config.ts'), join(coreDir, 'open-next.config.ts'), ); - await copyFile( - join(getModuleCliPath(), 'templates', 'wrangler.jsonc'), + await writeFile( join(coreDir, '.bigcommerce', 'wrangler.jsonc'), + JSON.stringify(wranglerConfig, null, 2), ); consola.success('Templates copied'); diff --git a/packages/cli/src/lib/wrangler-config.ts b/packages/cli/src/lib/wrangler-config.ts new file mode 100644 index 0000000000..af58f82d83 --- /dev/null +++ b/packages/cli/src/lib/wrangler-config.ts @@ -0,0 +1,56 @@ +export function getWranglerConfig(projectUuid: string, kvNamespaceId: string) { + return { + $schema: 'node_modules/wrangler/config-schema.json', + main: '.open-next/worker.js', + name: `project-${projectUuid}`, + compatibility_date: '2025-07-15', + compatibility_flags: ['nodejs_compat', 'global_fetch_strictly_public'], + observability: { + enabled: true, + head_sampling_rate: 0.05, + logs: { + enabled: true, + head_sampling_rate: 1, + invocation_logs: false, + }, + }, + assets: { + directory: '.open-next/assets', + binding: 'ASSETS', + }, + services: [ + { + binding: 'WORKER_SELF_REFERENCE', + service: `project-${projectUuid}`, + }, + ], + kv_namespaces: [ + { + binding: 'NEXT_INC_CACHE_KV', + id: kvNamespaceId, + }, + ], + durable_objects: { + bindings: [ + { + name: 'NEXT_CACHE_DO_QUEUE', + class_name: 'DOQueueHandler', + }, + { + name: 'NEXT_TAG_CACHE_DO_SHARDED', + class_name: 'DOShardedTagCache', + }, + { + name: 'NEXT_CACHE_DO_PURGE', + class_name: 'BucketCachePurge', + }, + ], + }, + migrations: [ + { + tag: 'v1', + new_sqlite_classes: ['DOQueueHandler', 'DOShardedTagCache', 'BucketCachePurge'], + }, + ], + }; +} diff --git a/packages/cli/templates/wrangler.jsonc b/packages/cli/templates/wrangler.jsonc deleted file mode 100644 index 0d395790e4..0000000000 --- a/packages/cli/templates/wrangler.jsonc +++ /dev/null @@ -1,54 +0,0 @@ -{ - "$schema": "node_modules/wrangler/config-schema.json", - "main": ".open-next/worker.js", - "name": "store-hash-project-uuid", - "compatibility_date": "2025-07-15", - "compatibility_flags": ["nodejs_compat", "global_fetch_strictly_public"], - "observability": { - "enabled": true, - "head_sampling_rate": 0.05, - "logs": { - "enabled": true, - "head_sampling_rate": 1, - "invocation_logs": false, - }, - }, - "assets": { - "directory": ".open-next/assets", - "binding": "ASSETS", - }, - "services": [ - { - "binding": "WORKER_SELF_REFERENCE", - "service": "store-hash-project-uuid", - }, - ], - "kv_namespaces": [ - { - "binding": "NEXT_INC_CACHE_KV", - "id": "placeholder-kv-id", - }, - ], - "durable_objects": { - "bindings": [ - { - "name": "NEXT_CACHE_DO_QUEUE", - "class_name": "DOQueueHandler", - }, - { - "name": "NEXT_TAG_CACHE_DO_SHARDED", - "class_name": "DOShardedTagCache", - }, - { - "name": "NEXT_CACHE_DO_PURGE", - "class_name": "BucketCachePurge", - }, - ], - }, - "migrations": [ - { - "tag": "v1", - "new_sqlite_classes": ["DOQueueHandler", "DOShardedTagCache", "BucketCachePurge"], - }, - ], -} diff --git a/packages/cli/tests/lib/wrangler-config.spec.ts b/packages/cli/tests/lib/wrangler-config.spec.ts new file mode 100644 index 0000000000..348008c43c --- /dev/null +++ b/packages/cli/tests/lib/wrangler-config.spec.ts @@ -0,0 +1,12 @@ +import { expect, test } from 'vitest'; + +import { getWranglerConfig } from '../../src/lib/wrangler-config'; + +test('returns a config with name identical to worker self reference service', () => { + const config = getWranglerConfig('uuid', 'kv-namespace-id'); + + expect(config.name).toBe(`project-uuid`); + expect( + config.services.find((service) => service.binding === 'WORKER_SELF_REFERENCE')?.service, + ).toBe(`project-uuid`); +}); From 50666af3131775270aef3cc3153ca36f11bc3c24 Mon Sep 17 00:00:00 2001 From: Matthew Volk Date: Tue, 19 Aug 2025 16:40:33 -0500 Subject: [PATCH 023/245] refactor: proxy next build if framework is nextjs (#2535) --- packages/cli/src/commands/build.ts | 127 +++++++++++++--------- packages/cli/tests/commands/build.spec.ts | 29 ++++- 2 files changed, 105 insertions(+), 51 deletions(-) diff --git a/packages/cli/src/commands/build.ts b/packages/cli/src/commands/build.ts index 666b3071fa..8d24937ac2 100644 --- a/packages/cli/src/commands/build.ts +++ b/packages/cli/src/commands/build.ts @@ -1,6 +1,7 @@ import { Command, Option } from 'commander'; import consola from 'consola'; import { execa } from 'execa'; +import { existsSync } from 'node:fs'; import { copyFile, cp, rm, writeFile } from 'node:fs/promises'; import { join } from 'node:path'; @@ -11,6 +12,11 @@ import { getWranglerConfig } from '../lib/wrangler-config'; const WRANGLER_VERSION = '4.24.3'; export const build = new Command('build') + .allowUnknownOption() + .argument( + '[next-build-options...]', + 'Next.js `build` options (see: https://nextjs.org/docs/app/api-reference/cli/next#next-build-options)', + ) .option('--project-uuid ', 'Project UUID to be included in the deployment configuration.') .addOption( new Option('--framework ', 'The framework to use for the build.').choices([ @@ -18,65 +24,86 @@ export const build = new Command('build') 'catalyst', ]), ) - .action(async (options) => { + .action(async (nextBuildOptions, options) => { const coreDir = process.cwd(); try { - const openNextOutDir = join(coreDir, '.open-next'); - const bigcommerceDistDir = join(coreDir, '.bigcommerce', 'dist'); - const config = getProjectConfig(); - const projectUuid = options.projectUuid ?? config.get('projectUuid'); + const framework = options.framework ?? config.get('framework'); - if (!projectUuid) { - throw new Error('Project UUID is required. Please run `link` or provide `--project-uuid`'); - } + if (framework === 'nextjs') { + const nextBin = join('node_modules', '.bin', 'next'); - const wranglerConfig = getWranglerConfig(projectUuid, 'PLACEHOLDER_KV_ID'); - - consola.start('Copying templates...'); - - await copyFile( - join(getModuleCliPath(), 'templates', 'open-next.config.ts'), - join(coreDir, 'open-next.config.ts'), - ); - await writeFile( - join(coreDir, '.bigcommerce', 'wrangler.jsonc'), - JSON.stringify(wranglerConfig, null, 2), - ); - - consola.success('Templates copied'); - - consola.start('Building project...'); - - await execa('pnpm', ['exec', 'opennextjs-cloudflare', 'build'], { - stdout: ['pipe', 'inherit'], - cwd: coreDir, - }); - - await execa( - 'pnpm', - [ - 'dlx', - `wrangler@${WRANGLER_VERSION}`, - 'deploy', - '--keep-vars', - '--outdir', - bigcommerceDistDir, - '--dry-run', - ], - { - stdout: ['pipe', 'inherit'], + if (!existsSync(nextBin)) { + throw new Error( + `Next.js is not installed in ${coreDir}. Are you in a valid Next.js project?`, + ); + } + + await execa(nextBin, ['build', ...nextBuildOptions], { + stdio: 'inherit', cwd: coreDir, - }, - ); + }); + } + + if (framework === 'catalyst') { + const openNextOutDir = join(coreDir, '.open-next'); + const bigcommerceDistDir = join(coreDir, '.bigcommerce', 'dist'); + + const projectUuid = options.projectUuid ?? config.get('projectUuid'); - consola.success('Project built'); + if (!projectUuid) { + throw new Error( + 'Project UUID is required. Please run `link` or provide `--project-uuid`', + ); + } - await cp(join(openNextOutDir, 'assets'), join(bigcommerceDistDir, 'assets'), { - recursive: true, - force: true, - }); + const wranglerConfig = getWranglerConfig(projectUuid, 'PLACEHOLDER_KV_ID'); + + consola.start('Copying templates...'); + + await copyFile( + join(getModuleCliPath(), 'templates', 'open-next.config.ts'), + join(coreDir, 'open-next.config.ts'), + ); + await writeFile( + join(coreDir, '.bigcommerce', 'wrangler.jsonc'), + JSON.stringify(wranglerConfig, null, 2), + ); + + consola.success('Templates copied'); + + consola.start('Building project...'); + + await execa('pnpm', ['exec', 'opennextjs-cloudflare', 'build'], { + stdout: ['pipe', 'inherit'], + cwd: coreDir, + }); + + await execa( + 'pnpm', + [ + 'dlx', + `wrangler@${WRANGLER_VERSION}`, + 'deploy', + '--keep-vars', + '--outdir', + bigcommerceDistDir, + '--dry-run', + ], + { + stdout: ['pipe', 'inherit'], + cwd: coreDir, + }, + ); + + consola.success('Project built'); + + await cp(join(openNextOutDir, 'assets'), join(bigcommerceDistDir, 'assets'), { + recursive: true, + force: true, + }); + } } catch (error) { consola.error(error); process.exitCode = 1; diff --git a/packages/cli/tests/commands/build.spec.ts b/packages/cli/tests/commands/build.spec.ts index 769d664bec..5001e48d4c 100644 --- a/packages/cli/tests/commands/build.spec.ts +++ b/packages/cli/tests/commands/build.spec.ts @@ -1,7 +1,21 @@ import { Command } from 'commander'; -import { expect, test } from 'vitest'; +import { execa } from 'execa'; +import { expect, test, vi } from 'vitest'; import { build } from '../../src/commands/build'; +import { program } from '../../src/program'; + +// eslint-disable-next-line @typescript-eslint/consistent-type-assertions +vi.spyOn(process, 'exit').mockImplementation(() => null as never); + +vi.mock('node:fs', () => ({ + existsSync: vi.fn(() => true), +})); + +vi.mock('execa', () => ({ + execa: vi.fn(() => Promise.resolve({ stdout: '' })), + __esModule: true, +})); test('properly configured Command instance', () => { expect(build).toBeInstanceOf(Command); @@ -13,3 +27,16 @@ test('properly configured Command instance', () => { ]), ); }); + +test('calls execa with Next.js build if framework is nextjs', async () => { + await program.parseAsync(['node', 'catalyst', 'build', '--framework', 'nextjs', '--debug']); + + expect(execa).toHaveBeenCalledWith( + 'node_modules/.bin/next', + ['build', '--debug'], + expect.objectContaining({ + stdio: 'inherit', + cwd: process.cwd(), + }), + ); +}); From ad2d8eaf74219a7126cfc7597d1b2266763f4660 Mon Sep 17 00:00:00 2001 From: Matthew Volk Date: Tue, 19 Aug 2025 16:57:52 -0500 Subject: [PATCH 024/245] feat: ignore files and folders output by catalyst build (#2536) --- core/.gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/.gitignore b/core/.gitignore index 255bc859a8..f4086e9252 100644 --- a/core/.gitignore +++ b/core/.gitignore @@ -50,3 +50,7 @@ messages/*.d.json.ts # Build config build-config.json + +# OpenNext +.open-next +.wrangler From 4bb29799f308d40948f731298fb11e593f3eea91 Mon Sep 17 00:00:00 2001 From: Matthew Volk Date: Tue, 19 Aug 2025 17:11:12 -0500 Subject: [PATCH 025/245] feat: override buildcommand when building with opennextjs-cloudflare (#2537) --- packages/cli/templates/open-next.config.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/cli/templates/open-next.config.ts b/packages/cli/templates/open-next.config.ts index 9c468fbed5..cecbebc45e 100644 --- a/packages/cli/templates/open-next.config.ts +++ b/packages/cli/templates/open-next.config.ts @@ -1,12 +1,12 @@ -// @ts-nocheck import { defineCloudflareConfig } from '@opennextjs/cloudflare'; import { purgeCache } from '@opennextjs/cloudflare/overrides/cache-purge/index'; import kvIncrementalCache from '@opennextjs/cloudflare/overrides/incremental-cache/kv-incremental-cache'; import doQueue from '@opennextjs/cloudflare/overrides/queue/do-queue'; import queueCache from '@opennextjs/cloudflare/overrides/queue/queue-cache'; import doShardedTagCache from '@opennextjs/cloudflare/overrides/tag-cache/do-sharded-tag-cache'; +import { type OpenNextConfig } from '@opennextjs/cloudflare'; -export default defineCloudflareConfig({ +const cloudflareConfig = defineCloudflareConfig({ incrementalCache: kvIncrementalCache, queue: queueCache(doQueue, { regionalCacheTtlSec: 5, @@ -27,3 +27,10 @@ export default defineCloudflareConfig({ enableCacheInterception: false, cachePurge: purgeCache({ type: 'durableObject' }), }); + +const config: OpenNextConfig = { + buildCommand: 'node_modules/.bin/next build', + ...cloudflareConfig, +}; + +export default config; From 114e64c55f1774bde40c7b62c432ddbdc8dde6c1 Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Wed, 20 Aug 2025 12:36:14 -0500 Subject: [PATCH 026/245] feat(cli): run opennext-cloudflare preview for catalyst framework (#2518) * feat(cli): run opennext-cloudflare preview for catalyst framework * fix: update options --- packages/cli/src/commands/build.ts | 15 +++-- packages/cli/src/commands/dev.ts | 1 + packages/cli/src/commands/start.ts | 60 +++++++++++++----- packages/cli/src/lib/wrangler-config.ts | 4 +- packages/cli/tests/commands/start.spec.ts | 76 ++++++++++++++++++++++- 5 files changed, 130 insertions(+), 26 deletions(-) diff --git a/packages/cli/src/commands/build.ts b/packages/cli/src/commands/build.ts index 8d24937ac2..0618e36416 100644 --- a/packages/cli/src/commands/build.ts +++ b/packages/cli/src/commands/build.ts @@ -13,6 +13,7 @@ const WRANGLER_VERSION = '4.24.3'; export const build = new Command('build') .allowUnknownOption() + // The unknown options end up in program.args, not in program.opts(). Commander does not take a guess at how to interpret the unknown options. .argument( '[next-build-options...]', 'Next.js `build` options (see: https://nextjs.org/docs/app/api-reference/cli/next#next-build-options)', @@ -75,10 +76,14 @@ export const build = new Command('build') consola.start('Building project...'); - await execa('pnpm', ['exec', 'opennextjs-cloudflare', 'build'], { - stdout: ['pipe', 'inherit'], - cwd: coreDir, - }); + await execa( + 'pnpm', + ['exec', 'opennextjs-cloudflare', 'build', '--skipWranglerConfigCheck'], + { + stdout: ['pipe', 'inherit'], + cwd: coreDir, + }, + ); await execa( 'pnpm', @@ -86,6 +91,8 @@ export const build = new Command('build') 'dlx', `wrangler@${WRANGLER_VERSION}`, 'deploy', + '--config', + join(coreDir, '.bigcommerce', 'wrangler.jsonc'), '--keep-vars', '--outdir', bigcommerceDistDir, diff --git a/packages/cli/src/commands/dev.ts b/packages/cli/src/commands/dev.ts index 64d3330c20..abfedf758c 100644 --- a/packages/cli/src/commands/dev.ts +++ b/packages/cli/src/commands/dev.ts @@ -9,6 +9,7 @@ export const dev = new Command('dev') // Proxy `--help` to the underlying `next dev` command .helpOption(false) .allowUnknownOption(true) + // The unknown options end up in program.args, not in program.opts(). Commander does not take a guess at how to interpret the unknown options. .argument( '[options...]', 'Next.js `dev` options (see: https://nextjs.org/docs/app/api-reference/cli/next#next-dev-options)', diff --git a/packages/cli/src/commands/start.ts b/packages/cli/src/commands/start.ts index a94508494d..9892d2f697 100644 --- a/packages/cli/src/commands/start.ts +++ b/packages/cli/src/commands/start.ts @@ -1,35 +1,61 @@ -import { Command } from 'commander'; +import { Command, Option } from 'commander'; import consola from 'consola'; import { execa } from 'execa'; import { existsSync } from 'node:fs'; import { join } from 'node:path'; +import { getProjectConfig } from '../lib/project-config'; + export const start = new Command('start') .description('Start your Catalyst storefront in optimized production mode.') - // Proxy `--help` to the underlying `next start` command - .helpOption(false) .allowUnknownOption(true) + // The unknown options end up in program.args, not in program.opts(). Commander does not take a guess at how to interpret the unknown options. .argument( - '[options...]', - 'Next.js `start` options (see: https://nextjs.org/docs/app/api-reference/cli/next#next-start-options)', + '[start-options...]', + 'Pass additional options to the start command. If framework is Next.js, see https://nextjs.org/docs/api-reference/cli#start for available options.', + ) + .addOption( + new Option('--framework ', 'The framework to use for the preview').choices([ + 'catalyst', + 'nextjs', + ]), ) - .action(async (options) => { + .action(async (startOptions, options) => { try { - const nextBin = join('node_modules', '.bin', 'next'); + const config = getProjectConfig(); + const framework = options.framework ?? config.get('framework'); + + if (framework === 'nextjs') { + const nextBin = join('node_modules', '.bin', 'next'); + + if (!existsSync(nextBin)) { + throw new Error( + `Next.js is not installed in ${process.cwd()}. Are you in a valid Next.js project?`, + ); + } - if (!existsSync(nextBin)) { - throw new Error( - `Next.js is not installed in ${process.cwd()}. Are you in a valid Next.js project?`, - ); + await execa(nextBin, ['start', ...startOptions], { + stdio: 'inherit', + cwd: process.cwd(), + }); } - // @todo conditionally run `next start` or `opennextjs-cloudflare preview` based on the framework type - await execa(nextBin, ['start', ...options], { - stdio: 'inherit', - cwd: process.cwd(), - }); + await execa( + 'pnpm', + [ + 'exec', + 'opennextjs-cloudflare', + 'preview', + '--config', + join('.bigcommerce', 'wrangler.jsonc'), + ...startOptions, + ], + { + stdio: 'inherit', + cwd: process.cwd(), + }, + ); } catch (error) { consola.error(error instanceof Error ? error.message : error); - process.exit(1); } }); diff --git a/packages/cli/src/lib/wrangler-config.ts b/packages/cli/src/lib/wrangler-config.ts index af58f82d83..14ec6512e1 100644 --- a/packages/cli/src/lib/wrangler-config.ts +++ b/packages/cli/src/lib/wrangler-config.ts @@ -1,7 +1,7 @@ export function getWranglerConfig(projectUuid: string, kvNamespaceId: string) { return { $schema: 'node_modules/wrangler/config-schema.json', - main: '.open-next/worker.js', + main: '../.open-next/worker.js', name: `project-${projectUuid}`, compatibility_date: '2025-07-15', compatibility_flags: ['nodejs_compat', 'global_fetch_strictly_public'], @@ -15,7 +15,7 @@ export function getWranglerConfig(projectUuid: string, kvNamespaceId: string) { }, }, assets: { - directory: '.open-next/assets', + directory: '../.open-next/assets', binding: 'ASSETS', }, services: [ diff --git a/packages/cli/tests/commands/start.spec.ts b/packages/cli/tests/commands/start.spec.ts index b03a23e799..563588e1d1 100644 --- a/packages/cli/tests/commands/start.spec.ts +++ b/packages/cli/tests/commands/start.spec.ts @@ -1,6 +1,7 @@ import { Command } from 'commander'; +import consola from 'consola'; import { execa } from 'execa'; -import { expect, test, vi } from 'vitest'; +import { afterEach, beforeAll, beforeEach, expect, test, vi } from 'vitest'; import { start } from '../../src/commands/start'; import { program } from '../../src/program'; @@ -14,18 +15,87 @@ vi.mock('execa', () => ({ __esModule: true, })); +vi.mock('../../src/lib/project-config', () => ({ + getProjectConfig: vi.fn(() => ({ + get: vi.fn((key) => { + if (key === 'framework') { + return 'catalyst'; + } + + return undefined; + }), + })), +})); + +beforeAll(() => { + consola.wrapAll(); +}); + +beforeEach(() => { + consola.mockTypes(() => vi.fn()); +}); + +afterEach(() => { + vi.clearAllMocks(); +}); + test('properly configured Command instance', () => { expect(start).toBeInstanceOf(Command); expect(start.name()).toBe('start'); expect(start.description()).toBe('Start your Catalyst storefront in optimized production mode.'); + expect(start.options).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + flags: '--framework ', + argChoices: ['catalyst', 'nextjs'], + }), + ]), + ); }); test('calls execa with Next.js production optimized server', async () => { - await program.parseAsync(['node', 'catalyst', 'start', '-p', '3001']); + await program.parseAsync([ + 'node', + 'catalyst', + 'start', + '--port', + '3001', + '--framework', + 'nextjs', + ]); expect(execa).toHaveBeenCalledWith( 'node_modules/.bin/next', - ['start', '-p', '3001'], + ['start', '--port', '3001'], + expect.objectContaining({ + stdio: 'inherit', + cwd: process.cwd(), + }), + ); +}); + +test('calls execa with OpenNext production optimized server', async () => { + await program.parseAsync([ + 'node', + 'catalyst', + 'start', + '--port', + '3001', + '--framework', + 'catalyst', + ]); + + expect(execa).toHaveBeenCalledWith( + 'pnpm', + [ + 'exec', + 'opennextjs-cloudflare', + 'preview', + '--config', + '.bigcommerce/wrangler.jsonc', + '--port', + '3001', + ], expect.objectContaining({ stdio: 'inherit', cwd: process.cwd(), From d89183c1621b202fbac8fee1f15b6c29fc96a973 Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Fri, 22 Aug 2025 13:36:46 -0500 Subject: [PATCH 027/245] feat(cli): add --dry-run option to deploy (#2540) * feat(cli): add --dry-run option to deploy * fix: split path --- packages/cli/src/commands/deploy.ts | 56 +++++++++++-------- packages/cli/tests/commands/deploy.spec.ts | 62 +++++++++++++++++++--- 2 files changed, 90 insertions(+), 28 deletions(-) diff --git a/packages/cli/src/commands/deploy.ts b/packages/cli/src/commands/deploy.ts index a16629a53f..dc9d5fdc73 100644 --- a/packages/cli/src/commands/deploy.ts +++ b/packages/cli/src/commands/deploy.ts @@ -60,10 +60,10 @@ const DeploymentStatusSchema = z.object({ .optional(), }); -export const generateBundleZip = async (rootDir: string) => { +export const generateBundleZip = async () => { consola.info('Generating bundle...'); - const distDir = join(rootDir, '.bigcommerce/dist'); + const distDir = join(process.cwd(), '.bigcommerce', 'dist'); // Check if .bigcommerce/dist exists try { @@ -122,10 +122,10 @@ export const generateUploadSignature = async ( return data; }; -export const uploadBundleZip = async (uploadUrl: string, rootDir: string) => { +export const uploadBundleZip = async (uploadUrl: string) => { consola.info('Uploading bundle...'); - const zipPath = join(rootDir, '.bigcommerce/dist/bundle.zip'); + const zipPath = join(process.cwd(), '.bigcommerce', 'dist', 'bundle.zip'); // Read the zip file as a buffer const fileBuffer = await readFile(zipPath); @@ -287,18 +287,15 @@ export const deploy = new Command('deploy') 'BigCommerce headless project UUID. Can be found via the BigCommerce API (GET /v3/infrastructure/projects).', ).env('BIGCOMMERCE_PROJECT_UUID'), ) - .option( - '--root-dir ', - 'Path to the root directory of your Catalyst project (default: current working directory).', - process.cwd(), - ) - .action(async (opts) => { + .option('--dry-run', 'Run the command to generate the bundle without uploading or deploying.') + + .action(async (options) => { try { - const config = getProjectConfig(opts.rootDir); + const config = getProjectConfig(); - await telemetry.identify(opts.storeHash); + await telemetry.identify(options.storeHash); - const projectUuid = opts.projectUuid ?? config.get('projectUuid'); + const projectUuid = options.projectUuid ?? config.get('projectUuid'); if (!projectUuid) { throw new Error( @@ -306,25 +303,40 @@ export const deploy = new Command('deploy') ); } - await generateBundleZip(opts.rootDir); + await generateBundleZip(); + + if (options.dryRun) { + consola.info('Dry run enabled — skipping upload and deployment steps.'); + consola.info('Next steps (skipped):'); + consola.info('- Generate upload signature'); + consola.info('- Upload bundle.zip'); + consola.info('- Create deployment'); + + process.exit(0); + } const uploadSignature = await generateUploadSignature( - opts.storeHash, - opts.accessToken, - opts.apiHost, + options.storeHash, + options.accessToken, + options.apiHost, ); - await uploadBundleZip(uploadSignature.upload_url, opts.rootDir); + await uploadBundleZip(uploadSignature.upload_url); const { deployment_uuid: deploymentUuid } = await createDeployment( projectUuid, uploadSignature.upload_uuid, - opts.storeHash, - opts.accessToken, - opts.apiHost, + options.storeHash, + options.accessToken, + options.apiHost, ); - await getDeploymentStatus(deploymentUuid, opts.storeHash, opts.accessToken, opts.apiHost); + await getDeploymentStatus( + deploymentUuid, + options.storeHash, + options.accessToken, + options.apiHost, + ); } catch (error) { consola.error(error); process.exit(1); diff --git a/packages/cli/tests/commands/deploy.spec.ts b/packages/cli/tests/commands/deploy.spec.ts index fea0a708f4..7a80b28806 100644 --- a/packages/cli/tests/commands/deploy.spec.ts +++ b/packages/cli/tests/commands/deploy.spec.ts @@ -2,9 +2,19 @@ import AdmZip from 'adm-zip'; import { Command } from 'commander'; import consola from 'consola'; import { http, HttpResponse } from 'msw'; -import { mkdir, stat, writeFile } from 'node:fs/promises'; +import { mkdir, realpath, stat, writeFile } from 'node:fs/promises'; import { dirname, join } from 'node:path'; -import { afterAll, afterEach, beforeAll, describe, expect, test, vi } from 'vitest'; +import { + afterAll, + afterEach, + beforeAll, + beforeEach, + describe, + expect, + MockInstance, + test, + vi, +} from 'vitest'; import { createDeployment, @@ -15,12 +25,15 @@ import { uploadBundleZip, } from '../../src/commands/deploy'; import { mkTempDir } from '../../src/lib/mk-temp-dir'; +import { program } from '../../src/program'; import { server } from '../mocks/node'; import { textHistory } from '../mocks/spinner'; // eslint-disable-next-line import/dynamic-import-chunkname vi.mock('yocto-spinner', () => import('../mocks/spinner')); +let exitMock: MockInstance; + let tmpDir: string; let cleanup: () => Promise; let outputZip: string; @@ -35,9 +48,14 @@ const deploymentUuid = '5b29c3c0-5f68-44fe-99e5-06492babf7be'; beforeAll(async () => { consola.mockTypes(() => vi.fn()); + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + exitMock = vi.spyOn(process, 'exit').mockImplementation(() => null as never); [tmpDir, cleanup] = await mkTempDir(); + // Normalize to /private/var to avoid /var vs /private/var mismatches + tmpDir = await realpath(tmpDir); + const workerPath = join(tmpDir, '.bigcommerce/dist/worker.js'); const assetsDir = join(tmpDir, '.bigcommerce/dist/assets'); @@ -49,6 +67,10 @@ beforeAll(async () => { await writeFile(join(assetsDir, 'test.txt'), 'asset file'); }); +beforeEach(() => { + process.chdir(tmpDir); +}); + afterEach(() => { vi.clearAllMocks(); @@ -70,14 +92,14 @@ test('properly configured Command instance', () => { expect.objectContaining({ flags: '--access-token ' }), expect.objectContaining({ flags: '--api-host ', defaultValue: 'api.bigcommerce.com' }), expect.objectContaining({ flags: '--project-uuid ' }), - expect.objectContaining({ flags: '--root-dir ', defaultValue: process.cwd() }), + expect.objectContaining({ flags: '--dry-run' }), ]), ); }); describe('bundle zip generation and upload', () => { test('creates bundle.zip from build output', async () => { - await generateBundleZip(tmpDir); + await generateBundleZip(); // Check file exists const stats = await stat(outputZip); @@ -89,7 +111,7 @@ describe('bundle zip generation and upload', () => { }); test('zip contains output folder with assets and worker.js', async () => { - await generateBundleZip(tmpDir); + await generateBundleZip(); // Check file exists const stats = await stat(outputZip); @@ -120,7 +142,7 @@ describe('bundle zip generation and upload', () => { }); test('fetches upload signature and uploads bundle zip', async () => { - const uploadResult = await uploadBundleZip(uploadUrl, tmpDir); + const uploadResult = await uploadBundleZip(uploadUrl); expect(consola.info).toHaveBeenCalledWith('Uploading bundle...'); expect(consola.success).toHaveBeenCalledWith('Bundle uploaded successfully.'); @@ -250,3 +272,31 @@ describe('deployment and event streaming', () => { expect(textHistory).toEqual(['Fetching...', 'Processing...']); }); }); + +test('--dry-run skips upload and deployment', async () => { + await program.parseAsync([ + 'node', + 'catalyst', + 'deploy', + '--store-hash', + storeHash, + '--access-token', + accessToken, + '--api-host', + apiHost, + '--project-uuid', + projectUuid, + '--dry-run', + ]); + + expect(consola.info).toHaveBeenCalledWith('Generating bundle...'); + expect(consola.success).toHaveBeenCalledWith(`Bundle created at: ${outputZip}`); + expect(consola.info).toHaveBeenCalledWith( + 'Dry run enabled — skipping upload and deployment steps.', + ); + expect(consola.info).toHaveBeenCalledWith('Next steps (skipped):'); + expect(consola.info).toHaveBeenCalledWith('- Generate upload signature'); + expect(consola.info).toHaveBeenCalledWith('- Upload bundle.zip'); + expect(consola.info).toHaveBeenCalledWith('- Create deployment'); + expect(exitMock).toHaveBeenCalledWith(0); +}); From 7c449c225b60ea2ca6bc3ee73343f4390543691a Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Fri, 22 Aug 2025 14:29:22 -0500 Subject: [PATCH 028/245] feat(cli): allow creation of project in link command (#2539) --- packages/cli/src/commands/deploy.ts | 2 +- packages/cli/src/commands/link.ts | 100 ++++++++++++++++--- packages/cli/tests/commands/link.spec.ts | 118 ++++++++++++++++++++--- packages/cli/tests/mocks/handlers.ts | 12 +++ 4 files changed, 206 insertions(+), 26 deletions(-) diff --git a/packages/cli/src/commands/deploy.ts b/packages/cli/src/commands/deploy.ts index dc9d5fdc73..76a4b108c8 100644 --- a/packages/cli/src/commands/deploy.ts +++ b/packages/cli/src/commands/deploy.ts @@ -284,7 +284,7 @@ export const deploy = new Command('deploy') .addOption( new Option( '--project-uuid ', - 'BigCommerce headless project UUID. Can be found via the BigCommerce API (GET /v3/infrastructure/projects).', + 'BigCommerce intrastructure project UUID. Can be found via the BigCommerce API (GET /v3/infrastructure/projects).', ).env('BIGCOMMERCE_PROJECT_UUID'), ) .option('--dry-run', 'Run the command to generate the bundle without uploading or deploying.') diff --git a/packages/cli/src/commands/link.ts b/packages/cli/src/commands/link.ts index 5706c01820..86ee35f508 100644 --- a/packages/cli/src/commands/link.ts +++ b/packages/cli/src/commands/link.ts @@ -16,6 +16,15 @@ const fetchProjectsSchema = z.object({ ), }); +const createProjectSchema = z.object({ + data: z.object({ + uuid: z.string(), + name: z.string(), + date_created: z.coerce.date(), + date_modified: z.coerce.date(), + }), +}); + async function fetchProjects(storeHash: string, accessToken: string, apiHost: string) { const response = await fetch( `https://${apiHost}/stores/${storeHash}/v3/infrastructure/projects`, @@ -27,9 +36,9 @@ async function fetchProjects(storeHash: string, accessToken: string, apiHost: st }, ); - if (response.status === 404) { + if (response.status === 403) { throw new Error( - 'Headless Projects API not enabled. If you are part of the alpha, contact support@bigcommerce.com to enable it.', + 'Infrastructure Projects API not enabled. If you are part of the alpha, contact support@bigcommerce.com to enable it.', ); } @@ -44,9 +53,49 @@ async function fetchProjects(storeHash: string, accessToken: string, apiHost: st return data; } +async function createProject( + name: string, + storeHash: string, + accessToken: string, + apiHost: string, +) { + const response = await fetch( + `https://${apiHost}/stores/${storeHash}/v3/infrastructure/projects`, + { + method: 'POST', + headers: { + 'X-Auth-Token': accessToken, + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ name }), + }, + ); + + if (response.status === 502) { + throw new Error('Failed to create project, is the name already in use?'); + } + + if (response.status === 403) { + throw new Error( + 'Infrastructure Projects API not enabled. If you are part of the alpha, contact support@bigcommerce.com to enable it.', + ); + } + + if (!response.ok) { + throw new Error(`Failed to create project: ${response.statusText}`); + } + + const res: unknown = await response.json(); + + const { data } = createProjectSchema.parse(res); + + return data; +} + export const link = new Command('link') .description( - 'Link your local Catalyst project to a BigCommerce headless project. You can provide a project UUID directly, or fetch and select from available projects using your store credentials.', + 'Link your local Catalyst project to a BigCommerce infrastructure project. You can provide a project UUID directly, or fetch and select from available projects using your store credentials.', ) .addOption( new Option( @@ -67,7 +116,7 @@ export const link = new Command('link') ) .option( '--project-uuid ', - 'BigCommerce headless project UUID. Can be found via the BigCommerce API (GET /v3/infrastructure/projects). Use this to link directly without fetching projects.', + 'BigCommerce infrastructure project UUID. Can be found via the BigCommerce API (GET /v3/infrastructure/projects). Use this to link directly without fetching projects.', ) .option( '--root-dir ', @@ -104,19 +153,44 @@ export const link = new Command('link') consola.success('Projects fetched.'); - if (!projects.length) { - throw new Error('No headless projects found for this store.'); - } - - const projectUuid = await consola.prompt('Select a project (Press to select).', { - type: 'select', - options: projects.map((project) => ({ + const promptOptions = [ + ...projects.map((project) => ({ label: project.name, value: project.uuid, hint: project.uuid, })), - cancel: 'reject', - }); + { + label: 'Create a new project', + value: 'create', + hint: 'Create a new infrastructure project for this BigCommerce store.', + }, + ]; + + let projectUuid = await consola.prompt( + 'Select a project or create a new project (Press to select).', + { + type: 'select', + options: promptOptions, + cancel: 'reject', + }, + ); + + if (projectUuid === 'create') { + const newProjectName = await consola.prompt('Enter a name for the new project:', { + type: 'text', + }); + + const data = await createProject( + newProjectName, + options.storeHash, + options.accessToken, + options.apiHost, + ); + + projectUuid = data.uuid; + + consola.success(`Project "${data.name}" created successfully.`); + } writeProjectConfig(projectUuid); diff --git a/packages/cli/tests/commands/link.spec.ts b/packages/cli/tests/commands/link.spec.ts index fec49e6c48..0f6d4169d2 100644 --- a/packages/cli/tests/commands/link.spec.ts +++ b/packages/cli/tests/commands/link.spec.ts @@ -22,6 +22,7 @@ const { mockIdentify } = vi.hoisted(() => ({ const projectUuid1 = 'a23f5785-fd99-4a94-9fb3-945551623923'; const projectUuid2 = 'b23f5785-fd99-4a94-9fb3-945551623924'; +const projectUuid3 = 'c23f5785-fd99-4a94-9fb3-945551623925'; const storeHash = 'test-store'; const accessToken = 'test-token'; @@ -66,7 +67,7 @@ test('properly configured Command instance', () => { expect(link).toBeInstanceOf(Command); expect(link.name()).toBe('link'); expect(link.description()).toBe( - 'Link your local Catalyst project to a BigCommerce headless project. You can provide a project UUID directly, or fetch and select from available projects using your store credentials.', + 'Link your local Catalyst project to a BigCommerce infrastructure project. You can provide a project UUID directly, or fetch and select from available projects using your store credentials.', ); expect(link.options).toEqual( expect.arrayContaining([ @@ -106,17 +107,20 @@ test('fetches projects and prompts user to select one', async () => { .spyOn(consola, 'prompt') .mockImplementation(async (message, opts) => { // Assert the prompt message and options - expect(message).toContain('Select a project (Press to select).'); + expect(message).toContain( + 'Select a project or create a new project (Press to select).', + ); // eslint-disable-next-line @typescript-eslint/consistent-type-assertions const options = (opts as { options: Array<{ label: string; value: string }> }).options; - expect(options).toHaveLength(2); + expect(options).toHaveLength(3); expect(options[0]).toMatchObject({ label: 'Project One', value: projectUuid1 }); expect(options[1]).toMatchObject({ label: 'Project Two', value: projectUuid2, }); + expect(options[2]).toMatchObject({ label: 'Create a new project', value: 'create' }); // Simulate selecting the second option return new Promise((resolve) => resolve(projectUuid2)); @@ -154,15 +158,97 @@ test('fetches projects and prompts user to select one', async () => { consolaPromptMock.mockRestore(); }); -test('errors when no projects are found', async () => { +test('prompts to create a new project', async () => { + const consolaPromptMock = vi + .spyOn(consola, 'prompt') + .mockImplementationOnce(async (message, opts) => { + // Assert the prompt message and options + expect(message).toContain( + 'Select a project or create a new project (Press to select).', + ); + + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + const options = (opts as { options: Array<{ label: string; value: string }> }).options; + + expect(options).toHaveLength(3); + expect(options[0]).toMatchObject({ label: 'Project One', value: projectUuid1 }); + expect(options[1]).toMatchObject({ + label: 'Project Two', + value: projectUuid2, + }); + expect(options[2]).toMatchObject({ label: 'Create a new project', value: 'create' }); + + // Simulate selecting the create option + return new Promise((resolve) => resolve('create')); + }) + .mockImplementationOnce(async (message) => { + expect(message).toBe('Enter a name for the new project:'); + + return new Promise((resolve) => resolve('New Project')); + }); + + await program.parseAsync([ + 'node', + 'catalyst', + 'link', + '--store-hash', + storeHash, + '--access-token', + accessToken, + '--root-dir', + tmpDir, + ]); + + expect(mockIdentify).toHaveBeenCalledWith(storeHash); + + expect(consola.start).toHaveBeenCalledWith('Fetching projects...'); + expect(consola.success).toHaveBeenCalledWith('Projects fetched.'); + + expect(consola.success).toHaveBeenCalledWith('Project "New Project" created successfully.'); + + expect(exitMock).toHaveBeenCalledWith(0); + + expect(config.get('projectUuid')).toBe(projectUuid3); + expect(config.get('framework')).toBe('catalyst'); + + consolaPromptMock.mockRestore(); +}); + +test('prompts to create a new project', async () => { server.use( - http.get('https://:apiHost/stores/:storeHash/v3/infrastructure/projects', () => - HttpResponse.json({ - data: [], - }), + http.post('https://:apiHost/stores/:storeHash/v3/infrastructure/projects', () => + HttpResponse.json({}, { status: 502 }), ), ); + const consolaPromptMock = vi + .spyOn(consola, 'prompt') + .mockImplementationOnce(async (message, opts) => { + // Assert the prompt message and options + expect(message).toContain( + 'Select a project or create a new project (Press to select).', + ); + + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + const options = (opts as { options: Array<{ label: string; value: string }> }).options; + + expect(options).toHaveLength(3); + expect(options[0]).toMatchObject({ label: 'Project One', value: projectUuid1 }); + expect(options[1]).toMatchObject({ + label: 'Project Two', + value: projectUuid2, + }); + expect(options[2]).toMatchObject({ label: 'Create a new project', value: 'create' }); + + // Simulate selecting the create option + return new Promise((resolve) => resolve('create')); + }) + .mockImplementationOnce(async (message) => { + expect(message).toBe('Enter a name for the new project:'); + + return new Promise((resolve) => resolve('New Project')); + }); + await program.parseAsync([ 'node', 'catalyst', @@ -178,16 +264,24 @@ test('errors when no projects are found', async () => { expect(mockIdentify).toHaveBeenCalledWith(storeHash); expect(consola.start).toHaveBeenCalledWith('Fetching projects...'); - expect(consola.error).toHaveBeenCalledWith('No headless projects found for this store.'); + expect(consola.success).toHaveBeenCalledWith('Projects fetched.'); + + expect(consola.error).toHaveBeenCalledWith( + 'Failed to create project, is the name already in use?', + ); + expect(exitMock).toHaveBeenCalledWith(1); + + consolaPromptMock.mockRestore(); }); -test('errors when headless projects API is not found', async () => { +test('errors when infrastructure projects API is not found', async () => { server.use( http.get('https://:apiHost/stores/:storeHash/v3/infrastructure/projects', () => - HttpResponse.json({}, { status: 404 }), + HttpResponse.json({}, { status: 403 }), ), ); + await program.parseAsync([ 'node', 'catalyst', @@ -204,7 +298,7 @@ test('errors when headless projects API is not found', async () => { expect(consola.start).toHaveBeenCalledWith('Fetching projects...'); expect(consola.error).toHaveBeenCalledWith( - 'Headless Projects API not enabled. If you are part of the alpha, contact support@bigcommerce.com to enable it.', + 'Infrastructure Projects API not enabled. If you are part of the alpha, contact support@bigcommerce.com to enable it.', ); }); diff --git a/packages/cli/tests/mocks/handlers.ts b/packages/cli/tests/mocks/handlers.ts index 4863fa2e7b..a2a46c3b42 100644 --- a/packages/cli/tests/mocks/handlers.ts +++ b/packages/cli/tests/mocks/handlers.ts @@ -73,4 +73,16 @@ export const handlers = [ }); }, ), + + // Handle for createProjects + http.post('https://:apiHost/stores/:storeHash/v3/infrastructure/projects', () => + HttpResponse.json({ + data: { + uuid: 'c23f5785-fd99-4a94-9fb3-945551623925', + name: 'New Project', + date_created: new Date().toISOString(), + date_modified: new Date().toISOString(), + }, + }), + ), ]; From 33b574d2fefe8514c4e512acf3f706058a6c8a2f Mon Sep 17 00:00:00 2001 From: Nathan Booker Date: Sat, 23 Aug 2025 08:47:15 -0700 Subject: [PATCH 029/245] feat: replace Vercel KV adapter with Vercel Runtime Cache API (#2475) --- .changeset/chatty-forks-sniff.md | 5 + core/lib/kv/adapters/bc.ts | 101 ------------- core/lib/kv/adapters/upstash.ts | 11 +- core/lib/kv/adapters/vercel-runtime-cache.ts | 78 ++++++++++ core/lib/kv/adapters/vercel.ts | 30 ---- core/lib/kv/index.ts | 13 +- core/package.json | 4 +- pnpm-lock.yaml | 149 +++++++++++-------- 8 files changed, 175 insertions(+), 216 deletions(-) create mode 100644 .changeset/chatty-forks-sniff.md delete mode 100644 core/lib/kv/adapters/bc.ts create mode 100644 core/lib/kv/adapters/vercel-runtime-cache.ts delete mode 100644 core/lib/kv/adapters/vercel.ts diff --git a/.changeset/chatty-forks-sniff.md b/.changeset/chatty-forks-sniff.md new file mode 100644 index 0000000000..b33770c5e1 --- /dev/null +++ b/.changeset/chatty-forks-sniff.md @@ -0,0 +1,5 @@ +--- +"@bigcommerce/catalyst-core": minor +--- + +Implement Vercel Runtime Cache API as replacement for Vercel KV adapter diff --git a/core/lib/kv/adapters/bc.ts b/core/lib/kv/adapters/bc.ts deleted file mode 100644 index ead6ff7f1f..0000000000 --- a/core/lib/kv/adapters/bc.ts +++ /dev/null @@ -1,101 +0,0 @@ -/* eslint-disable max-classes-per-file */ -/* eslint-disable @typescript-eslint/consistent-type-assertions */ -import { KvAdapter } from '../types'; - -class Kv { - private endpoint: string; - private apiKey: string; - - constructor() { - if (!process.env.BC_KV_REST_API_URL) { - throw new Error('BC_KV_REST_API_URL is not set'); - } - - if (!process.env.BC_KV_REST_API_TOKEN) { - throw new Error('BC_KV_REST_API_TOKEN is not set'); - } - - this.endpoint = process.env.BC_KV_REST_API_URL; - this.apiKey = process.env.BC_KV_REST_API_TOKEN; - } - - async get(key: string): Promise { - const [value] = await this.mget<[T]>([key]); - - return value; - } - - async mget(keys: string[]): Promise<{ [K in keyof T]: T[K] | null }> { - const normalizedKeys = Array.isArray(keys) ? keys : [keys]; - - const url = new URL(this.endpoint); - - normalizedKeys.forEach((key) => url.searchParams.append('key', key)); - - const response = await fetch(url, { - headers: { 'x-api-key': this.apiKey }, - }); - - if (!response.ok) { - throw new Error(`Failed to fetch keys: ${response.statusText}`); - } - - const { data } = (await response.json()) as { data: Array<{ key: string; value: unknown }> }; - - return data.map(({ value }) => value) as { [K in keyof T]: T[K] | null }; - } - - async set(key: string, value: unknown, ttlMs?: number): Promise { - return this.mset([{ key, value, ttlMs }]); - } - - async mset(data: Array<{ key: string; value: unknown; ttlMs?: number }>): Promise { - const response = await fetch(this.endpoint, { - method: 'PUT', - headers: { - 'Content-Type': 'application/json', - 'x-api-key': this.apiKey, - }, - body: JSON.stringify(data), - }); - - if (!response.ok) { - throw new Error(`Failed to put keys: ${response.statusText}`); - } - } - - async delete(key: string): Promise { - return this.mdelete([key]); - } - - async mdelete(keys: string[]): Promise { - const url = new URL(this.endpoint); - - keys.forEach((key) => url.searchParams.append('key', key)); - - const response = await fetch(url, { - method: 'DELETE', - headers: { 'x-api-key': this.apiKey }, - }); - - if (!response.ok) { - throw new Error(`Failed to delete keys: ${response.statusText}`); - } - } -} - -export class BcKvAdapter implements KvAdapter { - private kv = new Kv(); - - async mget(...keys: string[]) { - const values = await this.kv.mget(keys); - - return values; - } - - async set(key: string, value: Data, opts?: { ttlMs?: number }) { - await this.kv.set(key, value, opts?.ttlMs); - - return value; - } -} diff --git a/core/lib/kv/adapters/upstash.ts b/core/lib/kv/adapters/upstash.ts index 2922f14328..3bcb3d8ac2 100644 --- a/core/lib/kv/adapters/upstash.ts +++ b/core/lib/kv/adapters/upstash.ts @@ -2,23 +2,14 @@ import { Redis } from '@upstash/redis'; import { KvAdapter, SetCommandOptions } from '../types'; -import { MemoryKvAdapter } from './memory'; - -const memoryKv = new MemoryKvAdapter(); - export class UpstashKvAdapter implements KvAdapter { private upstashKv = Redis.fromEnv(); - private memoryKv = memoryKv; async mget(...keys: string[]) { - const memoryValues = await this.memoryKv.mget(...keys); - - return memoryValues.length ? memoryValues : this.upstashKv.mget(keys); + return this.upstashKv.mget(keys); } async set(key: string, value: Data, opts?: SetCommandOptions) { - await this.memoryKv.set(key, value, opts); - const response = await this.upstashKv.set(key, value, opts); if (response === 'OK') { diff --git a/core/lib/kv/adapters/vercel-runtime-cache.ts b/core/lib/kv/adapters/vercel-runtime-cache.ts new file mode 100644 index 0000000000..21fcf326d2 --- /dev/null +++ b/core/lib/kv/adapters/vercel-runtime-cache.ts @@ -0,0 +1,78 @@ +import { getCache } from '@vercel/functions'; + +import { KvAdapter, SetCommandOptions } from '../types'; + +export class RuntimeCacheAdapter implements KvAdapter { + private cache = getCache(); + + async mget(...keys: string[]): Promise> { + this.logger( + `MGET - Keys: ${keys.toString()} - Source: RUNTIME_CACHE - Fetching ${keys.length} keys`, + ); + + try { + const values = await Promise.all( + keys.map(async (key) => { + try { + // Use the Runtime Cache API + const cachedValue = await this.cache.get(key); + + if (cachedValue !== null) { + this.logger(`RUNTIME_CACHE GET - Key: ${key} - Found: true`); + + return cachedValue; + } + + this.logger(`RUNTIME_CACHE GET - Key: ${key} - Found: false`); + + return null; + } catch (error) { + this.logger( + `RUNTIME_CACHE GET ERROR - Key: ${key} - Error: ${error instanceof Error ? error.message : 'Unknown error'}`, + ); + + return null; + } + }), + ); + + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + return values as Array; + } catch (error) { + this.logger( + `RUNTIME_CACHE ACCESS ERROR - Returning null values: ${error instanceof Error ? error.message : 'Unknown error'}`, + ); + + // Return null for all keys if Runtime Cache is unavailable + return keys.map(() => null); + } + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + async set(key: string, value: Data, _opts?: SetCommandOptions): Promise { + this.logger(`SET - Key: ${key} - Setting in runtime cache`); + + try { + await this.cache.set(key, value); + this.logger(`RUNTIME_CACHE SET - Key: ${key} - Success`); + } catch (error) { + this.logger( + `RUNTIME_CACHE SET ERROR - Key: ${key} - Error: ${error instanceof Error ? error.message : 'Unknown error'}`, + ); + } + + return value; + } + + private logger(message: string) { + // Check if logging is enabled using the same logic as the main KV class + const loggingEnabled = + (process.env.NODE_ENV !== 'production' && process.env.KV_LOGGER !== 'false') || + process.env.KV_LOGGER === 'true'; + + if (loggingEnabled) { + // eslint-disable-next-line no-console + console.log(`[BigCommerce] Runtime Cache ${message}`); + } + } +} diff --git a/core/lib/kv/adapters/vercel.ts b/core/lib/kv/adapters/vercel.ts deleted file mode 100644 index eb26ea6e3e..0000000000 --- a/core/lib/kv/adapters/vercel.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { kv } from '@vercel/kv'; - -import { KvAdapter, SetCommandOptions } from '../types'; - -import { MemoryKvAdapter } from './memory'; - -const memoryKv = new MemoryKvAdapter(); - -export class VercelKvAdapter implements KvAdapter { - private vercelKv = kv; - private memoryKv = memoryKv; - - async mget(...keys: string[]) { - const memoryValues = await this.memoryKv.mget(...keys); - - return memoryValues.length ? memoryValues : this.vercelKv.mget(keys); - } - - async set(key: string, value: Data, opts?: SetCommandOptions) { - await this.memoryKv.set(key, value, opts); - - const response = await this.vercelKv.set(key, value, opts); - - if (response === 'OK') { - return null; - } - - return response; - } -} diff --git a/core/lib/kv/index.ts b/core/lib/kv/index.ts index 42472c2eaa..d3d1baa221 100644 --- a/core/lib/kv/index.ts +++ b/core/lib/kv/index.ts @@ -82,16 +82,11 @@ class KV implements KvAdapter { } async function createKVAdapter() { - if (process.env.BC_KV_REST_API_URL && process.env.BC_KV_REST_API_TOKEN) { - const { BcKvAdapter } = await import('./adapters/bc'); + // Prioritize Runtime Cache for Vercel environments + if (process.env.VERCEL === '1') { + const { RuntimeCacheAdapter } = await import('./adapters/vercel-runtime-cache'); - return new BcKvAdapter(); - } - - if (process.env.KV_REST_API_URL && process.env.KV_REST_API_TOKEN) { - const { VercelKvAdapter } = await import('./adapters/vercel'); - - return new VercelKvAdapter(); + return new RuntimeCacheAdapter(); } if (process.env.UPSTASH_REDIS_REST_URL && process.env.UPSTASH_REDIS_REST_TOKEN) { diff --git a/core/package.json b/core/package.json index 6fa087c3fb..fa630f1902 100644 --- a/core/package.json +++ b/core/package.json @@ -34,7 +34,7 @@ "@t3-oss/env-core": "^0.13.6", "@upstash/redis": "^1.35.0", "@vercel/analytics": "^1.5.0", - "@vercel/kv": "^3.0.0", + "@vercel/functions": "^2.2.12", "@vercel/speed-insights": "^1.2.0", "clsx": "^2.1.1", "content-security-policy-builder": "^2.3.0", @@ -50,7 +50,7 @@ "lodash.debounce": "^4.0.8", "lru-cache": "^11.1.0", "lucide-react": "^0.474.0", - "next": "15.4.2-canary.10", + "next": "15.5.1-canary.4", "next-auth": "5.0.0-beta.25", "next-intl": "^4.1.0", "nuqs": "^2.4.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6d23bb5682..af596a2554 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -97,13 +97,13 @@ importers: version: 1.35.0 '@vercel/analytics': specifier: ^1.5.0 - version: 1.5.0(next@15.4.2-canary.10(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)(svelte@5.1.15)(vue@3.5.16(typescript@5.8.3)) - '@vercel/kv': - specifier: ^3.0.0 - version: 3.0.0 + version: 1.5.0(next@15.5.1-canary.4(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)(svelte@5.1.15)(vue@3.5.16(typescript@5.8.3)) + '@vercel/functions': + specifier: ^2.2.12 + version: 2.2.12(@aws-sdk/credential-provider-web-identity@3.864.0) '@vercel/speed-insights': specifier: ^1.2.0 - version: 1.2.0(next@15.4.2-canary.10(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)(svelte@5.1.15)(vue@3.5.16(typescript@5.8.3)) + version: 1.2.0(next@15.5.1-canary.4(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)(svelte@5.1.15)(vue@3.5.16(typescript@5.8.3)) clsx: specifier: ^2.1.1 version: 2.1.1 @@ -147,17 +147,17 @@ importers: specifier: ^0.474.0 version: 0.474.0(react@19.1.0) next: - specifier: 15.4.2-canary.10 - version: 15.4.2-canary.10(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + specifier: 15.5.1-canary.4 + version: 15.5.1-canary.4(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) next-auth: specifier: 5.0.0-beta.25 - version: 5.0.0-beta.25(next@15.4.2-canary.10(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(nodemailer@6.9.16)(react@19.1.0) + version: 5.0.0-beta.25(next@15.5.1-canary.4(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(nodemailer@6.9.16)(react@19.1.0) next-intl: specifier: ^4.1.0 - version: 4.1.0(next@15.4.2-canary.10(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)(typescript@5.8.3) + version: 4.1.0(next@15.5.1-canary.4(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)(typescript@5.8.3) nuqs: specifier: ^2.4.3 - version: 2.4.3(next@15.4.2-canary.10(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0) + version: 2.4.3(next@15.5.1-canary.4(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0) p-lazy: specifier: ^5.0.0 version: 5.0.0 @@ -2408,8 +2408,8 @@ packages: '@next/bundle-analyzer@15.2.3': resolution: {integrity: sha512-alZemRg2ciCTmT2WUbzy1M9H4luzmmlyZtdB4tHDA+qoD4WTNEwty+oxn3oIzDzIiMvOaODXUNdMrYsFnsAdEA==} - '@next/env@15.4.2-canary.10': - resolution: {integrity: sha512-bofkSHw9RaLB04cjZoYxN1nPFlg11Lh+Op9O/ZcNC5Pvv/WYO0FLNDEqp9f3oiOCjQ80AT0S2vE46h3QJw5yzA==} + '@next/env@15.5.1-canary.4': + resolution: {integrity: sha512-2btxnxNqEUfRsaEi0I5WNLf+ly0ihit+cxQZzhvnO9XxeXlTr4PAvDt7nuiDki6wCg6tniApjodqq6DhFp8NNA==} '@next/eslint-plugin-next@15.2.3': resolution: {integrity: sha512-eNSOIMJtjs+dp4Ms1tB1PPPJUQHP3uZK+OQ7iFY9qXpGO6ojT6imCL+KcUOqE/GXGidWbBZJzYdgAdPHqeCEPA==} @@ -2417,50 +2417,50 @@ packages: '@next/eslint-plugin-next@15.3.3': resolution: {integrity: sha512-VKZJEiEdpKkfBmcokGjHu0vGDG+8CehGs90tBEy/IDoDDKGngeyIStt2MmE5FYNyU9BhgR7tybNWTAJY/30u+Q==} - '@next/swc-darwin-arm64@15.4.2-canary.10': - resolution: {integrity: sha512-FzYUTMD//39UJxi86NiIH0owG7dpp06pxP7JSaEzSvXP8mgf/vKQnTUvlRXnqMDYxqXpnDYEG8hrM3gusjX10g==} + '@next/swc-darwin-arm64@15.5.1-canary.4': + resolution: {integrity: sha512-beD8em1X39AzJ8I6xRnt89Q/hN3OvuUkJDey8/cYduoHhCxmdXpNY82jS1UslN8v192cEj4O7kNPWLlBrw9jpg==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@15.4.2-canary.10': - resolution: {integrity: sha512-Klw9YJRfoCxR3x57bcBn9aqbiN/4+ielLw44LHrnZ4uwUCOkSSmil3LBkHuD25IRpTs1CkJ2lvRmvZaBQmwDLg==} + '@next/swc-darwin-x64@15.5.1-canary.4': + resolution: {integrity: sha512-kriC0AVGMK/5ZXT+D7VTn7inU/ZtcUNfJPKPjcZIU2Wh+CIi2WzBUlUXnMsSv4fZgiuNhBi8M4y2FK0XB/r/bg==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@15.4.2-canary.10': - resolution: {integrity: sha512-WNftmm/A2HpcsxJMRkzLzHRjhUx9baIMfTLRiedEo1b9RZJ7KJF6JTXFANhv/AVbAYPMcxM8rFvCA3Qjm0WuMQ==} + '@next/swc-linux-arm64-gnu@15.5.1-canary.4': + resolution: {integrity: sha512-YVP8w7ihF9W84uAAVplORLI0JTvz1MkoR3AZVibQC2vxi9kTRdHvajam3N0/mDWSUj5d/IQtKRhGrPYk6WVmdg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@15.4.2-canary.10': - resolution: {integrity: sha512-GtB34+Ld9Iv9Wb2RuhXFoHqEbrrCms9RljFmbEFZi2rG+xzIgU9rm8a+YK8iu52XPjGONPmmCY5qqxGbm8mU0w==} + '@next/swc-linux-arm64-musl@15.5.1-canary.4': + resolution: {integrity: sha512-Eq3Koc7ZYkpNviFCs5rDmrnWt6ar60lGtxlZcnJ2jIGzVEYB/9H/dbr9SmHJx8XdGo4dtVL8ycCR/sq+7E7npg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-x64-gnu@15.4.2-canary.10': - resolution: {integrity: sha512-b54SR8ufT9hG9NdcVMwnvCq41icpGiIASzRypjhCWfo8q9yStIrigTNPtNTu0TGIB8CmeT6qSIb7/m4DSukahQ==} + '@next/swc-linux-x64-gnu@15.5.1-canary.4': + resolution: {integrity: sha512-o9H72MJ3fHJTvwjVpZbGCt4470wtf3a8GvLNRVWzE08qtBl5bevnZvSFXEIIK+q24GBjGsOs9ZbGrPJ/utuZog==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@15.4.2-canary.10': - resolution: {integrity: sha512-3v8EPS7OZoYugP6m6Pmza6W8b5V32PKbME1pjLkpv6sJ81kEI+7Y7BRdcDlPFPy5QgJxFj1AhTXfjslEuaWcxA==} + '@next/swc-linux-x64-musl@15.5.1-canary.4': + resolution: {integrity: sha512-ylFXmESywoXVT1vz/TuWCAHgvxJci5vvl9EbhIKtCU5PLkrWT54MOYVK9PpHPvn362wThhhbDBaI3DfTVO1U7A==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-win32-arm64-msvc@15.4.2-canary.10': - resolution: {integrity: sha512-zsRSGNhxNWE9bhwQviHOGNEexDjOpDRaY11qBqsttqwiQRvF/EBNDGVQnZaTCMQiOzjLd0Rw6aVMv3R/saFu0Q==} + '@next/swc-win32-arm64-msvc@15.5.1-canary.4': + resolution: {integrity: sha512-B9BMD55FWPqdDWgkXvxgRgRbzHK0yKLzhR3xw12f0VR0mD/XIqmZndqZwy0cCFld9Q1AoT+sSmY4DUC+Rw9T1Q==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@15.4.2-canary.10': - resolution: {integrity: sha512-J6JpJoCwpJ0XMnRefkyTO6wJm1fz+oVQYbHL8zt2Yjt2k3KVN33GlDyFb9vxlg61Nj21OKAceftYp5TgZLfhfQ==} + '@next/swc-win32-x64-msvc@15.5.1-canary.4': + resolution: {integrity: sha512-4l2s0r1LL90aK/fOXvbyWV9nskkJb3TCvFx27T/nrsMRYsDzF3kcDi1S3VQ4lICznZ6igU8Ubm1yDZzb++QvvQ==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -3914,6 +3914,9 @@ packages: '@types/lodash@4.17.5': resolution: {integrity: sha512-MBIOHVZqVqgfro1euRDWX7OO0fBVUUMrN6Pwm8LQsz8cWhEpihlvR70ENj3f40j58TNxZaWv2ndSkInykNBBJw==} + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + '@types/node-fetch@2.6.13': resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==} @@ -4143,9 +4146,18 @@ packages: vue-router: optional: true - '@vercel/kv@3.0.0': - resolution: {integrity: sha512-pKT8fRnfyYk2MgvyB6fn6ipJPCdfZwiKDdw7vB+HL50rjboEBHDVBEcnwfkEpVSp2AjNtoaOUH7zG+bVC/rvSg==} - engines: {node: '>=14.6'} + '@vercel/functions@2.2.12': + resolution: {integrity: sha512-WGGqro/Rg00Epj+t2l6lr68q6ZkFt5+Q4F4Ok8sJbYrpu5pniDay09ihJqUoz81NI9PIfIahGEjaKpucUhEIrg==} + engines: {node: '>= 18'} + peerDependencies: + '@aws-sdk/credential-provider-web-identity': '*' + peerDependenciesMeta: + '@aws-sdk/credential-provider-web-identity': + optional: true + + '@vercel/oidc@2.0.1': + resolution: {integrity: sha512-p/rFk8vz+AggU0bHXjwtRUyXNxboLvfCjwN0KH5xhBJ5wGS+n/psLJP1c69QPdWIZM4aVVIrTqdjUuDwuJGYzQ==} + engines: {node: '>= 18'} '@vercel/speed-insights@1.2.0': resolution: {integrity: sha512-y9GVzrUJ2xmgtQlzFP2KhVRoCglwfRQgjyfY607aU0hh0Un6d0OUyrJkjuAlsV18qR4zfoFPs/BiIj9YDS6Wzw==} @@ -7074,8 +7086,8 @@ packages: typescript: optional: true - next@15.4.2-canary.10: - resolution: {integrity: sha512-EZxcDRySil7NDUWgKtsSsDqORkyIOOjby3VeNp+fT8ksQcuIwEmD6RdWo1LmoSIOW/IZNBijDmPQYkga6lmjZg==} + next@15.5.1-canary.4: + resolution: {integrity: sha512-GPzm40zpB/oucI5lb84DT3+qktJp8YFZ9t7/lZwWdQqJb0ZfZiVvdZcoVr7niOOoHI3CU/97BRt9wsTO+GAJ8g==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} hasBin: true peerDependencies: @@ -11878,7 +11890,7 @@ snapshots: - bufferutil - utf-8-validate - '@next/env@15.4.2-canary.10': {} + '@next/env@15.5.1-canary.4': {} '@next/eslint-plugin-next@15.2.3': dependencies: @@ -11888,28 +11900,28 @@ snapshots: dependencies: fast-glob: 3.3.1 - '@next/swc-darwin-arm64@15.4.2-canary.10': + '@next/swc-darwin-arm64@15.5.1-canary.4': optional: true - '@next/swc-darwin-x64@15.4.2-canary.10': + '@next/swc-darwin-x64@15.5.1-canary.4': optional: true - '@next/swc-linux-arm64-gnu@15.4.2-canary.10': + '@next/swc-linux-arm64-gnu@15.5.1-canary.4': optional: true - '@next/swc-linux-arm64-musl@15.4.2-canary.10': + '@next/swc-linux-arm64-musl@15.5.1-canary.4': optional: true - '@next/swc-linux-x64-gnu@15.4.2-canary.10': + '@next/swc-linux-x64-gnu@15.5.1-canary.4': optional: true - '@next/swc-linux-x64-musl@15.4.2-canary.10': + '@next/swc-linux-x64-musl@15.5.1-canary.4': optional: true - '@next/swc-win32-arm64-msvc@15.4.2-canary.10': + '@next/swc-win32-arm64-msvc@15.5.1-canary.4': optional: true - '@next/swc-win32-x64-msvc@15.4.2-canary.10': + '@next/swc-win32-x64-msvc@15.5.1-canary.4': optional: true '@noble/ciphers@1.3.0': {} @@ -13599,6 +13611,8 @@ snapshots: '@types/lodash@4.17.5': {} + '@types/ms@2.1.0': {} + '@types/node-fetch@2.6.13': dependencies: '@types/node': 22.15.30 @@ -13938,20 +13952,27 @@ snapshots: dependencies: uncrypto: 0.1.3 - '@vercel/analytics@1.5.0(next@15.4.2-canary.10(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)(svelte@5.1.15)(vue@3.5.16(typescript@5.8.3))': + '@vercel/analytics@1.5.0(next@15.5.1-canary.4(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)(svelte@5.1.15)(vue@3.5.16(typescript@5.8.3))': optionalDependencies: - next: 15.4.2-canary.10(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + next: 15.5.1-canary.4(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) react: 19.1.0 svelte: 5.1.15 vue: 3.5.16(typescript@5.8.3) - '@vercel/kv@3.0.0': + '@vercel/functions@2.2.12(@aws-sdk/credential-provider-web-identity@3.864.0)': + dependencies: + '@vercel/oidc': 2.0.1 + optionalDependencies: + '@aws-sdk/credential-provider-web-identity': 3.864.0 + + '@vercel/oidc@2.0.1': dependencies: - '@upstash/redis': 1.35.0 + '@types/ms': 2.1.0 + ms: 2.1.3 - '@vercel/speed-insights@1.2.0(next@15.4.2-canary.10(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)(svelte@5.1.15)(vue@3.5.16(typescript@5.8.3))': + '@vercel/speed-insights@1.2.0(next@15.5.1-canary.4(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)(svelte@5.1.15)(vue@3.5.16(typescript@5.8.3))': optionalDependencies: - next: 15.4.2-canary.10(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + next: 15.5.1-canary.4(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) react: 19.1.0 svelte: 5.1.15 vue: 3.5.16(typescript@5.8.3) @@ -17429,27 +17450,27 @@ snapshots: netmask@2.0.2: {} - next-auth@5.0.0-beta.25(next@15.4.2-canary.10(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(nodemailer@6.9.16)(react@19.1.0): + next-auth@5.0.0-beta.25(next@15.5.1-canary.4(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(nodemailer@6.9.16)(react@19.1.0): dependencies: '@auth/core': 0.37.2(nodemailer@6.9.16) - next: 15.4.2-canary.10(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + next: 15.5.1-canary.4(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) react: 19.1.0 optionalDependencies: nodemailer: 6.9.16 - next-intl@4.1.0(next@15.4.2-canary.10(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)(typescript@5.8.3): + next-intl@4.1.0(next@15.5.1-canary.4(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)(typescript@5.8.3): dependencies: '@formatjs/intl-localematcher': 0.5.10 negotiator: 1.0.0 - next: 15.4.2-canary.10(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + next: 15.5.1-canary.4(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) react: 19.1.0 use-intl: 4.1.0(react@19.1.0) optionalDependencies: typescript: 5.8.3 - next@15.4.2-canary.10(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + next@15.5.1-canary.4(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): dependencies: - '@next/env': 15.4.2-canary.10 + '@next/env': 15.5.1-canary.4 '@swc/helpers': 0.5.15 caniuse-lite: 1.0.30001721 postcss: 8.4.31 @@ -17457,14 +17478,14 @@ snapshots: react-dom: 19.1.0(react@19.1.0) styled-jsx: 5.1.6(@babel/core@7.27.4)(react@19.1.0) optionalDependencies: - '@next/swc-darwin-arm64': 15.4.2-canary.10 - '@next/swc-darwin-x64': 15.4.2-canary.10 - '@next/swc-linux-arm64-gnu': 15.4.2-canary.10 - '@next/swc-linux-arm64-musl': 15.4.2-canary.10 - '@next/swc-linux-x64-gnu': 15.4.2-canary.10 - '@next/swc-linux-x64-musl': 15.4.2-canary.10 - '@next/swc-win32-arm64-msvc': 15.4.2-canary.10 - '@next/swc-win32-x64-msvc': 15.4.2-canary.10 + '@next/swc-darwin-arm64': 15.5.1-canary.4 + '@next/swc-darwin-x64': 15.5.1-canary.4 + '@next/swc-linux-arm64-gnu': 15.5.1-canary.4 + '@next/swc-linux-arm64-musl': 15.5.1-canary.4 + '@next/swc-linux-x64-gnu': 15.5.1-canary.4 + '@next/swc-linux-x64-musl': 15.5.1-canary.4 + '@next/swc-win32-arm64-msvc': 15.5.1-canary.4 + '@next/swc-win32-x64-msvc': 15.5.1-canary.4 '@playwright/test': 1.52.0 sharp: 0.34.3 transitivePeerDependencies: @@ -17517,12 +17538,12 @@ snapshots: dependencies: boolbase: 1.0.0 - nuqs@2.4.3(next@15.4.2-canary.10(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0): + nuqs@2.4.3(next@15.5.1-canary.4(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0): dependencies: mitt: 3.0.1 react: 19.1.0 optionalDependencies: - next: 15.4.2-canary.10(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + next: 15.5.1-canary.4(@babel/core@7.27.4)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) nwsapi@2.2.20: {} From 63d2dd70d8054344d8ad35bafc0e38661ea2d247 Mon Sep 17 00:00:00 2001 From: Nathan Booker Date: Sat, 23 Aug 2025 22:00:27 -0500 Subject: [PATCH 030/245] chore: update @makeswift/runtime to version 0.25.0 in package.json --- .changeset/great-queens-joke.md | 5 ++ core/app/[locale]/layout.tsx | 5 +- core/lib/makeswift/provider.tsx | 8 +- core/package.json | 2 +- pnpm-lock.yaml | 135 ++++++++++++++++++-------------- 5 files changed, 88 insertions(+), 67 deletions(-) create mode 100644 .changeset/great-queens-joke.md diff --git a/.changeset/great-queens-joke.md b/.changeset/great-queens-joke.md new file mode 100644 index 0000000000..e21f4b880e --- /dev/null +++ b/.changeset/great-queens-joke.md @@ -0,0 +1,5 @@ +--- +"@bigcommerce/catalyst-makeswift": minor +--- + +Bump Makeswift runtime to 0.25.0 for Next v15.5 compatibility diff --git a/core/app/[locale]/layout.tsx b/core/app/[locale]/layout.tsx index 2ec2160787..f54b9ebcc0 100644 --- a/core/app/[locale]/layout.tsx +++ b/core/app/[locale]/layout.tsx @@ -1,8 +1,8 @@ +import { getSiteVersion } from '@makeswift/runtime/next/server'; import { Analytics } from '@vercel/analytics/react'; import { SpeedInsights } from '@vercel/speed-insights/next'; import { clsx } from 'clsx'; import type { Metadata } from 'next'; -import { draftMode } from 'next/headers'; import { notFound } from 'next/navigation'; import { NextIntlClientProvider } from 'next-intl'; import { setRequestLocale } from 'next-intl/server'; @@ -108,6 +108,7 @@ export default async function RootLayout({ params, children }: Props) { const { data } = await fetchRootLayoutMetadata(); const toastNotificationCookieData = await getToastNotification(); + const siteVersion = await getSiteVersion(); if (!routing.locales.includes(locale)) { notFound(); @@ -118,7 +119,7 @@ export default async function RootLayout({ params, children }: Props) { setRequestLocale(locale); return ( - + f.variable))} lang={locale}> diff --git a/core/lib/makeswift/provider.tsx b/core/lib/makeswift/provider.tsx index 34895773c7..a87e511e29 100644 --- a/core/lib/makeswift/provider.tsx +++ b/core/lib/makeswift/provider.tsx @@ -1,19 +1,19 @@ 'use client'; -import { ReactRuntimeProvider, RootStyleRegistry } from '@makeswift/runtime/next'; +import { ReactRuntimeProvider, RootStyleRegistry, type SiteVersion } from '@makeswift/runtime/next'; import { runtime } from '~/lib/makeswift/runtime'; import '~/lib/makeswift/components'; export function MakeswiftProvider({ children, - previewMode, + siteVersion, }: { children: React.ReactNode; - previewMode: boolean; + siteVersion: SiteVersion | null; }) { return ( - + {children} ); diff --git a/core/package.json b/core/package.json index 8a7ae7b784..0e47f1fe37 100644 --- a/core/package.json +++ b/core/package.json @@ -17,7 +17,7 @@ "@conform-to/react": "^1.6.1", "@conform-to/zod": "^1.6.1", "@icons-pack/react-simple-icons": "^11.2.0", - "@makeswift/runtime": "^0.24.6", + "@makeswift/runtime": "^0.25.0", "@radix-ui/react-accordion": "^1.2.11", "@radix-ui/react-checkbox": "^1.3.2", "@radix-ui/react-dialog": "^1.1.14", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b3c15624e8..6f3f4d406d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -48,8 +48,8 @@ importers: specifier: ^11.2.0 version: 11.2.0(react@19.1.0) '@makeswift/runtime': - specifier: ^0.24.6 - version: 0.24.6(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(next@15.4.2-canary.10(@babel/core@7.27.4)(@playwright/test@1.52.0)(babel-plugin-macros@3.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + specifier: ^0.25.0 + version: 0.25.0(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(next@15.4.2-canary.10(@babel/core@7.27.4)(@playwright/test@1.52.0)(babel-plugin-macros@3.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-accordion': specifier: ^1.2.11 version: 1.2.11(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) @@ -1882,19 +1882,20 @@ packages: resolution: {integrity: sha512-qC72D4+CDdjGqJvkFMMEAtancHUQ7/d/tAiHf64z8MopFDmcrtbcJuerDtFceuAfQJ2pDSfCKCtbqoGBNnwg0w==} engines: {node: '>=8'} - '@makeswift/controls@0.1.10': - resolution: {integrity: sha512-OYuQmCVM5FuutBIETrug7kgW5TFp35zNn2T7TEgOdVXHGksvZpj4MIg52XbEHSF3fij/UXVVod6VXzIFLAHjZA==} + '@makeswift/controls@0.1.12': + resolution: {integrity: sha512-2jgfUMcxh7WHLXMPmP2MVbEsb4jNMsbIxE0YB+LE9dFMfiSnK0WHgr23JLKPk2EnxexK+ICzQr7sHEyaSL2smg==} - '@makeswift/next-plugin@0.4.1': - resolution: {integrity: sha512-68ZpoL7TzykDcSbRWVA1q+1g6/CxMgARIqtOI1QfnGRzMJa/uJ6p9Uziz7ugtu7ukMMhhONeJuJcjvA0wcG9Bw==} + '@makeswift/next-plugin@0.5.0': + resolution: {integrity: sha512-UHnd5edRDv0JwyMHSVhgD3wcgJO2kdV6jmsw80SJvaE3zZOtNFK1OtKSYMmNtwrH4nNiNKjM1HZbjoHkbbjK7Q==} peerDependencies: next: ^13.4.0 || ^14.0.0 || ^15.0.0 - '@makeswift/prop-controllers@0.4.3': - resolution: {integrity: sha512-FI/AnaTVtqFPD75+MWHvGM1V6laLXbmrse98TuRN0OUuY/JCZ5+JjSoGtxlC667po0C6L22Zt1dUJSTvrn4FCg==} + '@makeswift/prop-controllers@0.4.6': + resolution: {integrity: sha512-+Wl9WDmocwEEVIhLfMpLmFUq5PamAbbwdEni1dxYJck9NrjNWf/jyXecARJxme2fiGmvxZX8N8+awhGm1k9s4A==} - '@makeswift/runtime@0.24.6': - resolution: {integrity: sha512-20vtK5DdLrsb/Dp0h5hLEc8ESIPJLy5WHiBZGEEZ9jQyP2XeZf4N1vQRdHyf7bJluK58VvCkZm9qP/gIITjG0g==} + '@makeswift/runtime@0.25.0': + resolution: {integrity: sha512-ZnA3M1PApZCMOTX2EhJbM7MsV2xjFt6sVBpTGNf1HCoLjVmR+b7ocbEG0EH0ippupH6iI2DCtnFtg8f4WBFMaQ==} + engines: {node: '>=20.0.0'} peerDependencies: '@types/react': ^18.0.0 || ^19.0.0 '@types/react-dom': ^18.0.0 || ^19.0.0 @@ -2602,10 +2603,16 @@ packages: '@radix-ui/rect@1.1.1': resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} - '@redux-devtools/extension@3.3.0': - resolution: {integrity: sha512-X34S/rC8S/M1BIrkYD1mJ5f8vlH0BDqxXrs96cvxSBo4FhMdbhU+GUGsmNYov1xjSyLMHgo8NYrUG8bNX7525g==} + '@reduxjs/toolkit@2.8.2': + resolution: {integrity: sha512-MYlOhQ0sLdw4ud48FoC5w0dH9VfWQjtCjreKwYTT3l+r427qYC5Y8PihNutepr8XrNaBUDQo9khWUwQxZaqt5A==} peerDependencies: - redux: ^3.1.0 || ^4.0.0 || ^5.0.0 + react: ^16.9.0 || ^17.0.0 || ^18 || ^19 + react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0 + peerDependenciesMeta: + react: + optional: true + react-redux: + optional: true '@rollup/pluginutils@5.1.4': resolution: {integrity: sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==} @@ -2807,6 +2814,12 @@ packages: '@sinonjs/fake-timers@10.3.0': resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + '@standard-schema/spec@1.0.0': + resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} + + '@standard-schema/utils@0.3.0': + resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} + '@stylistic/eslint-plugin@2.7.2': resolution: {integrity: sha512-3DVLU5HEuk2pQoBmXJlzvrxbKNpu2mJ0SRqz5O/CJjyNCr12ZiPcYMEtuArTyPOk5i7bsAU44nywh1rGfe3gKQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -3052,9 +3065,6 @@ packages: '@types/react-headroom@3.2.3': resolution: {integrity: sha512-rdgcMfoxN6wnGm8mSlwA7vuuK8ojXUI/tWHX1qJSAS7DNuvt7zv3zUtYs15UETEtE0Wc2YJCq0PZlHhZ+lRP4Q==} - '@types/react@19.1.2': - resolution: {integrity: sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw==} - '@types/react@19.1.6': resolution: {integrity: sha512-JeG0rEWak0N6Itr6QUx+X60uQmN+5t3j9r/OVDtWzFXKaj6kD1BwJzOksD0FF6iWxZlbE1kB0q9vtnU2ekqa1Q==} @@ -5138,16 +5148,15 @@ packages: immediate@3.0.6: resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} + immer@10.1.1: + resolution: {integrity: sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==} + immer@9.0.21: resolution: {integrity: sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==} immutable@4.3.7: resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==} - import-fresh@3.3.0: - resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} - engines: {node: '>=6'} - import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} @@ -5679,6 +5688,10 @@ packages: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} + jwt-decode@4.0.0: + resolution: {integrity: sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==} + engines: {node: '>=18'} + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -6925,8 +6938,8 @@ packages: react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - react-player@2.16.0: - resolution: {integrity: sha512-mAIPHfioD7yxO0GNYVFD1303QFtI3lyyQZLY229UEAp/a10cSW+hPcakg0Keq8uWJxT2OiT/4Gt+Lc9bD6bJmQ==} + react-player@2.16.1: + resolution: {integrity: sha512-mxP6CqjSWjidtyDoMOSHVPdhX0pY16aSvw5fVr44EMaT7X5Xz46uQ4b/YBm1v2x+3hHkB9PmjEEkmbHb9PXQ4w==} peerDependencies: react: '>=16.6.0' @@ -6992,13 +7005,13 @@ packages: resolution: {integrity: sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw==} engines: {node: '>= 14.18.0'} - redux-thunk@2.4.2: - resolution: {integrity: sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==} + redux-thunk@3.1.0: + resolution: {integrity: sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==} peerDependencies: - redux: ^4 + redux: ^5.0.0 - redux@4.2.1: - resolution: {integrity: sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==} + redux@5.0.1: + resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==} reflect.getprototypeof@1.0.10: resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} @@ -9755,7 +9768,7 @@ snapshots: dependencies: '@lukeed/csprng': 1.1.0 - '@makeswift/controls@0.1.10': + '@makeswift/controls@0.1.12': dependencies: color: 3.2.1 css-box-model: 1.2.1 @@ -9765,20 +9778,20 @@ snapshots: uuid: 9.0.1 zod: 3.25.51 - '@makeswift/next-plugin@0.4.1(next@15.4.2-canary.10(@babel/core@7.27.4)(@playwright/test@1.52.0)(babel-plugin-macros@3.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))': + '@makeswift/next-plugin@0.5.0(next@15.4.2-canary.10(@babel/core@7.27.4)(@playwright/test@1.52.0)(babel-plugin-macros@3.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))': dependencies: enhanced-resolve: 5.10.0 escalade: 3.1.1 next: 15.4.2-canary.10(@babel/core@7.27.4)(@playwright/test@1.52.0)(babel-plugin-macros@3.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) semver: 7.7.2 - '@makeswift/prop-controllers@0.4.3': + '@makeswift/prop-controllers@0.4.6': dependencies: - '@makeswift/controls': 0.1.10 + '@makeswift/controls': 0.1.12 ts-pattern: 5.5.0 zod: 3.25.51 - '@makeswift/runtime@0.24.6(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(next@15.4.2-canary.10(@babel/core@7.27.4)(@playwright/test@1.52.0)(babel-plugin-macros@3.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@makeswift/runtime@0.25.0(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(next@15.4.2-canary.10(@babel/core@7.27.4)(@playwright/test@1.52.0)(babel-plugin-macros@3.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@emotion/cache': 11.14.0 '@emotion/css': 11.13.5 @@ -9786,11 +9799,11 @@ snapshots: '@emotion/server': 11.11.0(@emotion/css@11.13.5) '@emotion/sheet': 1.4.0 '@emotion/utils': 1.4.2 - '@makeswift/controls': 0.1.10 - '@makeswift/next-plugin': 0.4.1(next@15.4.2-canary.10(@babel/core@7.27.4)(@playwright/test@1.52.0)(babel-plugin-macros@3.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)) - '@makeswift/prop-controllers': 0.4.3 + '@makeswift/controls': 0.1.12 + '@makeswift/next-plugin': 0.5.0(next@15.4.2-canary.10(@babel/core@7.27.4)(@playwright/test@1.52.0)(babel-plugin-macros@3.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)) + '@makeswift/prop-controllers': 0.4.6 '@popmotion/popcorn': 0.4.4 - '@redux-devtools/extension': 3.3.0(redux@4.2.1) + '@reduxjs/toolkit': 2.8.2(react@19.1.0) '@types/is-hotkey': 0.1.10 '@types/use-sync-external-store': 0.0.3 '@types/uuid': 9.0.8 @@ -9809,6 +9822,7 @@ snapshots: immutable: 4.3.7 is-hotkey: 0.1.8 js-base64: 3.7.7 + jwt-decode: 4.0.0 next: 15.4.2-canary.10(@babel/core@7.27.4)(@playwright/test@1.52.0)(babel-plugin-macros@3.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) ot-json0: 1.1.0 parse5: 7.2.1 @@ -9816,9 +9830,7 @@ snapshots: polished: 3.0.3 react: 19.1.0 react-dom: 19.1.0(react@19.1.0) - react-player: 2.16.0(react@19.1.0) - redux: 4.2.1 - redux-thunk: 2.4.2(redux@4.2.1) + react-player: 2.16.1(react@19.1.0) reselect: 5.1.1 scroll-into-view-if-needed: 2.2.31 set-cookie-parser: 2.7.1 @@ -9833,6 +9845,7 @@ snapshots: '@types/react': 19.1.6 '@types/react-dom': 19.1.6(@types/react@19.1.6) transitivePeerDependencies: + - react-redux - supports-color '@manypkg/find-root@1.1.0': @@ -10549,11 +10562,16 @@ snapshots: '@radix-ui/rect@1.1.1': {} - '@redux-devtools/extension@3.3.0(redux@4.2.1)': + '@reduxjs/toolkit@2.8.2(react@19.1.0)': dependencies: - '@babel/runtime': 7.26.7 - immutable: 4.3.7 - redux: 4.2.1 + '@standard-schema/spec': 1.0.0 + '@standard-schema/utils': 0.3.0 + immer: 10.1.1 + redux: 5.0.1 + redux-thunk: 3.1.0(redux@5.0.1) + reselect: 5.1.1 + optionalDependencies: + react: 19.1.0 '@rollup/pluginutils@5.1.4(rollup@4.44.2)': dependencies: @@ -10742,6 +10760,10 @@ snapshots: dependencies: '@sinonjs/commons': 3.0.1 + '@standard-schema/spec@1.0.0': {} + + '@standard-schema/utils@0.3.0': {} + '@stylistic/eslint-plugin@2.7.2(eslint@8.57.1)(typescript@5.8.3)': dependencies: '@types/eslint': 9.6.1 @@ -10917,7 +10939,7 @@ snapshots: '@types/hoist-non-react-statics@3.3.6': dependencies: - '@types/react': 19.1.2 + '@types/react': 19.1.6 hoist-non-react-statics: 3.3.2 '@types/http-cache-semantics@4.0.4': {} @@ -10986,10 +11008,6 @@ snapshots: dependencies: '@types/react': 19.1.6 - '@types/react@19.1.2': - dependencies: - csstype: 3.1.3 - '@types/react@19.1.6': dependencies: csstype: 3.1.3 @@ -12111,7 +12129,7 @@ snapshots: cosmiconfig@7.1.0: dependencies: '@types/parse-json': 4.0.2 - import-fresh: 3.3.0 + import-fresh: 3.3.1 parse-json: 5.2.0 path-type: 4.0.0 yaml: 1.10.2 @@ -13551,15 +13569,12 @@ snapshots: immediate@3.0.6: {} + immer@10.1.1: {} + immer@9.0.21: {} immutable@4.3.7: {} - import-fresh@3.3.0: - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - import-fresh@3.3.1: dependencies: parent-module: 1.0.1 @@ -14277,6 +14292,8 @@ snapshots: object.assign: 4.1.7 object.values: 1.2.1 + jwt-decode@4.0.0: {} + keyv@4.5.4: dependencies: json-buffer: 3.0.1 @@ -15545,7 +15562,7 @@ snapshots: react-is@18.3.1: {} - react-player@2.16.0(react@19.1.0): + react-player@2.16.1(react@19.1.0): dependencies: deepmerge: 4.3.1 load-script: 1.0.0 @@ -15625,13 +15642,11 @@ snapshots: readdirp@4.1.1: {} - redux-thunk@2.4.2(redux@4.2.1): + redux-thunk@3.1.0(redux@5.0.1): dependencies: - redux: 4.2.1 + redux: 5.0.1 - redux@4.2.1: - dependencies: - '@babel/runtime': 7.26.7 + redux@5.0.1: {} reflect.getprototypeof@1.0.10: dependencies: From eab04b85a4cb07b998a85d04648faa9badcad214 Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Mon, 25 Aug 2025 10:48:27 -0500 Subject: [PATCH 031/245] fix(cli): prevent existing bundle.zip from being included in the bundle (#2542) --- packages/cli/src/commands/deploy.ts | 5 +++-- packages/cli/tests/commands/deploy.spec.ts | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/cli/src/commands/deploy.ts b/packages/cli/src/commands/deploy.ts index 76a4b108c8..7fe1bae1bc 100644 --- a/packages/cli/src/commands/deploy.ts +++ b/packages/cli/src/commands/deploy.ts @@ -63,6 +63,7 @@ const DeploymentStatusSchema = z.object({ export const generateBundleZip = async () => { consola.info('Generating bundle...'); + const bigcommerceDir = join(process.cwd(), '.bigcommerce'); const distDir = join(process.cwd(), '.bigcommerce', 'dist'); // Check if .bigcommerce/dist exists @@ -79,7 +80,7 @@ export const generateBundleZip = async () => { throw new Error(`Dist directory is empty: ${distDir}`); } - const outputZip = join(distDir, 'bundle.zip'); + const outputZip = join(bigcommerceDir, 'bundle.zip'); // Use AdmZip to create the zip const zip = new AdmZip(); @@ -125,7 +126,7 @@ export const generateUploadSignature = async ( export const uploadBundleZip = async (uploadUrl: string) => { consola.info('Uploading bundle...'); - const zipPath = join(process.cwd(), '.bigcommerce', 'dist', 'bundle.zip'); + const zipPath = join(process.cwd(), '.bigcommerce', 'bundle.zip'); // Read the zip file as a buffer const fileBuffer = await readFile(zipPath); diff --git a/packages/cli/tests/commands/deploy.spec.ts b/packages/cli/tests/commands/deploy.spec.ts index 7a80b28806..04ad2697d9 100644 --- a/packages/cli/tests/commands/deploy.spec.ts +++ b/packages/cli/tests/commands/deploy.spec.ts @@ -56,10 +56,10 @@ beforeAll(async () => { // Normalize to /private/var to avoid /var vs /private/var mismatches tmpDir = await realpath(tmpDir); - const workerPath = join(tmpDir, '.bigcommerce/dist/worker.js'); - const assetsDir = join(tmpDir, '.bigcommerce/dist/assets'); + const workerPath = join(tmpDir, '.bigcommerce', 'dist', 'worker.js'); + const assetsDir = join(tmpDir, '.bigcommerce', 'dist', 'assets'); - outputZip = join(tmpDir, '.bigcommerce/dist/bundle.zip'); + outputZip = join(tmpDir, '.bigcommerce', 'bundle.zip'); await mkdir(dirname(workerPath), { recursive: true }); await writeFile(workerPath, 'console.log("worker");'); From 85de083650516811fad2b5aaa09ffe600c0b870b Mon Sep 17 00:00:00 2001 From: Matthew Volk Date: Mon, 25 Aug 2025 18:28:27 -0500 Subject: [PATCH 032/245] fix: build command --project-uuid should also read from env (#2557) --- packages/cli/src/commands/build.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/cli/src/commands/build.ts b/packages/cli/src/commands/build.ts index 0618e36416..4708add806 100644 --- a/packages/cli/src/commands/build.ts +++ b/packages/cli/src/commands/build.ts @@ -18,7 +18,12 @@ export const build = new Command('build') '[next-build-options...]', 'Next.js `build` options (see: https://nextjs.org/docs/app/api-reference/cli/next#next-build-options)', ) - .option('--project-uuid ', 'Project UUID to be included in the deployment configuration.') + .addOption( + new Option( + '--project-uuid ', + 'Project UUID to be included in the deployment configuration.', + ).env('BIGCOMMERCE_PROJECT_UUID'), + ) .addOption( new Option('--framework ', 'The framework to use for the build.').choices([ 'nextjs', From 3cc89f9c65e4518df23c48a747c3b0af0b0e2cb6 Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Tue, 26 Aug 2025 16:15:55 -0500 Subject: [PATCH 033/245] feat(cli): add env option to deploy command (#2558) * feat(cli): add env option to deploy command * fix: remove default values * fix: change error message * fix: rename to secrets * fix: use variadic option --- packages/cli/src/commands/deploy.ts | 27 ++++++++++++++++++++++ packages/cli/tests/commands/deploy.spec.ts | 26 +++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/packages/cli/src/commands/deploy.ts b/packages/cli/src/commands/deploy.ts index 7fe1bae1bc..7dd55084a6 100644 --- a/packages/cli/src/commands/deploy.ts +++ b/packages/cli/src/commands/deploy.ts @@ -148,12 +148,29 @@ export const uploadBundleZip = async (uploadUrl: string) => { return true; }; +export const parseEnvironmentVariables = (secretOption?: string[]) => { + return secretOption?.map((envVar) => { + const [key, value] = envVar.split('='); + + if (!key || !value) { + throw new Error(`Invalid secret format: ${envVar}. Expected format: KEY=VALUE`); + } + + return { + type: 'secret' as const, + key: key.trim(), + value: value.trim(), + }; + }); +}; + export const createDeployment = async ( projectUuid: string, uploadUuid: string, storeHash: string, accessToken: string, apiHost: string, + environmentVariables?: Array<{ type: 'secret' | 'plain_text'; key: string; value: string }>, ) => { consola.info('Creating deployment...'); @@ -169,6 +186,7 @@ export const createDeployment = async ( body: JSON.stringify({ project_uuid: projectUuid, upload_uuid: uploadUuid, + environment_variables: environmentVariables, }), }, ); @@ -288,6 +306,12 @@ export const deploy = new Command('deploy') 'BigCommerce intrastructure project UUID. Can be found via the BigCommerce API (GET /v3/infrastructure/projects).', ).env('BIGCOMMERCE_PROJECT_UUID'), ) + .addOption( + new Option( + '--secret ', + 'Secrets to set for the deployment. Format: SECRET_1=FOO,SECRET_2=BAR', + ), + ) .option('--dry-run', 'Run the command to generate the bundle without uploading or deploying.') .action(async (options) => { @@ -324,12 +348,15 @@ export const deploy = new Command('deploy') await uploadBundleZip(uploadSignature.upload_url); + const environmentVariables = parseEnvironmentVariables(options.secret); + const { deployment_uuid: deploymentUuid } = await createDeployment( projectUuid, uploadSignature.upload_uuid, options.storeHash, options.accessToken, options.apiHost, + environmentVariables, ); await getDeploymentStatus( diff --git a/packages/cli/tests/commands/deploy.spec.ts b/packages/cli/tests/commands/deploy.spec.ts index 04ad2697d9..856e7e30fd 100644 --- a/packages/cli/tests/commands/deploy.spec.ts +++ b/packages/cli/tests/commands/deploy.spec.ts @@ -22,6 +22,7 @@ import { generateBundleZip, generateUploadSignature, getDeploymentStatus, + parseEnvironmentVariables, uploadBundleZip, } from '../../src/commands/deploy'; import { mkTempDir } from '../../src/lib/mk-temp-dir'; @@ -92,6 +93,7 @@ test('properly configured Command instance', () => { expect.objectContaining({ flags: '--access-token ' }), expect.objectContaining({ flags: '--api-host ', defaultValue: 'api.bigcommerce.com' }), expect.objectContaining({ flags: '--project-uuid ' }), + expect.objectContaining({ flags: '--secret ' }), expect.objectContaining({ flags: '--dry-run' }), ]), ); @@ -300,3 +302,27 @@ test('--dry-run skips upload and deployment', async () => { expect(consola.info).toHaveBeenCalledWith('- Create deployment'); expect(exitMock).toHaveBeenCalledWith(0); }); + +test('reads from env options', () => { + const envVariables = parseEnvironmentVariables([ + 'BIGCOMMERCE_STORE_HASH=123', + 'BIGCOMMERCE_STOREFRONT_TOKEN=456', + ]); + + expect(envVariables).toEqual([ + { + type: 'secret', + key: 'BIGCOMMERCE_STORE_HASH', + value: '123', + }, + { + type: 'secret', + key: 'BIGCOMMERCE_STOREFRONT_TOKEN', + value: '456', + }, + ]); + + expect(() => parseEnvironmentVariables(['foo_bar'])).toThrow( + 'Invalid secret format: foo_bar. Expected format: KEY=VALUE', + ); +}); From 03b35f7bf385180dd97285ae3c3d24de8ab7fef1 Mon Sep 17 00:00:00 2001 From: Hunter Garrett Date: Tue, 26 Aug 2025 17:38:27 -0400 Subject: [PATCH 034/245] fix: text variable for button and button-link components --- core/vibes/soul/primitives/button-link/index.tsx | 16 ++++++++-------- core/vibes/soul/primitives/button/index.tsx | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/core/vibes/soul/primitives/button-link/index.tsx b/core/vibes/soul/primitives/button-link/index.tsx index 7b505e6ce3..cf4d977e82 100644 --- a/core/vibes/soul/primitives/button-link/index.tsx +++ b/core/vibes/soul/primitives/button-link/index.tsx @@ -20,19 +20,19 @@ export interface ButtonLinkProps extends ComponentPropsWithoutRef { * --button-font-family: var(--font-family-body); * --button-primary-background: hsl(var(--primary)); * --button-primary-background-hover: color-mix(in oklab, hsl(var(--primary)), white 75%); - * --button-primary-text: hsl(var(--foreground)); + * --button-primary-foreground: hsl(var(--foreground)); * --button-primary-border: hsl(var(--primary)); * --button-secondary-background: hsl(var(--foreground)); * --button-secondary-background-hover: hsl(var(--background)); - * --button-secondary-text: hsl(var(--background)); + * --button-secondary-foreground: hsl(var(--background)); * --button-secondary-border: hsl(var(--foreground)); * --button-tertiary-background: hsl(var(--background)); * --button-tertiary-background-hover: hsl(var(--contrast-100)); - * --button-tertiary-text: hsl(var(--foreground)); + * --button-tertiary-foreground: hsl(var(--foreground)); * --button-tertiary-border: hsl(var(--contrast-200)); * --button-ghost-background: transparent; * --button-ghost-background-hover: hsl(var(--foreground) / 5%); - * --button-ghost-text: hsl(var(--foreground)); + * --button-ghost-foreground: hsl(var(--foreground)); * --button-ghost-border: transparent; * } * ``` @@ -52,13 +52,13 @@ export function ButtonLink({ 'relative z-0 inline-flex h-fit select-none items-center justify-center overflow-hidden border text-center font-[family-name:var(--button-font-family)] font-semibold leading-normal after:absolute after:inset-0 after:-z-10 after:-translate-x-[105%] after:transition-[opacity,transform] after:duration-300 after:[animation-timing-function:cubic-bezier(0,0.25,0,1)] hover:after:translate-x-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--button-focus,hsl(var(--primary)))] focus-visible:ring-offset-2', { primary: - 'border-[var(--button-primary-border,hsl(var(--primary)))] bg-[var(--button-primary-background,hsl(var(--primary)))] text-[var(--button-primary-text)] after:bg-[var(--button-primary-background-hover,color-mix(in_oklab,hsl(var(--primary)),white_75%))]', + 'border-[var(--button-primary-border,hsl(var(--primary)))] bg-[var(--button-primary-background,hsl(var(--primary)))] text-[var(--button-primary-foreground,hsl(var(--foreground)))] after:bg-[var(--button-primary-background-hover,color-mix(in_oklab,hsl(var(--primary)),white_75%))]', secondary: - 'border-[var(--button-secondary-border,hsl(var(--foreground)))] bg-[var(--button-secondary-background,hsl(var(--foreground)))] text-[var(--button-secondary-text,hsl(var(--background)))] after:bg-[var(--button-secondary-background-hover,hsl(var(--background)))]', + 'border-[var(--button-secondary-border,hsl(var(--foreground)))] bg-[var(--button-secondary-background,hsl(var(--foreground)))] text-[var(--button-secondary-foreground,hsl(var(--background)))] after:bg-[var(--button-secondary-background-hover,hsl(var(--background)))]', tertiary: - 'border-[var(--button-tertiary-border,hsl(var(--contrast-200)))] bg-[var(--button-tertiary-background,hsl(var(--background)))] text-[var(--button-tertiary-text,hsl(var(--foreground)))] after:bg-[var(--button-tertiary-background-hover,hsl(var(--contrast-100)))]', + 'border-[var(--button-tertiary-border,hsl(var(--contrast-200)))] bg-[var(--button-tertiary-background,hsl(var(--background)))] text-[var(--button-tertiary-foreground,hsl(var(--foreground)))] after:bg-[var(--button-tertiary-background-hover,hsl(var(--contrast-100)))]', ghost: - 'border-[var(--button-ghost-border,transparent)] bg-[var(--button-ghost-background,transparent)] text-[var(--button-ghost-text,hsl(var(--foreground)))] after:bg-[var(--button-ghost-background-hover,hsl(var(--foreground)/5%))]', + 'border-[var(--button-ghost-border,transparent)] bg-[var(--button-ghost-background,transparent)] text-[var(--button-ghost-foreground,hsl(var(--foreground)))] after:bg-[var(--button-ghost-background-hover,hsl(var(--foreground)/5%))]', }[variant], { 'x-small': 'min-h-8 text-xs', diff --git a/core/vibes/soul/primitives/button/index.tsx b/core/vibes/soul/primitives/button/index.tsx index c637a086e2..349caf8466 100644 --- a/core/vibes/soul/primitives/button/index.tsx +++ b/core/vibes/soul/primitives/button/index.tsx @@ -20,19 +20,19 @@ export interface ButtonProps extends ComponentPropsWithoutRef<'button'> { * --button-font-family: var(--font-family-body); * --button-primary-background: hsl(var(--primary)); * --button-primary-background-hover: color-mix(in oklab, hsl(var(--primary)), white 75%); - * --button-primary-text: hsl(var(--foreground)); + * --button-primary-foreground: hsl(var(--foreground)); * --button-primary-border: hsl(var(--primary)); * --button-secondary-background: hsl(var(--foreground)); * --button-secondary-background-hover: hsl(var(--background)); - * --button-secondary-text: hsl(var(--background)); + * --button-secondary-foreground: hsl(var(--background)); * --button-secondary-border: hsl(var(--foreground)); * --button-tertiary-background: hsl(var(--background)); * --button-tertiary-background-hover: hsl(var(--contrast-100)); - * --button-tertiary-text: hsl(var(--foreground)); + * --button-tertiary-foreground: hsl(var(--foreground)); * --button-tertiary-border: hsl(var(--contrast-200)); * --button-ghost-background: transparent; * --button-ghost-background-hover: hsl(var(--foreground) / 5%); - * --button-ghost-text: hsl(var(--foreground)); + * --button-ghost-foreground: hsl(var(--foreground)); * --button-ghost-border: transparent; * --button-loader-icon: hsl(var(--foreground)); * --button-danger-background: color-mix(in oklab, hsl(var(--error)), white 30%); @@ -61,13 +61,13 @@ export function Button({ 'relative z-0 inline-flex h-fit cursor-pointer select-none items-center justify-center overflow-hidden border text-center font-[family-name:var(--button-font-family,var(--font-family-body))] font-semibold leading-normal after:absolute after:inset-0 after:-z-10 after:-translate-x-[105%] after:duration-300 after:[animation-timing-function:cubic-bezier(0,0.25,0,1)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--button-focus,hsl(var(--primary)))] focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-30', { primary: - 'border-[var(--button-primary-border,hsl(var(--primary)))] bg-[var(--button-primary-background,hsl(var(--primary)))] text-[var(--button-primary-text,hsl(var(--foreground)))] after:bg-[var(--button-primary-background-hover,color-mix(in_oklab,hsl(var(--primary)),white_75%))]', + 'border-[var(--button-primary-border,hsl(var(--primary)))] bg-[var(--button-primary-background,hsl(var(--primary)))] text-[var(--button-primary-foreground,hsl(var(--foreground)))] after:bg-[var(--button-primary-background-hover,color-mix(in_oklab,hsl(var(--primary)),white_75%))]', secondary: - 'border-[var(--button-secondary-border,hsl(var(--foreground)))] bg-[var(--button-secondary-background,hsl(var(--foreground)))] text-[var(--button-secondary-text,hsl(var(--background)))] after:bg-[var(--button-secondary-background-hover,hsl(var(--background)))]', + 'border-[var(--button-secondary-border,hsl(var(--foreground)))] bg-[var(--button-secondary-background,hsl(var(--foreground)))] text-[var(--button-secondary-foreground,hsl(var(--background)))] after:bg-[var(--button-secondary-background-hover,hsl(var(--background)))]', tertiary: - 'border-[var(--button-tertiary-border,hsl(var(--contrast-200)))] bg-[var(--button-tertiary-background,hsl(var(--background)))] text-[var(--button-tertiary-text,hsl(var(--foreground)))] after:bg-[var(--button-tertiary-background-hover,hsl(var(--contrast-100)))]', + 'border-[var(--button-tertiary-border,hsl(var(--contrast-200)))] bg-[var(--button-tertiary-background,hsl(var(--background)))] text-[var(--button-tertiary-foreground,hsl(var(--foreground)))] after:bg-[var(--button-tertiary-background-hover,hsl(var(--contrast-100)))]', ghost: - 'border-[var(--button-ghost-border,transparent)] bg-[var(--button-ghost-background,transparent)] text-[var(--button-ghost-text,hsl(var(--foreground)))] after:bg-[var(--button-ghost-background-hover,hsl(var(--foreground)/5%))]', + 'border-[var(--button-ghost-border,transparent)] bg-[var(--button-ghost-background,transparent)] text-[var(--button-ghost-foreground,hsl(var(--foreground)))] after:bg-[var(--button-ghost-background-hover,hsl(var(--foreground)/5%))]', danger: 'border-[var(--button-danger-border,color-mix(in_oklab,hsl(var(--error)),white_30%))] bg-[var(--button-danger-background,color-mix(in_oklab,hsl(var(--error)),white_30%))] text-[var(--button-danger-foreground)] after:bg-[var(--button-danger-background-hover,color-mix(in_oklab,hsl(var(--error)),white_75%))]', }[variant], From 9166b76fde91496fcd9d768b7b8bf3fb88310a4b Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Thu, 28 Aug 2025 10:58:03 -0500 Subject: [PATCH 035/245] fix(cli): update description for secret option in deploy (#2562) --- packages/cli/src/commands/deploy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/src/commands/deploy.ts b/packages/cli/src/commands/deploy.ts index 7dd55084a6..a5f1e5f59c 100644 --- a/packages/cli/src/commands/deploy.ts +++ b/packages/cli/src/commands/deploy.ts @@ -309,7 +309,7 @@ export const deploy = new Command('deploy') .addOption( new Option( '--secret ', - 'Secrets to set for the deployment. Format: SECRET_1=FOO,SECRET_2=BAR', + 'Secrets to set for the deployment. Format: SECRET_1=FOO SECRET_2=BAR', ), ) .option('--dry-run', 'Run the command to generate the bundle without uploading or deploying.') From 707ec24745b6a0040551328d64657ff40df4e252 Mon Sep 17 00:00:00 2001 From: Matthew Volk Date: Fri, 29 Aug 2025 14:45:31 -0500 Subject: [PATCH 036/245] chore: prefer performance.now over Date.now in server component (#2563) --- .changeset/cruel-pens-dance.md | 5 +++++ packages/client/src/client.ts | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 .changeset/cruel-pens-dance.md diff --git a/.changeset/cruel-pens-dance.md b/.changeset/cruel-pens-dance.md new file mode 100644 index 0000000000..87c01750ad --- /dev/null +++ b/.changeset/cruel-pens-dance.md @@ -0,0 +1,5 @@ +--- +"@bigcommerce/catalyst-client": patch +--- + +Replace usage of Date.now with performance.now for compatibility with upcoming Next.js Composable Cache feature diff --git a/packages/client/src/client.ts b/packages/client/src/client.ts index dc31eb563f..8e26981822 100644 --- a/packages/client/src/client.ts +++ b/packages/client/src/client.ts @@ -243,10 +243,10 @@ class Client { const { name, type } = getOperationInfo(document); - const timeStart = Date.now(); + const timeStart = performance.now(); return (response: Response) => { - const timeEnd = Date.now(); + const timeEnd = performance.now(); const duration = timeEnd - timeStart; const complexity = response.headers.get('x-bc-graphql-complexity'); From a27054f4f22013707d40a100b15122c22354c956 Mon Sep 17 00:00:00 2001 From: Matthew Volk Date: Fri, 29 Aug 2025 15:07:35 -0500 Subject: [PATCH 037/245] chore: fix performance.now to 2 decimal places (#2565) --- .changeset/tender-women-smash.md | 5 +++++ packages/client/src/client.ts | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changeset/tender-women-smash.md diff --git a/.changeset/tender-women-smash.md b/.changeset/tender-women-smash.md new file mode 100644 index 0000000000..70b406f7d5 --- /dev/null +++ b/.changeset/tender-women-smash.md @@ -0,0 +1,5 @@ +--- +"@bigcommerce/catalyst-client": patch +--- + +Truncate performance.now to 2 decimal places diff --git a/packages/client/src/client.ts b/packages/client/src/client.ts index 8e26981822..dd25618110 100644 --- a/packages/client/src/client.ts +++ b/packages/client/src/client.ts @@ -247,7 +247,7 @@ class Client { return (response: Response) => { const timeEnd = performance.now(); - const duration = timeEnd - timeStart; + const duration = (timeEnd - timeStart).toFixed(2); const complexity = response.headers.get('x-bc-graphql-complexity'); From 4145846667bfe8c3976271e6e50b5c3ec462dc1c Mon Sep 17 00:00:00 2001 From: Hunter Garrett Date: Tue, 2 Sep 2025 11:20:51 -0400 Subject: [PATCH 038/245] feat: support target prop in Footer links --- .changeset/loud-actors-build.md | 5 +++++ core/lib/makeswift/components/site-footer/client.tsx | 4 ++-- core/vibes/soul/sections/footer/index.tsx | 3 +++ 3 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 .changeset/loud-actors-build.md diff --git a/.changeset/loud-actors-build.md b/.changeset/loud-actors-build.md new file mode 100644 index 0000000000..343c39f976 --- /dev/null +++ b/.changeset/loud-actors-build.md @@ -0,0 +1,5 @@ +--- +"@bigcommerce/catalyst-makeswift": minor +--- + +Now have the ability to make footer links open in new tabs diff --git a/core/lib/makeswift/components/site-footer/client.tsx b/core/lib/makeswift/components/site-footer/client.tsx index 544f66a3bf..5ef6134bc6 100644 --- a/core/lib/makeswift/components/site-footer/client.tsx +++ b/core/lib/makeswift/components/site-footer/client.tsx @@ -43,7 +43,7 @@ interface Props { title: string; links: Array<{ label: string; - link: { href: string }; + link: { href: string; target?: string }; }>; }>; copyright?: string; @@ -57,7 +57,7 @@ function combineSections( passedSections, makeswiftSections.map(({ title, links }) => ({ title, - links: links.map(({ label, link }) => ({ label, href: link.href })), + links: links.map(({ label, link }) => ({ label, href: link.href, target: link.target })), })), (left, right) => ({ ...left, links: [...left.links, ...right.links] }), ); diff --git a/core/vibes/soul/sections/footer/index.tsx b/core/vibes/soul/sections/footer/index.tsx index 0c72018115..aff22fa211 100644 --- a/core/vibes/soul/sections/footer/index.tsx +++ b/core/vibes/soul/sections/footer/index.tsx @@ -14,6 +14,7 @@ interface Image { interface Link { href: string; label: string; + target?: string; } export interface Section { @@ -175,6 +176,8 @@ export const Footer = ({ {link.label} From 69797a4c9f0bfc8b27b7f144ded5545fdbb5e5cf Mon Sep 17 00:00:00 2001 From: Jorge Moya Date: Wed, 3 Sep 2025 10:14:19 -0500 Subject: [PATCH 039/245] feat(core): add visual queues when cart update is pending (#2564) * feat(core): add visual queues when cart update is pending * fix: add pulse animation to skeletons --- .changeset/large-flowers-attack.md | 14 +++ core/app/[locale]/(default)/cart/page.tsx | 1 + core/messages/en.json | 1 + core/vibes/soul/sections/cart/client.tsx | 133 ++++++++++++++++++++-- 4 files changed, 138 insertions(+), 11 deletions(-) create mode 100644 .changeset/large-flowers-attack.md diff --git a/.changeset/large-flowers-attack.md b/.changeset/large-flowers-attack.md new file mode 100644 index 0000000000..e400b07b2b --- /dev/null +++ b/.changeset/large-flowers-attack.md @@ -0,0 +1,14 @@ +--- +"@bigcommerce/catalyst-core": patch +--- + +Add visual queues when the cart state is being updated in the Cart page. Will also warn about pending state when trying to navigate away from page. + +## Migration + +1. Update `/core/vibes/soul/sections/cart/client.tsx` to include latest changes: + - Use `isLineItemActionPending` to track when we need to disable checkout button and add a loading state. + - Add skeletons to checkout summary fields that will update when the pending state is complete. + - Add side effects to handle when a user `beforeunload` and when user tries to navigate using a link. + - Add prop to `lineItemActionPendingLabel` to be able to pass in a translatable label to the window alert. +2. Add label to dictionary of choice. diff --git a/core/app/[locale]/(default)/cart/page.tsx b/core/app/[locale]/(default)/cart/page.tsx index df61e28227..c79728585e 100644 --- a/core/app/[locale]/(default)/cart/page.tsx +++ b/core/app/[locale]/(default)/cart/page.tsx @@ -221,6 +221,7 @@ export default async function Cart({ params }: Props) { incrementLineItemLabel={t('increment')} key={`${cart.entityId}-${cart.version}`} lineItemAction={updateLineItem} + lineItemActionPendingLabel={t('cartUpdateInProgress')} shipping={{ action: updateShippingInfo, countries, diff --git a/core/messages/en.json b/core/messages/en.json index 27b6184735..c3a5f3db22 100644 --- a/core/messages/en.json +++ b/core/messages/en.json @@ -286,6 +286,7 @@ "removeItem": "Remove item", "cartCombined": "We noticed you had items saved in a previous cart, so we've added them to your current cart for you.", "cartRestored": "You started a cart on another device, and we've restored it here so you can pick up where you left off.", + "cartUpdateInProgress": "You have a cart update in progress. Are you sure you want to leave this page? Your changes may be lost.", "CheckoutSummary": { "title": "Summary", "subTotal": "Subtotal", diff --git a/core/vibes/soul/sections/cart/client.tsx b/core/vibes/soul/sections/cart/client.tsx index 6b8c4c5e85..dc9fdf0622 100644 --- a/core/vibes/soul/sections/cart/client.tsx +++ b/core/vibes/soul/sections/cart/client.tsx @@ -9,11 +9,13 @@ import { startTransition, useActionState, useEffect, + useMemo, useOptimistic, } from 'react'; import { useFormStatus } from 'react-dom'; import { Button } from '@/vibes/soul/primitives/button'; +import * as Skeleton from '@/vibes/soul/primitives/skeleton'; import { toast } from '@/vibes/soul/primitives/toaster'; import { StickySidebarLayout } from '@/vibes/soul/sections/sticky-sidebar-layout'; import { useEvents } from '~/components/analytics/events'; @@ -127,6 +129,7 @@ export interface CartProps { cart: Cart; couponCode?: CouponCode; shipping?: Shipping; + lineItemActionPendingLabel?: string; } const defaultEmptyState = { @@ -168,6 +171,7 @@ export function CartClient({ incrementLineItemLabel, deleteLineItemLabel, lineItemAction, + lineItemActionPendingLabel = 'You have a cart update in progress. Are you sure you want to leave this page? Your changes may be lost.', checkoutAction, checkoutLabel = 'Checkout', emptyState = defaultEmptyState, @@ -175,7 +179,7 @@ export function CartClient({ shipping, }: CartProps) { const events = useEvents(); - const [state, formAction] = useActionState(lineItemAction, { + const [state, formAction, isLineItemActionPending] = useActionState(lineItemAction, { lineItems: cart.lineItems, lastResult: null, }); @@ -190,6 +194,86 @@ export function CartClient({ } }, [form.errors]); + // Prevent page unload when line item action is pending + useEffect(() => { + const handleBeforeUnload = (event: BeforeUnloadEvent) => { + if (isLineItemActionPending) { + event.preventDefault(); + // eslint-disable-next-line @typescript-eslint/no-deprecated + event.returnValue = ''; // Chrome requires returnValue to be set + + return ''; // For older browsers + } + }; + + if (isLineItemActionPending) { + window.addEventListener('beforeunload', handleBeforeUnload); + } + + return () => { + window.removeEventListener('beforeunload', handleBeforeUnload); + }; + }, [isLineItemActionPending]); + + // Prevent client-side navigation when line item action is pending + useEffect(() => { + const handleClick = (event: MouseEvent) => { + if (isLineItemActionPending && event.target instanceof HTMLElement) { + const link = event.target.closest('a[href]'); + + if ( + link instanceof HTMLAnchorElement && + link.href && + !link.href.startsWith('mailto:') && + !link.href.startsWith('tel:') + ) { + // eslint-disable-next-line no-alert + const shouldNavigate = window.confirm(lineItemActionPendingLabel); + + if (!shouldNavigate) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + }; + + const handleKeyDown = (event: KeyboardEvent) => { + if ( + isLineItemActionPending && + (event.key === 'Enter' || event.key === ' ') && + event.target instanceof HTMLElement + ) { + const link = event.target.closest('a[href]'); + + if ( + link instanceof HTMLAnchorElement && + link.href && + !link.href.startsWith('mailto:') && + !link.href.startsWith('tel:') + ) { + // eslint-disable-next-line no-alert + const shouldNavigate = window.confirm(lineItemActionPendingLabel); + + if (!shouldNavigate) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + }; + + if (isLineItemActionPending) { + document.addEventListener('click', handleClick, true); + document.addEventListener('keydown', handleKeyDown, true); + } + + return () => { + document.removeEventListener('click', handleClick, true); + document.removeEventListener('keydown', handleKeyDown, true); + }; + }, [isLineItemActionPending, lineItemActionPendingLabel]); + const [optimisticLineItems, setOptimisticLineItems] = useOptimistic( state.lineItems, (prevState, formData) => { @@ -226,7 +310,10 @@ export function CartClient({ }, ); - const optimisticQuantity = optimisticLineItems.reduce((total, item) => total + item.quantity, 0); + const optimisticQuantity = useMemo( + () => optimisticLineItems.reduce((total, item) => total + item.quantity, 0), + [optimisticLineItems], + ); if (optimisticQuantity === 0) { return ; @@ -245,7 +332,11 @@ export function CartClient({ {cart.summaryItems.map((summaryItem, index) => (
{summaryItem.label}
-
{summaryItem.value}
+ {isLineItemActionPending ? ( + + ) : ( +
{summaryItem.value}
+ )}
))} @@ -264,10 +355,18 @@ export function CartClient({ )}
{cart.totalLabel ?? 'Total'}
-
{cart.total}
+ {isLineItemActionPending ? ( + + ) : ( +
{cart.total}
+ )}
- + {checkoutLabel} @@ -448,10 +547,12 @@ function CounterForm({ function CheckoutButton({ action, + isCartUpdatePending, ...props -}: { action: Action } & ComponentPropsWithoutRef< - typeof Button ->) { +}: { + action: Action; + isCartUpdatePending: boolean; +} & ComponentPropsWithoutRef) { const [lastResult, formAction] = useActionState(action, null); const [form] = useForm({ lastResult }); @@ -466,13 +567,23 @@ function CheckoutButton({ return (
- + ); } -function SubmitButton(props: ComponentPropsWithoutRef) { +function SubmitButton({ + isCartUpdatePending, + ...props +}: { isCartUpdatePending: boolean } & ComponentPropsWithoutRef) { const { pending } = useFormStatus(); - return + + + ); + } + return (
diff --git a/core/vibes/soul/sections/cart/gift-certificate-code-form/gift-certificate-chip.tsx b/core/vibes/soul/sections/cart/gift-certificate-code-form/gift-certificate-chip.tsx new file mode 100644 index 0000000000..46c3a2b6c5 --- /dev/null +++ b/core/vibes/soul/sections/cart/gift-certificate-code-form/gift-certificate-chip.tsx @@ -0,0 +1,47 @@ +import { getFormProps, getInputProps, useForm } from '@conform-to/react'; +import { parseWithZod } from '@conform-to/zod'; + +import { Chip } from '@/vibes/soul/primitives/chip'; + +import { giftCertificateCodeActionFormDataSchema } from '../schema'; + +export interface GiftCertificateChipProps { + action: (payload: FormData) => void; + onSubmit: (formData: FormData) => void; + giftCertificateCode: string; + removeLabel?: string; +} + +export function GiftCertificateChip({ + giftCertificateCode, + removeLabel = 'Remove gift certificate code', + onSubmit, + action, +}: GiftCertificateChipProps) { + const [form, fields] = useForm({ + onValidate({ formData }) { + return parseWithZod(formData, { + schema: giftCertificateCodeActionFormDataSchema({}), + }); + }, + onSubmit(event, { formData }) { + event.preventDefault(); + + onSubmit(formData); + }, + }); + + return ( + + + + {giftCertificateCode.toUpperCase()} + +
+ ); +} diff --git a/core/vibes/soul/sections/cart/gift-certificate-code-form/index.tsx b/core/vibes/soul/sections/cart/gift-certificate-code-form/index.tsx new file mode 100644 index 0000000000..8c39d9107f --- /dev/null +++ b/core/vibes/soul/sections/cart/gift-certificate-code-form/index.tsx @@ -0,0 +1,148 @@ +'use client'; + +import { getFormProps, getInputProps, SubmissionResult, useForm } from '@conform-to/react'; +import { parseWithZod } from '@conform-to/zod'; +import { startTransition, useActionState, useOptimistic } from 'react'; +import { useFormStatus } from 'react-dom'; + +import { FieldError } from '@/vibes/soul/form/field-error'; +import { Input } from '@/vibes/soul/form/input'; +import { Button } from '@/vibes/soul/primitives/button'; + +import { giftCertificateCodeActionFormDataSchema } from '../schema'; + +import { GiftCertificateChip } from './gift-certificate-chip'; + +type Action = (state: Awaited, payload: Payload) => State | Promise; + +export interface GiftCertificateCodeFormState { + giftCertificateCodes: string[]; + lastResult: SubmissionResult | null; +} + +export interface GiftCertificateCodeFormProps { + action: Action; + giftCertificateCodes?: string[]; + ctaLabel?: string; + disabled?: boolean; + label?: string; + placeholder?: string; + removeLabel?: string; + requiredErrorMessage?: string; +} + +export function GiftCertificateCodeForm({ + action, + giftCertificateCodes, + ctaLabel = 'Apply', + disabled = false, + label = 'Gift certificate code', + placeholder, + removeLabel, + requiredErrorMessage, +}: GiftCertificateCodeFormProps) { + const [state, formAction] = useActionState(action, { + giftCertificateCodes: giftCertificateCodes ?? [], + lastResult: null, + }); + + const schema = giftCertificateCodeActionFormDataSchema({ required_error: requiredErrorMessage }); + + const [optimisticGiftCertificateCodes, setOptimisticGiftCertificateCodes] = useOptimistic< + string[], + FormData + >(state.giftCertificateCodes, (prevState, formData) => { + const submission = parseWithZod(formData, { schema }); + + if (submission.status !== 'success') return prevState; + + switch (submission.value.intent) { + case 'delete': { + const giftCertificateCode = submission.value.giftCertificateCode; + + return prevState.filter((code) => code !== giftCertificateCode); + } + + default: + return prevState; + } + }); + + const [form, fields] = useForm({ + lastResult: state.lastResult, + shouldValidate: 'onBlur', + shouldRevalidate: 'onInput', + onValidate({ formData }) { + return parseWithZod(formData, { schema }); + }, + onSubmit(event, { formData }) { + event.preventDefault(); + + startTransition(() => { + formAction(formData); + setOptimisticGiftCertificateCodes(formData); + }); + }, + }); + + return ( +
+
+ +
+ + {ctaLabel} +
+
+ {optimisticGiftCertificateCodes.length > 0 && ( +
+ {optimisticGiftCertificateCodes.map((giftCertificateCode) => ( + { + startTransition(() => { + formAction(formData); + setOptimisticGiftCertificateCodes(formData); + }); + }} + removeLabel={removeLabel} + /> + ))} +
+ )} + {form.errors?.map((error, index) => ( + {error} + ))} +
+ ); +} + +function SubmitButton({ disabled, ...props }: React.ComponentPropsWithoutRef) { + const { pending } = useFormStatus(); + + return ( + + ); +} diff --git a/core/vibes/soul/sections/gift-certificate-balance-section/schema.ts b/core/vibes/soul/sections/gift-certificate-balance-section/schema.ts new file mode 100644 index 0000000000..476b37422a --- /dev/null +++ b/core/vibes/soul/sections/gift-certificate-balance-section/schema.ts @@ -0,0 +1,6 @@ +import { z } from 'zod'; + +export const giftCertificateCodeSchema = ({ required_error }: { required_error: string }) => + z.object({ + code: z.string({ required_error }).min(1), + }); diff --git a/core/vibes/soul/sections/gift-certificate-purchase-section/index.tsx b/core/vibes/soul/sections/gift-certificate-purchase-section/index.tsx new file mode 100644 index 0000000000..71a6104159 --- /dev/null +++ b/core/vibes/soul/sections/gift-certificate-purchase-section/index.tsx @@ -0,0 +1,169 @@ +'use client'; + +import { SubmissionResult } from '@conform-to/react'; +import { clsx } from 'clsx'; +import { useFormatter } from 'next-intl'; +import { ReactNode, useCallback, useState } from 'react'; + +import { DynamicForm, DynamicFormAction } from '@/vibes/soul/form/dynamic-form'; +import { Field, FieldGroup } from '@/vibes/soul/form/dynamic-form/schema'; +import { Streamable } from '@/vibes/soul/lib/streamable'; +import { GiftCertificateCard } from '@/vibes/soul/primitives/gift-certificate-card'; +import { toast } from '@/vibes/soul/primitives/toaster'; +import { Breadcrumb, Breadcrumbs } from '@/vibes/soul/sections/breadcrumbs'; +import { SectionLayout } from '@/vibes/soul/sections/section-layout'; + +interface Props { + action: DynamicFormAction; + formFields: Array>; + currencyCode?: string; + ctaLabel?: string; + title?: string; + subtitle?: string; + description?: string; + breadcrumbs?: Streamable; + logo: string | { src: string; alt: string }; + expiresAt?: string; + expiresAtLabel?: string; + settings: { + minCustomAmount?: number; + maxCustomAmount?: number; + }; +} + +// eslint-disable-next-line valid-jsdoc +/** + * This component supports various CSS variables for theming. Here's a comprehensive list, along + * with their default values: + * + * ```css + * :root { + * --gift-certificate-purchase-subtitle-font-family: var(--font-family-mono); + * --gift-certificate-purchase-title-font-family: var(--font-family-heading); + * --gift-certificate-description-text: hsl(var(--contrast-500)); + * } + * ``` + */ +export function GiftCertificatePurchaseSection({ + action, + currencyCode, + formFields, + title = 'Purchase a gift certificate', + description = 'Explore our gift certificates, perfect for any occasion. Choose the amount and personalize your message.', + subtitle, + breadcrumbs, + logo, + settings, + expiresAt, + expiresAtLabel, + ctaLabel = 'Add to cart', +}: Props) { + const format = useFormatter(); + const [formattedAmount, setFormattedAmount] = useState(undefined); + const handleFormChange = (e: React.FormEvent) => { + if (!(e.target instanceof HTMLInputElement || e.target instanceof HTMLSelectElement)) { + return; + } + + if (e.target.name !== 'amount') { + return; + } + + if ( + e.target.value.trim() === '' || + Number.isNaN(Number(e.target.value)) || + Number(e.target.value) === 0 || + currencyCode == null + ) { + setFormattedAmount(undefined); + + return; + } + + if (e.target instanceof HTMLInputElement) { + e.target.value = e.target.value.replace(/[^0-9.]/g, ''); + + if (settings.maxCustomAmount && Number(e.target.value) > settings.maxCustomAmount) { + e.target.value = String(settings.maxCustomAmount); + } + } + + const formatted = format.number(Number(e.target.value), { + style: 'currency', + currency: currencyCode, + }); + + setFormattedAmount(formatted); + }; + + const handleSuccess = useCallback((lastResult: SubmissionResult, successMessage: ReactNode) => { + toast.success(successMessage); + }, []); + + return ( + + {breadcrumbs && } + +
+
+
+
+ +
+
+
+ +
+
+
+ {subtitle != null && ( +

+ {subtitle} +

+ )} +

+ {title} +

+
+
+
+
+ +
+
+
+

+ {description} +

+
+ +
+
+
+ ); +} diff --git a/core/vibes/soul/sections/gift-certificates-section/index.tsx b/core/vibes/soul/sections/gift-certificates-section/index.tsx new file mode 100644 index 0000000000..111133cab2 --- /dev/null +++ b/core/vibes/soul/sections/gift-certificates-section/index.tsx @@ -0,0 +1,106 @@ +import { clsx } from 'clsx'; +import { ArrowRightIcon } from 'lucide-react'; + +import { ButtonLink } from '@/vibes/soul/primitives/button-link'; +import { GiftCertificateCard } from '@/vibes/soul/primitives/gift-certificate-card'; +import { SectionLayout } from '@/vibes/soul/sections/section-layout'; + +interface Props { + title?: string; + description?: string; + logo: string | { src: string; alt: string }; + checkBalanceLabel?: string; + checkBalanceHref: string; + exampleBalance?: string; + purchaseLabel?: string; + purchaseHref: string; + variant?: 'left' | 'right'; +} + +// eslint-disable-next-line valid-jsdoc +/** + * This component supports various CSS variables for theming. Here's a comprehensive list, along + * with their default values: + * + * ```css + * :root { + * --gift-certificate-title-font-family: var(--font-family-heading); + * --gift-certificate-title: hsl(var(--foreground)); + * } + * ``` + */ +export function GiftCertificatesSection({ + title = 'Gift certificates', + description = 'Give the perfect gift that never goes out of style. Let friends and loved ones choose exactly what they want from our entire collection.', + logo, + purchaseLabel = 'Shop now', + purchaseHref, + checkBalanceLabel = 'Check Balance', + checkBalanceHref, + exampleBalance, + variant = 'left', +}: Props) { + return ( + +
+
+

+ {title} +

+
+

{description}

+
+
+ +
+ {purchaseLabel} + +
+
+ + {checkBalanceLabel} + +
+
+ +
+
+ +
+
+ +
+ +
+ {purchaseLabel} + +
+
+ + {checkBalanceLabel} + +
+
+
+ ); +} diff --git a/core/vibes/soul/sections/order-details-section/index.tsx b/core/vibes/soul/sections/order-details-section/index.tsx index 4b0e76a516..c74dbef204 100644 --- a/core/vibes/soul/sections/order-details-section/index.tsx +++ b/core/vibes/soul/sections/order-details-section/index.tsx @@ -65,12 +65,19 @@ interface Destination { lineItems: ShipmentLineItem[]; } +interface EmailDestination { + title: string; + email: string; + lineItems: ShipmentLineItem[]; +} + export interface Order { id: string; status: string; statusColor?: 'success' | 'warning' | 'error' | 'info'; date: string; destinations: Destination[]; + emailDestinations: EmailDestination[]; summary: Summary; } @@ -152,6 +159,9 @@ export function OrderDetailsSection({ methodLabel={shipmentMethodLabel} /> ))} + {order.emailDestinations.map((destination, index) => ( + + ))}
@@ -214,6 +224,21 @@ function Shipment({ ); } +function EmailDestination({ destination }: { destination: EmailDestination }) { + return ( +
+
+
+ {destination.title} +
+ {destination.lineItems.map((lineItem) => ( + + ))} +
+
+ ); +} + function ShipmentSkeleton({ shipmentsPlaceholderCount = 1, lineItemsPlaceholderCount = 2, diff --git a/core/vibes/soul/sections/sidebar-menu/sidebar-menu-select.tsx b/core/vibes/soul/sections/sidebar-menu/sidebar-menu-select.tsx index 701171d3dd..3d0407c00a 100644 --- a/core/vibes/soul/sections/sidebar-menu/sidebar-menu-select.tsx +++ b/core/vibes/soul/sections/sidebar-menu/sidebar-menu-select.tsx @@ -1,6 +1,6 @@ 'use client'; -import { Select } from '@/vibes/soul/primitives/select'; +import { Select } from '@/vibes/soul/form/select'; import { usePathname, useRouter } from '~/i18n/routing'; export function SidebarMenuSelect({ links }: { links: Array<{ href: string; label: string }> }) { @@ -9,11 +9,11 @@ export function SidebarMenuSelect({ links }: { links: Array<{ href: string; labe return (