diff --git a/.github/workflows/cli-integration.yml b/.github/workflows/cli-integration.yml new file mode 100644 index 0000000000..fb9b210ca8 --- /dev/null +++ b/.github/workflows/cli-integration.yml @@ -0,0 +1,55 @@ +name: Create Catalyst CLI + +on: + push: + branches: [main] + pull_request: + types: [opened, synchronize] + merge_group: + types: [checks_requested] + +jobs: + integration-tests: + name: Integration Tests + + runs-on: ubuntu-latest + + env: + TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} + TURBO_TEAM: ${{ vars.TURBO_TEAM }} + TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} + BIGCOMMERCE_STORE_HASH: ${{ secrets.BIGCOMMERCE_STORE_HASH }} + BIGCOMMERCE_CUSTOMER_IMPERSONATION_TOKEN: ${{ secrets.BIGCOMMERCE_CUSTOMER_IMPERSONATION_TOKEN }} + + steps: + - name: Checkout code + uses: actions/checkout@main + with: + fetch-depth: 2 + + - uses: pnpm/action-setup@v2 + + - name: Use Node.js + uses: actions/setup-node@main + with: + node-version-file: ".nvmrc" + cache: "pnpm" + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build CLI + run: pnpm build + working-directory: packages/create-catalyst + + - name: Run CLI + run: | + node dist/index.js \ + --ghRef ${{ github.sha }} \ + --projectDir ${{ runner.temp }} \ + --projectName catalyst-integration-test \ + --channelId 1 \ + --accessToken some_access_token \ + --storeHash ${{ secrets.BIGCOMMERCE_STORE_HASH }} \ + --customerImpersonationToken ${{ secrets.BIGCOMMERCE_CUSTOMER_IMPERSONATION_TOKEN }} + working-directory: packages/create-catalyst diff --git a/.github/workflows/cli-unit.yml b/.github/workflows/cli-unit.yml new file mode 100644 index 0000000000..e4be0377e1 --- /dev/null +++ b/.github/workflows/cli-unit.yml @@ -0,0 +1,43 @@ +name: Create Catalyst CLI + +on: + push: + branches: [main] + pull_request: + types: [opened, synchronize] + merge_group: + types: [checks_requested] + +jobs: + unit-tests: + name: Unit Tests + + runs-on: ubuntu-latest + + env: + TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} + TURBO_TEAM: ${{ vars.TURBO_TEAM }} + TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} + BIGCOMMERCE_STORE_HASH: ${{ secrets.BIGCOMMERCE_STORE_HASH }} + BIGCOMMERCE_CUSTOMER_IMPERSONATION_TOKEN: ${{ secrets.BIGCOMMERCE_CUSTOMER_IMPERSONATION_TOKEN }} + + steps: + - name: Checkout code + uses: actions/checkout@main + with: + fetch-depth: 2 + + - uses: pnpm/action-setup@v2 + + - name: Use Node.js + uses: actions/setup-node@main + with: + node-version-file: ".nvmrc" + cache: "pnpm" + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Run Tests + run: pnpm test + working-directory: packages/create-catalyst diff --git a/packages/create-catalyst/.eslintrc.cjs b/packages/create-catalyst/.eslintrc.cjs index d68fbfbc3b..3549aaf941 100644 --- a/packages/create-catalyst/.eslintrc.cjs +++ b/packages/create-catalyst/.eslintrc.cjs @@ -6,6 +6,8 @@ const config = { extends: ['@bigcommerce/catalyst/base', '@bigcommerce/catalyst/prettier'], rules: { 'no-console': 'off', + 'import/no-named-as-default': 'off', + '@typescript-eslint/naming-convention': 'off', }, ignorePatterns: ['/dist/**'], }; diff --git a/packages/create-catalyst/.swcrc b/packages/create-catalyst/.swcrc new file mode 100644 index 0000000000..fff5a4ccba --- /dev/null +++ b/packages/create-catalyst/.swcrc @@ -0,0 +1,17 @@ +{ + "$schema": "https://json.schemastore.org/swcrc", + "sourceMaps": true, + "jsc": { + "parser": { + "syntax": "typescript", + "decorators": true, + "dynamicImport": true + }, + "transform": { + "legacyDecorator": true, + "decoratorMetadata": true + }, + "baseUrl": "./" + }, + "minify": false +} diff --git a/packages/create-catalyst/README.md b/packages/create-catalyst/README.md index 1c622d5164..befcda9df6 100644 --- a/packages/create-catalyst/README.md +++ b/packages/create-catalyst/README.md @@ -1,55 +1,23 @@ -# packages/create-catalyst +# create-catalyst -> [!WARNING] -> The create-catalyst package is in development and not published to the NPM registry +Create a new Catalyst project, optionally connect the project to a BigCommerce store. Also supports "switching" the store that Catalyst is connected to by running `init`. -Scaffolding for Catalyst storefront projects. - -## Usage - -**NPM:** - -```sh -npm create @bigcommerce/catalyst@latest my-catalyst-store -``` - -**PNPM:** +## NPM ```sh -pnpm create @bigcommerce/catalyst@latest my-catalyst-store +npm create catalyst-storefront@latest --storeHash your_store_hash --accessToken your_access_token ``` -**Yarn:** +## PNPM ```sh -yarn create @bigcommerce/catalyst@latest my-catalyst-store +pnpm create catalyst-storefront@latest --storeHash your_store_hash --accessToken your_access_token ``` -## Contributing - -**Prerequisites:** - -- Node `>=18.16` -- [Verdaccio](https://verdaccio.org/) `>=5` - -**Developing Locally:** - -While developing `create-catalyst` locally, it's essential to test your changes before publishing them to NPM. To achieve this, we utilize Verdaccio, a lightweight private npm proxy registry that you can run in your local environment. By publishing `create-catalyst` to Verdaccio during local development, we can point `[yarn|npm|pnpm] create @bigcommerce/catalyst` at the Verdaccio registry URL and observe how our changes will behave once they are published to NPM. - -1. Install Verdaccio: https://verdaccio.org/docs/installation -2. Run Verdaccio: `verdaccio --listen 4873` -3. Add an NPM user with `@bigcommerce` scope to Verdaccio: `npm adduser --scope=@bigcommerce --registry=http://localhost:4873` - -> ⚠️ **IMPORTANT:** NPM registry data is immutable, meaning once published, a package cannot change. Be careful to ensure that you do not run commands such as `publish` against the default NPM registry if your work is not ready to be published. Always explicitly pass `--registry=http://localhost:` with commands that modify the registry (such as `publish`) to ensure you only publish to Verdaccio when working locally. - -4. If necessary, run `pnpm build` and `pnpm publish --registry=http://localhost:4873` in each Catalyst-scoped package required by relevant examples listed in `apps/` (e.g., Catalyst `core` examples require `@bigcommerce/components`, `@bigcommerce/eslint-config-catalyst`, `@bigcommerce/catalyst-client`) -5. Run `pnpm build` and `pnpm publish --registry=http://localhost:4873` in the `@bigcommerce/create-catalyst` package -6. Confirm published packages are listed in Verdaccio: http://localhost:4873 - -In order to point `npm create`, `pnpm create`, and/or `yarn create` to the Verdaccio registry, run one or more of the following commands against the package manager's global configuration: - -- **NPM:** `npm config set @bigcommerce:registry http://localhost:4873` -- **PNPM:** `pnpm config set @bigcommerce:registry http://localhost:4873` -- **Yarn:** `yarn config set npmScopes.bigcommerce.npmRegistryServer "http://localhost:4873" -H` and then `yarn config set unsafeHttpWhitelist "localhost" -H` +# To Do -7. Finally, navigate to the directory in which you'd like to create a new Catalyst storefront, and run `[yarn|npm|pnpm] create @bigcommerce/catalyst name-of-your-catalyst-storefront` +- [ ] Channel Site Routes +- [ ] Check Active Storeront Limit +- [ ] Prompt Sample Data API for New Channels +- [ ] Yarn module resolution bug +- [ ] Write root `.vscode/settings.json` diff --git a/packages/create-catalyst/flow.mermaid b/packages/create-catalyst/flow.mermaid new file mode 100644 index 0000000000..ccd1d78ea0 --- /dev/null +++ b/packages/create-catalyst/flow.mermaid @@ -0,0 +1,30 @@ +flowchart TD + A[npm/pnpm/yarn create @bigcommerce/catalyst@latest] --> B[Login to BigCommerce Store] + A --> C[Use Sample Data] + C --> D[@todo] + B --> E[Check Active Storefront Limit for Store] + E -->|User Allowed to Create Channel| F[Create New Channel] + E -->|User Unable to Create Channel| G[Use Existing Channel] + F -->|YES| H[Enter a Name for Your New Channel] + F -->|NO| G + G --> M + H --> I[Channel Name Already Taken] + I --> H + H --> J[Channel Created Successfully] + J --> K[Do you want create Sample Data for your New Channel?] + K -->|YES| L[Hit Cloudflare Worker to Seed New Channel] + K -->|NO| M[Create Channel Site URL] + L --> M + M --> N[Create Channel Site Checkout URL] + N --> O[Create Channel Routes] + O --> P[Create Customer Impersonation Token] + P --> Q[Generate JWT Signing Secret for NextAuth] + Q --> R[Create Required Environment Variables to run Catalyst Next.js App] + R --> S[Clone Catalyst Template from GitHub] + S --> T[Copy Catalyst Components from GitHub] + T --> U[Reconcile Configuration Files - Tailwind, TsConfig, Package.json] + U --> V[Write Configuration Files and Environment Variable File] + V --> W[Install Dependencies] + W --> X[Run GraphQL Codegen] + X --> Y[Lint to Validate Types] + Y --> Z[Successfully Created Catalyst Project] diff --git a/packages/create-catalyst/jest.config.cjs b/packages/create-catalyst/jest.config.cjs new file mode 100644 index 0000000000..20f733e616 --- /dev/null +++ b/packages/create-catalyst/jest.config.cjs @@ -0,0 +1,12 @@ +module.exports = { + extensionsToTreatAsEsm: ['.ts'], + transform: { + '^.+\\.(t|j)s?$': '@swc/jest', + }, + transformIgnorePatterns: [], + // moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], + moduleNameMapper: { + '^(\\.{1,2}/.*)\\.js$': '$1', + }, + testEnvironment: 'node', +}; diff --git a/packages/create-catalyst/package.json b/packages/create-catalyst/package.json index c47fdeb104..3eea1ad135 100644 --- a/packages/create-catalyst/package.json +++ b/packages/create-catalyst/package.json @@ -7,17 +7,44 @@ "dist" ], "scripts": { + "dev": "tsup --watch", "typecheck": "tsc --noEmit", "lint": "eslint . --max-warnings 0", - "test": "jest" + "test": "jest", + "build": "tsup" }, "engines": { "node": ">=18.16" }, + "dependencies": { + "@inquirer/prompts": "^3.3.0", + "chalk": "^5.3.0", + "commander": "^11.1.0", + "fs-extra": "^11.2.0", + "giget": "^1.2.1", + "lodash.kebabcase": "^4.1.1", + "lodash.merge": "^4.6.2", + "lodash.set": "^4.3.2", + "lodash.unset": "^4.5.2", + "msw": "^2.1.7", + "nypm": "^0.3.6", + "ora": "^8.0.1", + "zod": "^3.22.4", + "zod-validation-error": "^3.0.2" + }, "devDependencies": { "@bigcommerce/eslint-config": "^2.7.0", "@bigcommerce/eslint-config-catalyst": "workspace:^", + "@swc/core": "^1.3.107", + "@swc/jest": "^0.2.34", + "@types/fs-extra": "^11.0.4", + "@types/jest": "^29.5.11", + "@types/lodash.kebabcase": "^4.1.9", + "@types/lodash.merge": "^4.6.9", + "@types/lodash.set": "^4.3.9", + "@types/lodash.unset": "^4.5.9", "@types/node": "^18.17.12", + "@types/prompts": "^2.4.9", "eslint": "^8.55.0", "jest": "^29.7.0", "prettier": "^3.1.1", diff --git a/packages/create-catalyst/src/commands/create.ts b/packages/create-catalyst/src/commands/create.ts new file mode 100644 index 0000000000..bdca12b8a6 --- /dev/null +++ b/packages/create-catalyst/src/commands/create.ts @@ -0,0 +1,185 @@ +import { input, select } from '@inquirer/prompts'; +import chalk from 'chalk'; +import { exec as execCallback } from 'child_process'; +import { promisify } from 'util'; +import { z } from 'zod'; + +import { cloneCatalyst } from '../utils/clone-catalyst.js'; +import { Https } from '../utils/https.js'; +import { installDependencies } from '../utils/install-dependencies.js'; +import { login } from '../utils/login.js'; +import { parse } from '../utils/parse.js'; +import { getPackageManager } from '../utils/pm.js'; +import { projectConfig } from '../utils/project-config.js'; +import { spinner } from '../utils/spinner.js'; +import { writeEnv } from '../utils/write-env.js'; + +const exec = promisify(execCallback); + +export const create = async (opts: unknown) => { + const ProjectNameSchema = z.string().optional(); + const ProjectDirSchema = z.string().optional(); + const BigCommerceHostnameSchema = z.string().min(1); + const SampleDataApiUrlSchema = z.string().url(); + const PackageManagerSchema = z.enum(['npm', 'pnpm', 'yarn']).optional(); + const GhRefSchema = z.string(); + const StoreHashSchema = z.string().optional(); + const AccessTokenSchema = z.string().optional(); + const ChannelIdSchema = z.string().optional(); + const CustomerImpersonationTokenSchema = z.string().optional(); + + const OptionsSchema = z.object({ + projectName: ProjectNameSchema, + projectDir: ProjectDirSchema, + bigCommerceHostname: BigCommerceHostnameSchema, + sampleDataApiUrl: SampleDataApiUrlSchema, + packageManager: PackageManagerSchema, + ghRef: GhRefSchema, + storeHash: StoreHashSchema, + accessToken: AccessTokenSchema, + channelId: ChannelIdSchema, + customerImpersonationToken: CustomerImpersonationTokenSchema, + }); + + const options = parse(opts, OptionsSchema); + + const pm = getPackageManager(options.packageManager); + const bigCommerceApiUrl = `https://api.${options.bigCommerceHostname}`; + const bigCommerceAuthUrl = `https://login.${options.bigCommerceHostname}`; + const { projectName, projectDir } = await projectConfig({ + projectDir: options.projectDir, + projectName: options.projectName, + }); + const { storeHash, accessToken } = await login( + bigCommerceAuthUrl, + options.storeHash, + options.accessToken, + ); + + if (!storeHash || !accessToken) { + console.log(`\nCreating '${projectName}' at '${projectDir}'\n`); + + await cloneCatalyst({ projectDir, projectName, ghRef: options.ghRef }); + + console.log(`\nUsing ${chalk.bold(pm)}\n`); + + await installDependencies(projectDir, pm); + + console.log( + [ + `\n${chalk.green('Success!')} Created '${projectName}' at '${projectDir}'\n`, + `Next steps:`, + chalk.yellow(`\n- cd ${projectName} && cp .env.example .env.local`), + chalk.yellow(`\n- Populate .env.local with your BigCommerce API credentials\n`), + ].join('\n'), + ); + + process.exit(0); + } + + const bc = new Https({ bigCommerceApiUrl, storeHash, accessToken }); + + let channelId = options.channelId ? options.channelId : 0; + let customerImpersonationToken = options.customerImpersonationToken + ? options.customerImpersonationToken + : ''; + + if (!channelId || !customerImpersonationToken) { + const { data: channels } = await bc.channels(); + const { + features: { storefront_limits: limits }, + } = await bc.storeInformation(); + + const activeStatus = ['prelaunch', 'active', 'connected']; + const activeChannels = channels.filter((ch) => activeStatus.includes(ch.status)); + + let canCreateChannel = true; + + if (activeChannels.length >= limits.active) { + canCreateChannel = false; + } else if (channels.length >= limits.total_including_inactive) { + canCreateChannel = false; + } else { + console.log(`${limits.active - activeChannels.length} active channels remaining.`); + } + + if (!canCreateChannel) { + const channelSortOrder = ['catalyst', 'next', 'bigcommerce']; + + const existingChannel = await select({ + message: 'Which channel would you like to use?', + choices: activeChannels + .sort( + (a, b) => channelSortOrder.indexOf(a.platform) - channelSortOrder.indexOf(b.platform), + ) + .map((ch) => ({ + name: ch.name, + value: ch, + description: `Channel Platform: ${ + ch.platform === 'bigcommerce' + ? 'Stencil' + : ch.platform.charAt(0).toUpperCase() + ch.platform.slice(1) + }`, + })), + }); + + channelId = existingChannel.id; + + const { + data: { token }, + } = await bc.customerImpersonationToken(channelId); + + customerImpersonationToken = token; + } else { + const newChannelName = await input({ + message: 'What would you like to name your new channel?', + }); + + const sampleDataApi = new Https({ + sampleDataApiUrl: options.sampleDataApiUrl, + storeHash, + accessToken, + }); + + const { + data: { id: createdChannelId, storefront_api_token: storefrontApiToken }, + } = await sampleDataApi.createChannel(newChannelName); + + channelId = createdChannelId; + customerImpersonationToken = storefrontApiToken; + } + } + + console.log(`\nCreating '${projectName}' at '${projectDir}'\n`); + + await cloneCatalyst({ projectDir, projectName, ghRef: options.ghRef }); + + writeEnv(projectDir, { + channelId: channelId.toString(), + storeHash, + accessToken, + customerImpersonationToken, + }); + + console.log(`\nUsing ${chalk.bold(pm)}\n`); + + await installDependencies(projectDir, pm); + + await spinner(exec(`${pm} run codegen`, { cwd: projectDir }), { + text: 'Generating GraphQL types...', + successText: 'GraphQL types generated successfully', + failText: (err) => chalk.red(`Failed to generate GraphQL types: ${err.message}`), + }); + + await spinner(exec(`${pm} run lint --fix`, { cwd: projectDir }), { + text: 'Linting to validate generated types...', + successText: 'GraphQL types validated successfully', + failText: (err) => chalk.red(`Failed to validate GraphQL types: ${err.message}`), + }); + + console.log( + `\n${chalk.green('Success!')} Created '${projectName}' at '${projectDir}'\n`, + '\nNext steps:\n', + chalk.yellow(`\ncd ${projectName} && ${pm} run dev\n`), + ); +}; diff --git a/packages/create-catalyst/src/commands/init.ts b/packages/create-catalyst/src/commands/init.ts new file mode 100644 index 0000000000..0c1b3dc6ff --- /dev/null +++ b/packages/create-catalyst/src/commands/init.ts @@ -0,0 +1,115 @@ +import { input, select } from '@inquirer/prompts'; +import chalk from 'chalk'; +import * as z from 'zod'; + +import { Https } from '../utils/https.js'; +import { login } from '../utils/login.js'; +import { parse } from '../utils/parse.js'; +import { writeEnv } from '../utils/write-env.js'; + +export const init = async (opts: unknown) => { + const BigCommerceHostnameSchema = z.string().min(1); + const SampleDataApiUrlSchema = z.string().url(); + const StoreHashSchema = z.string().optional(); + const AccessTokenSchema = z.string().optional(); + + const OptionsSchema = z.object({ + bigCommerceHostname: BigCommerceHostnameSchema, + sampleDataApiUrl: SampleDataApiUrlSchema, + storeHash: StoreHashSchema, + accessToken: AccessTokenSchema, + }); + + const options = parse(opts, OptionsSchema); + + const bigCommerceApiUrl = `https://api.${options.bigCommerceHostname}`; + const bigCommerceAuthUrl = `https://login.${options.bigCommerceHostname}`; + const projectDir = process.cwd(); + const { storeHash, accessToken } = await login( + bigCommerceAuthUrl, + options.storeHash, + options.accessToken, + ); + + if (!storeHash || !accessToken) { + console.log( + chalk.yellow('\nNo store hash or access token provided. Unable to write new environment.\n'), + ); + + process.exit(1); + } + + const bc = new Https({ bigCommerceApiUrl, storeHash, accessToken }); + + const { data: channels } = await bc.channels(); + const { + features: { storefront_limits: limits }, + } = await bc.storeInformation(); + + const activeStatus = ['prelaunch', 'active', 'connected']; + const activeChannels = channels.filter((ch) => activeStatus.includes(ch.status)); + + let canCreateChannel = true; + + if (activeChannels.length >= limits.active) { + canCreateChannel = false; + } else if (channels.length >= limits.total_including_inactive) { + canCreateChannel = false; + } else { + console.log(`${limits.active - activeChannels.length} active channels remaining.`); + } + + let channelId = 0; + let customerImpersonationToken = ''; + + if (!canCreateChannel) { + const channelSortOrder = ['catalyst', 'next', 'bigcommerce']; + + const existingChannel = await select({ + message: 'Which channel would you like to use?', + choices: activeChannels + .sort((a, b) => channelSortOrder.indexOf(a.platform) - channelSortOrder.indexOf(b.platform)) + .map((ch) => ({ + name: ch.name, + value: ch, + description: `Channel Platform: ${ + ch.platform === 'bigcommerce' + ? 'Stencil' + : ch.platform.charAt(0).toUpperCase() + ch.platform.slice(1) + }`, + })), + }); + + channelId = existingChannel.id; + + const { + data: { token }, + } = await bc.customerImpersonationToken(channelId); + + customerImpersonationToken = token; + } else { + const newChannelName = await input({ + message: 'What would you like to name your new channel?', + }); + + const sampleDataApi = new Https({ + sampleDataApiUrl: options.sampleDataApiUrl, + storeHash, + accessToken, + }); + + const { + data: { id: createdChannelId, storefront_api_token: storefrontApiToken }, + } = await sampleDataApi.createChannel(newChannelName); + + channelId = createdChannelId; + customerImpersonationToken = storefrontApiToken; + } + + writeEnv(projectDir, { + channelId: channelId.toString(), + storeHash, + accessToken, + customerImpersonationToken, + }); +}; diff --git a/packages/create-catalyst/src/index.ts b/packages/create-catalyst/src/index.ts new file mode 100644 index 0000000000..33792527af --- /dev/null +++ b/packages/create-catalyst/src/index.ts @@ -0,0 +1,89 @@ +#!/usr/bin/env node + +import chalk from 'chalk'; +import { Command, Option } from 'commander'; + +import PACKAGE_INFO from '../package.json'; + +import { create } from './commands/create.js'; +import { init } from './commands/init.js'; + +console.log(chalk.cyanBright(`\n◢ ${PACKAGE_INFO.name} v${PACKAGE_INFO.version}\n`)); + +const program = new Command(); + +const projectName = new Option('--projectName ', 'Project name').env('PROJECT_NAME'); + +const projectDir = new Option('--projectDir ', 'Project installation directory').env( + 'PROJECT_DIR', +); + +const bigCommerceHostname = new Option('--bigCommerceHostname ', 'BigCommerce Hostname') + .default('bigcommerce.com') + .env('BIGCOMMERCE_HOSTNAME') + .hideHelp(); + +const sampleDataApiUrl = new Option('--sampleDataApiUrl ', 'Sample Data API URL') + .default('https://api.bc-sample.store') + .env('SAMPLE_DATA_URL') + .hideHelp(); + +const packageManager = new Option('--packageManager ', 'Package manager to use') + .env('PACKAGE_MANAGER') + .hideHelp(); + +const ghRef = new Option( + '--ghRef ', + 'Clone a specific ref from the bigcommerce/catalyst repository', +) + .default('main') + .env('GH_REF') + .hideHelp(); + +const storeHash = new Option('--storeHash ', 'BigCommerce store hash').env( + 'BIGCOMMERCE_STORE_HASH', +); + +const accessToken = new Option('--accessToken ', 'BigCommerce access token').env( + 'BIGCOMMERCE_ACCESS_TOKEN', +); + +const channelId = new Option('--channelId ', 'BigCommerce channel ID').env( + 'BIGCOMMERCE_CHANNEL_ID', +); + +const customerImpersonationToken = new Option( + '--customerImpersonationToken ', + 'BigCommerce customer impersonation token', +).env('BIGCOMMERCE_CUSTOMER_IMPERSONATION_TOKEN'); + +program + .name(PACKAGE_INFO.name) + .description('A command line tool to create a new Catalyst project.') + .version(PACKAGE_INFO.version); + +program + .command('create', { isDefault: true }) + .description('Command to scaffold and connect a Catalyst storefront to your BigCommerce store') + .addOption(projectName) + .addOption(projectDir) + .addOption(channelId) + .addOption(customerImpersonationToken) + .addOption(bigCommerceHostname) + .addOption(sampleDataApiUrl) + .addOption(packageManager) + .addOption(ghRef) + .addOption(storeHash) + .addOption(accessToken) + .action((opts) => create(opts)); + +program + .command('init') + .description('Connect a BigCommerce store with an existing Catalyst project') + .addOption(bigCommerceHostname) + .addOption(sampleDataApiUrl) + .addOption(storeHash) + .addOption(accessToken) + .action((opts) => init(opts)); + +program.parse(process.argv); diff --git a/packages/create-catalyst/src/utils/clone-catalyst.ts b/packages/create-catalyst/src/utils/clone-catalyst.ts new file mode 100644 index 0000000000..739c25fb13 --- /dev/null +++ b/packages/create-catalyst/src/utils/clone-catalyst.ts @@ -0,0 +1,92 @@ +import chalk from 'chalk'; +import { copySync, readJsonSync, removeSync, writeJsonSync } from 'fs-extra/esm'; +import { downloadTemplate } from 'giget'; +import merge from 'lodash.merge'; +import set from 'lodash.set'; +import unset from 'lodash.unset'; +import { join } from 'path'; +import * as z from 'zod'; + +import { spinner } from './spinner.js'; + +export const cloneCatalyst = async ({ + projectDir, + projectName, + ghRef = 'main', +}: { + projectDir: string; + projectName: string; + ghRef?: string; +}) => { + await spinner( + downloadTemplate(`github:bigcommerce/catalyst/apps/core#${ghRef}`, { + dir: projectDir, + offline: false, + }), + { + text: 'Cloning Catalyst template...', + successText: 'Catalyst template cloned successfully', + failText: (err) => chalk.red(`Failed to clone Catalyst template: ${err.message}`), + }, + ); + + await spinner( + downloadTemplate(`github:bigcommerce/catalyst/packages/components#${ghRef}`, { + dir: join(projectDir, 'tmp'), + offline: false, + }), + { + text: 'Cloning Catalyst components...', + successText: 'Catalyst components cloned successfully', + failText: (err) => chalk.red(`Failed to clone Catalyst components: ${err.message}`), + }, + ); + + copySync(join(projectDir, 'tmp/src/components'), join(projectDir, 'components', 'ui')); + copySync(join(projectDir, 'tmp/tailwind.config.js'), join(projectDir, 'tailwind.config.js')); + + const packageJson = z + .object({}) + .passthrough() + .parse( + merge( + {}, + readJsonSync(join(projectDir, 'tmp/package.json')), + readJsonSync(join(projectDir, 'package.json')), + { name: projectName, description: '' }, + ), + ); + + unset(packageJson, 'private'); + unset(packageJson, 'exports'); + unset(packageJson, 'sideEffects'); + unset(packageJson, 'peerDependencies'); // will go away + unset(packageJson, 'dependencies.@bigcommerce/components'); // will go away + unset(packageJson, 'devDependencies.react'); // will go away + unset(packageJson, 'devDependencies.react-dom'); // will go away + + set(packageJson, 'dependencies.@bigcommerce/catalyst-client', `^0.1.0`); + set(packageJson, 'devDependencies.@bigcommerce/eslint-config-catalyst', `^0.1.0`); + + writeJsonSync(join(projectDir, 'package.json'), packageJson, { spaces: 2 }); + + const tsConfigJson = z + .object({}) + .passthrough() + .parse( + merge( + {}, + readJsonSync(join(projectDir, 'tmp/tsconfig.json')), + readJsonSync(join(projectDir, 'tsconfig.json')), + ), + ); + + unset(tsConfigJson, 'compilerOptions.declaration'); + unset(tsConfigJson, 'compilerOptions.declarationMap'); + + set(tsConfigJson, 'compilerOptions.paths.@bigcommerce/components/*', ['./components/ui/*']); + + writeJsonSync(join(projectDir, 'tsconfig.json'), tsConfigJson, { spaces: 2 }); + + removeSync(join(projectDir, 'tmp')); +}; diff --git a/packages/create-catalyst/src/utils/https.ts b/packages/create-catalyst/src/utils/https.ts new file mode 100644 index 0000000000..bf7b1eab24 --- /dev/null +++ b/packages/create-catalyst/src/utils/https.ts @@ -0,0 +1,274 @@ +/* eslint-disable @typescript-eslint/unified-signatures */ + +import chalk from 'chalk'; +import { z } from 'zod'; + +import { parse } from './parse.js'; + +export class Https { + DEVICE_OAUTH_CLIENT_ID = 'o094w49fnipwgbo0h9772pc2q6pw1p7'; + + bigCommerceApiUrl: string; + bigCommerceAuthUrl: string; + sampleDataApiUrl: string; + storeHash: string; + accessToken: string; + + constructor({ + bigCommerceApiUrl, + storeHash, + accessToken, + }: { + bigCommerceApiUrl: string; + storeHash: string; + accessToken: string; + }); + constructor({ + sampleDataApiUrl, + storeHash, + accessToken, + }: { + sampleDataApiUrl: string; + storeHash: string; + accessToken: string; + }); + constructor({ bigCommerceAuthUrl }: { bigCommerceAuthUrl: string }); + constructor({ + bigCommerceApiUrl, + bigCommerceAuthUrl, + sampleDataApiUrl, + storeHash, + accessToken, + }: { + bigCommerceApiUrl?: string; + bigCommerceAuthUrl?: string; + sampleDataApiUrl?: string; + storeHash?: string; + accessToken?: string; + }) { + this.bigCommerceApiUrl = bigCommerceApiUrl || ''; + this.bigCommerceAuthUrl = bigCommerceAuthUrl || ''; + this.sampleDataApiUrl = sampleDataApiUrl || ''; + this.storeHash = storeHash || ''; + this.accessToken = accessToken || ''; + } + + auth(path: string, opts: RequestInit = {}) { + if (!this.bigCommerceAuthUrl) { + throw new Error('bigCommerceAuthUrl is required to make API requests'); + } + + const { headers = {}, ...rest } = opts; + + const options = { + method: 'POST', + headers: { + ...headers, + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + ...rest, + }; + + return fetch(`${this.bigCommerceAuthUrl}${path}`, options); + } + + async getDeviceCode() { + const response = await this.auth('/device/token', { + body: JSON.stringify({ + scopes: [ + 'store_v2_content', + 'store_v2_information', + 'store_v2_products', + 'store_cart_read_only', + 'store_sites', + 'store_channel_settings', + 'store_storefront_api_customer_impersonation', + ].join(' '), + client_id: this.DEVICE_OAUTH_CLIENT_ID, + }), + }); + + if (!response.ok) { + console.error( + chalk.red(`\nPOST /device/token failed: ${response.status} ${response.statusText}\n`), + ); + process.exit(1); + } + + const DeviceCodeSchema = z.object({ + device_code: z.string(), + user_code: z.string(), + verification_uri: z.string(), + expires_in: z.number(), + interval: z.number(), + }); + + return parse(await response.json(), DeviceCodeSchema); + } + + async checkDeviceCode(deviceCode: string) { + const response = await this.auth('/device/token', { + body: JSON.stringify({ + device_code: deviceCode, + client_id: this.DEVICE_OAUTH_CLIENT_ID, + }), + }); + + if (response.status !== 200) { + console.error( + chalk.red(`\nPOST /device/token failed: ${response.status} ${response.statusText}\n`), + ); + process.exit(1); + } + + const DeviceCodeSuccessSchema = z.object({ + access_token: z.string(), + store_hash: z.string(), + context: z.string(), + api_uri: z.string().url(), + }); + + return parse(await response.json(), DeviceCodeSuccessSchema); + } + + BigCommerceV3ApiResponseSchema = (schema: z.ZodType) => + z.object({ + data: schema, + meta: z.object({}), + }); + + api(path: string, opts: RequestInit = {}) { + if (!this.bigCommerceApiUrl || !this.storeHash || !this.accessToken) { + throw new Error( + 'bigCommerceApiUrl, storeHash, and accessToken are required to make API requests', + ); + } + + const { headers = {}, ...rest } = opts; + + const options = { + headers: { + ...headers, + Accept: 'application/json', + 'X-Auth-Token': this.accessToken, + }, + ...rest, + }; + + return fetch(`${this.bigCommerceApiUrl}/stores/${this.storeHash}${path}`, options); + } + + async storeInformation() { + const res = await this.api('/v2/store'); + + if (!res.ok) { + console.error(chalk.red(`\nGET /v2/store failed: ${res.status} ${res.statusText}\n`)); + process.exit(1); + } + + const BigCommerceStoreInfo = z.object({ + features: z.object({ + storefront_limits: z.object({ + active: z.number(), + total_including_inactive: z.number(), + }), + }), + }); + + return parse(await res.json(), BigCommerceStoreInfo); + } + + async channels() { + const res = await this.api('/v3/channels'); + + if (!res.ok) { + console.error(chalk.red(`\nGET /v3/channels failed: ${res.status} ${res.statusText}\n`)); + process.exit(1); + } + + const BigCommerceChannelsV3ResponseSchema = this.BigCommerceV3ApiResponseSchema( + z.array( + z.object({ + id: z.number(), + name: z.string(), + status: z.string(), + platform: z.string(), + }), + ), + ); + + return parse(await res.json(), BigCommerceChannelsV3ResponseSchema); + } + + async customerImpersonationToken(channelId: number) { + const res = await this.api('/v3/storefront/api-token-customer-impersonation', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ expires_at: 2147483647, channel_id: channelId }), + }); + + if (!res.ok) { + console.error( + chalk.red( + `\nPOST /v3/storefront/api-token-customer-impersonation failed: ${res.status} ${res.statusText}\n`, + ), + ); + process.exit(1); + } + + const BigCommerceCustomerImpersonationTokenSchema = z.object({ + data: z.object({ + token: z.string(), + }), + }); + + return parse(await res.json(), BigCommerceCustomerImpersonationTokenSchema); + } + + sampleDataApi(path: string, opts: RequestInit = {}) { + if (!this.sampleDataApiUrl || !this.storeHash || !this.accessToken) { + throw new Error( + 'sampleDataApiUrl, storeHash, and accessToken are required to make API requests', + ); + } + + const { headers = {}, ...rest } = opts; + + const options = { + method: 'POST', + headers: { + ...headers, + Accept: 'application/json', + 'Content-Type': 'application/json', + 'X-Auth-Token': this.accessToken, + }, + ...rest, + }; + + return fetch(`${this.sampleDataApiUrl}/stores/${this.storeHash}${path}`, options); + } + + async createChannel(channelName: string) { + const res = await this.sampleDataApi('/v3/channels/catalyst', { + body: JSON.stringify({ name: channelName }), + }); + + if (!res.ok) { + console.error( + chalk.red(`\nPOST /v3/channels/catalyst failed: ${res.status} ${res.statusText}\n`), + ); + process.exit(1); + } + + const SampleDataChannelCreateSchema = z.object({ + data: z.object({ + id: z.number(), + name: z.string().min(1), + storefront_api_token: z.string(), + }), + }); + + return parse(await res.json(), SampleDataChannelCreateSchema); + } +} diff --git a/packages/create-catalyst/src/utils/install-dependencies.ts b/packages/create-catalyst/src/utils/install-dependencies.ts new file mode 100644 index 0000000000..6403ce2561 --- /dev/null +++ b/packages/create-catalyst/src/utils/install-dependencies.ts @@ -0,0 +1,12 @@ +import chalk from 'chalk'; +import { installDependencies as installDeps } from 'nypm'; + +import { type PackageManager } from './pm.js'; +import { spinner } from './spinner.js'; + +export const installDependencies = async (projectDir: string, packageManager: PackageManager) => + spinner(installDeps({ cwd: projectDir, silent: true, packageManager }), { + text: `Installing dependencies. This could take a minute...`, + successText: `Dependencies installed successfully`, + failText: (err) => chalk.red(`Failed to install dependencies: ${err.message}`), + }); diff --git a/packages/create-catalyst/src/utils/login.ts b/packages/create-catalyst/src/utils/login.ts new file mode 100644 index 0000000000..634a0d59d0 --- /dev/null +++ b/packages/create-catalyst/src/utils/login.ts @@ -0,0 +1,101 @@ +/* eslint-disable no-await-in-loop */ + +import { confirm, input } from '@inquirer/prompts'; +import chalk from 'chalk'; + +import { Https } from './https.js'; +import { spinner } from './spinner.js'; + +const DEVICE_OAUTH_ENABLED = process.env.DEVICE_OAUTH_ENABLED ?? false; + +const poll = async (auth: Https, deviceCode: string, interval: number, expiresIn: number) => { + const intervalMs = interval * 1000; + const expiresAtMs = expiresIn * 1000; + const retries = expiresAtMs / intervalMs; + + for (let i = 0; i < retries; i += 1) { + try { + return await auth.checkDeviceCode(deviceCode); + } catch (err) { + // noop + } + + await new Promise((resolve) => setTimeout(resolve, intervalMs)); + } + + console.error(chalk.red('\nDevice code expired. Please try again.\n')); + process.exit(1); +}; + +export const login = async ( + bigCommerceAuthUrl: string, + storeHash?: string, + accessToken?: string, +) => { + if (storeHash && accessToken) { + return { storeHash, accessToken }; + } + + const shouldLogin = await confirm({ + message: 'Would you like to connect to a BigCommerce store?', + }); + + if (!shouldLogin) { + return { storeHash, accessToken }; + } + + if (!DEVICE_OAUTH_ENABLED) { + console.log( + [ + `\nPlease create an access token at ${chalk.cyan( + `${bigCommerceAuthUrl}/deep-links/settings/api-accounts/create`, + )} with the following scopes:`, + ` - Content: ${chalk.yellow('modify')}`, + ` - Information & settings: ${chalk.yellow('modify')}`, + ` - Products: ${chalk.yellow('modify')}`, + ` - Carts: ${chalk.yellow('read-only')}`, + ` - Sites & routes: ${chalk.yellow('modify')}`, + ` - Channel settings: ${chalk.yellow('modify')}`, + ` - Storefront API customer impersonation tokens: ${chalk.yellow('manage')}\n`, + ].join('\n'), + ); + + return { + storeHash: await input({ + message: 'Enter your store hash', + validate: (i) => (i.length > 0 ? true : 'Store hash is required'), + }), + accessToken: await input({ + message: 'Enter your access token', + validate: (i) => (i.length > 0 ? true : 'Access token is required'), + }), + }; + } + + const auth = new Https({ bigCommerceAuthUrl }); + + const deviceCode = await auth.getDeviceCode(); + + console.log( + [ + `\nPlease visit ${chalk.cyan(deviceCode.verification_uri)} and enter the code: ${chalk.yellow( + deviceCode.user_code, + )}\n`, + `The code will expire in ${chalk.yellow(`${deviceCode.expires_in / 60} minutes`)}\n`, + ].join('\n'), + ); + + const { store_hash, access_token } = await spinner( + poll(auth, deviceCode.device_code, deviceCode.interval, deviceCode.expires_in), + { + text: 'Waiting for device code to be authorized', + successText: 'Device code authorized', + failText: 'Device code expired', + }, + ); + + return { + storeHash: store_hash, + accessToken: access_token, + }; +}; diff --git a/packages/create-catalyst/src/utils/parse.ts b/packages/create-catalyst/src/utils/parse.ts new file mode 100644 index 0000000000..c902ca90dd --- /dev/null +++ b/packages/create-catalyst/src/utils/parse.ts @@ -0,0 +1,14 @@ +import * as z from 'zod'; +import { fromZodError } from 'zod-validation-error'; + +export const parse = (data: unknown, schema: z.Schema): T => { + try { + return schema.parse(data); + } catch (error) { + if (error instanceof z.ZodError) { + console.error(fromZodError(error).toString()); + } + + process.exit(1); + } +}; diff --git a/packages/create-catalyst/src/utils/pm.spec.ts b/packages/create-catalyst/src/utils/pm.spec.ts new file mode 100644 index 0000000000..80c5e00b0e --- /dev/null +++ b/packages/create-catalyst/src/utils/pm.spec.ts @@ -0,0 +1,32 @@ +import { getPackageManager } from './pm.js'; + +describe('getPackageManager', () => { + afterEach(() => { + jest.resetModules(); + jest.clearAllMocks(); + }); + + it("should return 'yarn' when npm_config_user_agent contains 'yarn'", () => { + process.env.npm_config_user_agent = 'yarn/2.0.0'; + + const packageManager = getPackageManager(); + + expect(packageManager).toBe('yarn'); + }); + + it("should return 'pnpm' when npm_config_user_agent contains 'pnpm'", () => { + process.env.npm_config_user_agent = 'pnpm/6.0.0'; + + const packageManager = getPackageManager(); + + expect(packageManager).toBe('pnpm'); + }); + + it("should return 'npm' when npm_config_user_agent does not contain 'pnpm' or 'yarn'", () => { + process.env.npm_config_user_agent = 'npm/7.0.0'; + + const packageManager = getPackageManager(); + + expect(packageManager).toBe('npm'); + }); +}); diff --git a/packages/create-catalyst/src/utils/pm.ts b/packages/create-catalyst/src/utils/pm.ts new file mode 100644 index 0000000000..7406f08fda --- /dev/null +++ b/packages/create-catalyst/src/utils/pm.ts @@ -0,0 +1,29 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2024 Vercel, Inc. + * + * Sourced and modified from: + * https://github.com/vercel/next.js/blob/771e29cb719b382e92d89cac11fbfcb818f5f628/packages/create-next-app/helpers/get-pkg-manager.ts + * + * License: + * https://github.com/vercel/next.js/blob/771e29cb719b382e92d89cac11fbfcb818f5f628/license.md + */ + +export type PackageManager = 'npm' | 'pnpm' | 'yarn'; + +export function getPackageManager(packageManager?: PackageManager): PackageManager { + if (packageManager) return packageManager; + + const userAgent = process.env.npm_config_user_agent || ''; + + if (userAgent.startsWith('yarn')) { + return 'yarn'; + } + + if (userAgent.startsWith('pnpm')) { + return 'pnpm'; + } + + return 'npm'; +} diff --git a/packages/create-catalyst/src/utils/project-config.ts b/packages/create-catalyst/src/utils/project-config.ts new file mode 100644 index 0000000000..34ab02a89c --- /dev/null +++ b/packages/create-catalyst/src/utils/project-config.ts @@ -0,0 +1,33 @@ +import { input } from '@inquirer/prompts'; +import { pathExistsSync } from 'fs-extra/esm'; +import kebabCase from 'lodash.kebabcase'; +import { join } from 'path'; + +export const projectConfig = async (opts: { projectDir?: string; projectName?: string }) => { + let projectName = kebabCase(opts.projectName); + let projectDir = opts.projectDir && projectName ? join(opts.projectDir, projectName) : undefined; + + if (projectDir && projectName) { + return { projectDir, projectName }; + } + + const validateProjectName = (i: string) => { + const formattedInput = kebabCase(i); + + if (!formattedInput) return 'Project name is required'; + + const targetDir = join(process.cwd(), formattedInput); + + return pathExistsSync(targetDir) ? `Destination '${targetDir}' already exists` : true; + }; + + const rawProjectName = await input({ + message: 'What is the name of your project?', + validate: validateProjectName, + }); + + projectName = kebabCase(rawProjectName); + projectDir = join(process.cwd(), projectName); + + return { projectName, projectDir }; +}; diff --git a/packages/create-catalyst/src/utils/spinner.spec.ts b/packages/create-catalyst/src/utils/spinner.spec.ts new file mode 100644 index 0000000000..5009c9463a --- /dev/null +++ b/packages/create-catalyst/src/utils/spinner.spec.ts @@ -0,0 +1,29 @@ +import { oraPromise } from 'ora'; + +import { spinner } from './spinner.js'; + +jest.mock('ora', () => ({ + oraPromise: jest.fn().mockResolvedValue('Result'), +})); + +describe('spinner', () => { + it('should call oraPromise with the provided action', async () => { + const mockAction = jest.fn(); + + await spinner(mockAction, { text: 'Loading', successText: 'Loaded' }); + + expect(oraPromise).toHaveBeenCalledWith(mockAction, { + spinner: 'triangle', + text: 'Loading', + successText: 'Loaded', + }); + }); + + it('should return the resolved value of the action', async () => { + const mockAction = jest.fn().mockResolvedValue('Result'); + + const result = await spinner(mockAction, { text: 'Loading', successText: 'Loaded' }); + + expect(result).toBe('Result'); + }); +}); diff --git a/packages/create-catalyst/src/utils/spinner.ts b/packages/create-catalyst/src/utils/spinner.ts new file mode 100644 index 0000000000..68a264067b --- /dev/null +++ b/packages/create-catalyst/src/utils/spinner.ts @@ -0,0 +1,13 @@ +import { type Ora, oraPromise, type PromiseOptions } from 'ora'; + +const spinnerIcon = 'triangle' as const; + +export const spinner = async ( + action: PromiseLike | ((spinner: Ora) => PromiseLike), + oraOpts: PromiseOptions, +) => { + return oraPromise(action, { + spinner: spinnerIcon, + ...oraOpts, + }).catch(() => process.exit(1)); +}; diff --git a/packages/create-catalyst/src/utils/write-env.ts b/packages/create-catalyst/src/utils/write-env.ts new file mode 100644 index 0000000000..b2f3216773 --- /dev/null +++ b/packages/create-catalyst/src/utils/write-env.ts @@ -0,0 +1,33 @@ +import { randomBytes } from 'crypto'; +import { outputFileSync } from 'fs-extra/esm'; +import { join } from 'path'; + +export const writeEnv = ( + projectDir: string, + { + channelId, + storeHash, + accessToken, + customerImpersonationToken, + }: { + channelId: string; + storeHash: string; + accessToken: string; + customerImpersonationToken: string; + }, +) => { + /** + * @todo silence request logs by default + */ + outputFileSync( + join(projectDir, '.env.local'), + [ + `AUTH_SECRET=${randomBytes(32).toString('hex')}`, + `ENABLE_ADMIN_ROUTE=true`, + `BIGCOMMERCE_STORE_HASH=${storeHash}`, + `BIGCOMMERCE_CHANNEL_ID=${channelId}`, + `BIGCOMMERCE_ACCESS_TOKEN=${accessToken}`, + `BIGCOMMERCE_CUSTOMER_IMPERSONATION_TOKEN=${customerImpersonationToken}`, + ].join('\n'), + ); +}; diff --git a/packages/create-catalyst/tsconfig.json b/packages/create-catalyst/tsconfig.json index ab006c6c8d..fc214f0bbb 100644 --- a/packages/create-catalyst/tsconfig.json +++ b/packages/create-catalyst/tsconfig.json @@ -1,23 +1,15 @@ { "$schema": "https://json.schemastore.org/tsconfig", - "display": "Default", + "display": "Node 18", "compilerOptions": { - "module": "NodeNext", - "composite": false, - "declaration": true, - "declarationMap": true, - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "inlineSources": false, - "incremental": true, - "isolatedModules": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "preserveWatchOutput": true, - "skipLibCheck": true, + "lib": ["es2023"], + "module": "node16", + "target": "es2022", "strict": true, + "esModuleInterop": true, "resolveJsonModule": true, - "tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json" - }, - "exclude": ["node_modules"] + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "moduleResolution": "node16" + } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ba408be568..4b21d33cfc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -283,7 +283,7 @@ importers: version: 3.2.4 tsup: specifier: ^6.7.0 - version: 6.7.0(typescript@5.3.3) + version: 6.7.0(@swc/core@1.3.107)(typescript@5.3.3) typescript: specifier: ^5.3.3 version: 5.3.3 @@ -392,6 +392,49 @@ importers: version: 5.3.3 packages/create-catalyst: + dependencies: + '@inquirer/prompts': + specifier: ^3.3.0 + version: 3.3.0 + chalk: + specifier: ^5.3.0 + version: 5.3.0 + commander: + specifier: ^11.1.0 + version: 11.1.0 + fs-extra: + specifier: ^11.2.0 + version: 11.2.0 + giget: + specifier: ^1.2.1 + version: 1.2.1 + lodash.kebabcase: + specifier: ^4.1.1 + version: 4.1.1 + lodash.merge: + specifier: ^4.6.2 + version: 4.6.2 + lodash.set: + specifier: ^4.3.2 + version: 4.3.2 + lodash.unset: + specifier: ^4.5.2 + version: 4.5.2 + msw: + specifier: ^2.1.7 + version: 2.1.7(typescript@5.3.3) + nypm: + specifier: ^0.3.6 + version: 0.3.6 + ora: + specifier: ^8.0.1 + version: 8.0.1 + zod: + specifier: ^3.22.4 + version: 3.22.4 + zod-validation-error: + specifier: ^3.0.2 + version: 3.0.2(zod@3.22.4) devDependencies: '@bigcommerce/eslint-config': specifier: ^2.7.0 @@ -399,9 +442,36 @@ importers: '@bigcommerce/eslint-config-catalyst': specifier: workspace:^ version: link:../eslint-config-catalyst + '@swc/core': + specifier: ^1.3.107 + version: 1.3.107 + '@swc/jest': + specifier: ^0.2.34 + version: 0.2.34(@swc/core@1.3.107) + '@types/fs-extra': + specifier: ^11.0.4 + version: 11.0.4 + '@types/jest': + specifier: ^29.5.11 + version: 29.5.11 + '@types/lodash.kebabcase': + specifier: ^4.1.9 + version: 4.1.9 + '@types/lodash.merge': + specifier: ^4.6.9 + version: 4.6.9 + '@types/lodash.set': + specifier: ^4.3.9 + version: 4.3.9 + '@types/lodash.unset': + specifier: ^4.5.9 + version: 4.5.9 '@types/node': specifier: ^18.17.12 version: 18.19.3 + '@types/prompts': + specifier: ^2.4.9 + version: 2.4.9 eslint: specifier: ^8.55.0 version: 8.55.0 @@ -413,7 +483,7 @@ importers: version: 3.1.1 tsup: specifier: ^6.7.0 - version: 6.7.0(typescript@5.3.3) + version: 6.7.0(@swc/core@1.3.107)(typescript@5.3.3) typescript: specifier: ^5.3.3 version: 5.3.3 @@ -1828,6 +1898,18 @@ packages: transitivePeerDependencies: - supports-color + /@bundled-es-modules/cookie@2.0.0: + resolution: {integrity: sha512-Or6YHg/kamKHpxULAdSqhGqnWFneIXu1NKvvfBBzKGwpVsYuFIQ5aBPHDnnoR3ghW1nvSkALd+EF9iMtY7Vjxw==} + dependencies: + cookie: 0.5.0 + dev: false + + /@bundled-es-modules/statuses@1.0.1: + resolution: {integrity: sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==} + dependencies: + statuses: 2.0.1 + dev: false + /@colors/colors@1.5.0: resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} @@ -3117,7 +3199,6 @@ packages: ansi-escapes: 4.3.2 chalk: 4.1.2 figures: 3.2.0 - dev: true /@inquirer/confirm@2.0.15: resolution: {integrity: sha512-hj8Q/z7sQXsF0DSpLQZVDhWYGN6KLM/gNjjqGkpKwBzljbQofGjn0ueHADy4HUY+OqDHmXuwk/bY+tZyIuuB0w==} @@ -3126,7 +3207,6 @@ packages: '@inquirer/core': 5.1.1 '@inquirer/type': 1.1.5 chalk: 4.1.2 - dev: true /@inquirer/core@5.1.1: resolution: {integrity: sha512-IuJyZQUg75+L5AmopgnzxYrgcU6PJKL0hoIs332G1Gv55CnmZrhG6BzNOeZ5sOsTi1YCGOopw4rYICv74ejMFg==} @@ -3146,7 +3226,6 @@ packages: signal-exit: 4.1.0 strip-ansi: 6.0.1 wrap-ansi: 6.2.0 - dev: true /@inquirer/editor@1.2.13: resolution: {integrity: sha512-gBxjqt0B9GLN0j6M/tkEcmcIvB2fo9Cw0f5NRqDTkYyB9AaCzj7qvgG0onQ3GVPbMyMbbP4tWYxrBOaOdKpzNA==} @@ -3156,7 +3235,6 @@ packages: '@inquirer/type': 1.1.5 chalk: 4.1.2 external-editor: 3.1.0 - dev: true /@inquirer/expand@1.1.14: resolution: {integrity: sha512-yS6fJ8jZYAsxdxuw2c8XTFMTvMR1NxZAw3LxDaFnqh7BZ++wTQ6rSp/2gGJhMacdZ85osb+tHxjVgx7F+ilv5g==} @@ -3166,7 +3244,6 @@ packages: '@inquirer/type': 1.1.5 chalk: 4.1.2 figures: 3.2.0 - dev: true /@inquirer/input@1.2.14: resolution: {integrity: sha512-tISLGpUKXixIQue7jypNEShrdzJoLvEvZOJ4QRsw5XTfrIYfoWFqAjMQLerGs9CzR86yAI89JR6snHmKwnNddw==} @@ -3175,7 +3252,6 @@ packages: '@inquirer/core': 5.1.1 '@inquirer/type': 1.1.5 chalk: 4.1.2 - dev: true /@inquirer/password@1.1.14: resolution: {integrity: sha512-vL2BFxfMo8EvuGuZYlryiyAB3XsgtbxOcFs4H9WI9szAS/VZCAwdVqs8rqEeaAf/GV/eZOghIOYxvD91IsRWSg==} @@ -3185,7 +3261,6 @@ packages: '@inquirer/type': 1.1.5 ansi-escapes: 4.3.2 chalk: 4.1.2 - dev: true /@inquirer/prompts@3.3.0: resolution: {integrity: sha512-BBCqdSnhNs+WziSIo4f/RNDu6HAj4R/Q5nMgJb5MNPFX8sJGCvj9BoALdmR0HTWXyDS7TO8euKj6W6vtqCQG7A==} @@ -3200,7 +3275,6 @@ packages: '@inquirer/password': 1.1.14 '@inquirer/rawlist': 1.2.14 '@inquirer/select': 1.3.1 - dev: true /@inquirer/rawlist@1.2.14: resolution: {integrity: sha512-xIYmDpYgfz2XGCKubSDLKEvadkIZAKbehHdWF082AyC2I4eHK44RUfXaoOAqnbqItZq4KHXS6jDJ78F2BmQvxg==} @@ -3209,7 +3283,6 @@ packages: '@inquirer/core': 5.1.1 '@inquirer/type': 1.1.5 chalk: 4.1.2 - dev: true /@inquirer/select@1.3.1: resolution: {integrity: sha512-EgOPHv7XOHEqiBwBJTyiMg9r57ySyW4oyYCumGp+pGyOaXQaLb2kTnccWI6NFd9HSi5kDJhF7YjA+3RfMQJ2JQ==} @@ -3220,12 +3293,10 @@ packages: ansi-escapes: 4.3.2 chalk: 4.1.2 figures: 3.2.0 - dev: true /@inquirer/type@1.1.5: resolution: {integrity: sha512-wmwHvHozpPo4IZkkNtbYenem/0wnfI6hvOcGKmPEa0DwuaH5XUQzFqy6OpEpjEegZMhYIk8HDYITI16BPLtrRA==} engines: {node: '>=14.18.0'} - dev: true /@isaacs/cliui@8.0.2: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} @@ -3305,6 +3376,13 @@ packages: - supports-color - ts-node + /@jest/create-cache-key-function@29.7.0: + resolution: {integrity: sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dependencies: + '@jest/types': 29.6.3 + dev: true + /@jest/environment@29.7.0: resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -3365,7 +3443,7 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.20 + '@jridgewell/trace-mapping': 0.3.22 '@types/node': 18.19.8 chalk: 4.1.2 collect-v8-coverage: 1.0.2 @@ -3425,7 +3503,7 @@ packages: dependencies: '@babel/core': 7.23.6 '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.22 + '@jridgewell/trace-mapping': 0.3.20 babel-plugin-istanbul: 6.1.1 chalk: 4.1.2 convert-source-map: 2.0.0 @@ -3521,6 +3599,23 @@ packages: react: 18.2.0 dev: true + /@mswjs/cookies@1.1.0: + resolution: {integrity: sha512-0ZcCVQxifZmhwNBoQIrystCb+2sWBY2Zw8lpfJBPCHGCA/HWqehITeCRVIv4VMy8MPlaHo2w2pTHFV2pFfqKPw==} + engines: {node: '>=18'} + dev: false + + /@mswjs/interceptors@0.25.16: + resolution: {integrity: sha512-8QC8JyKztvoGAdPgyZy49c9vSHHAZjHagwl4RY9E8carULk8ym3iTaiawrT1YoLF/qb449h48f71XDPgkUSOUg==} + engines: {node: '>=18'} + dependencies: + '@open-draft/deferred-promise': 2.2.0 + '@open-draft/logger': 0.3.0 + '@open-draft/until': 2.1.0 + is-node-process: 1.2.0 + outvariant: 1.4.2 + strict-event-emitter: 0.5.1 + dev: false + /@ndelangen/get-tarball@3.0.9: resolution: {integrity: sha512-9JKTEik4vq+yGosHYhZ1tiH/3WpUS0Nh0kej4Agndhox8pAdWhEx5knFVRcb/ya9knCRCs1rPxNrSXTDdfVqpA==} dependencies: @@ -3636,6 +3731,21 @@ packages: '@nodelib/fs.scandir': 2.1.5 fastq: 1.15.0 + /@open-draft/deferred-promise@2.2.0: + resolution: {integrity: sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==} + dev: false + + /@open-draft/logger@0.3.0: + resolution: {integrity: sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==} + dependencies: + is-node-process: 1.2.0 + outvariant: 1.4.2 + dev: false + + /@open-draft/until@2.1.0: + resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==} + dev: false + /@panva/hkdf@1.1.1: resolution: {integrity: sha512-dhPeilub1NuIG0X5Kvhh9lH4iW3ZsHlnzwgwbOlgwQ2wG1IqFzsgHqmKPk3WzsdWAeaxKJxgM0+W433RmN45GA==} dev: false @@ -5648,12 +5758,146 @@ packages: '@types/express': 4.17.21 file-system-cache: 2.3.0 + /@swc/core-darwin-arm64@1.3.107: + resolution: {integrity: sha512-47tD/5vSXWxPd0j/ZllyQUg4bqalbQTsmqSw0J4dDdS82MWqCAwUErUrAZPRjBkjNQ6Kmrf5rpCWaGTtPw+ngw==} + engines: {node: '>=10'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@swc/core-darwin-x64@1.3.107: + resolution: {integrity: sha512-hwiLJ2ulNkBGAh1m1eTfeY1417OAYbRGcb/iGsJ+LuVLvKAhU/itzsl535CvcwAlt2LayeCFfcI8gdeOLeZa9A==} + engines: {node: '>=10'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@swc/core-linux-arm-gnueabihf@1.3.107: + resolution: {integrity: sha512-I2wzcC0KXqh0OwymCmYwNRgZ9nxX7DWnOOStJXV3pS0uB83TXAkmqd7wvMBuIl9qu4Hfomi9aDM7IlEEn9tumQ==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@swc/core-linux-arm64-gnu@1.3.107: + resolution: {integrity: sha512-HWgnn7JORYlOYnGsdunpSF8A+BCZKPLzLtEUA27/M/ZuANcMZabKL9Zurt7XQXq888uJFAt98Gy+59PU90aHKg==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@swc/core-linux-arm64-musl@1.3.107: + resolution: {integrity: sha512-vfPF74cWfAm8hyhS8yvYI94ucMHIo8xIYU+oFOW9uvDlGQRgnUf/6DEVbLyt/3yfX5723Ln57U8uiMALbX5Pyw==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@swc/core-linux-x64-gnu@1.3.107: + resolution: {integrity: sha512-uBVNhIg0ip8rH9OnOsCARUFZ3Mq3tbPHxtmWk9uAa5u8jQwGWeBx5+nTHpDOVd3YxKb6+5xDEI/edeeLpha/9g==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@swc/core-linux-x64-musl@1.3.107: + resolution: {integrity: sha512-mvACkUvzSIB12q1H5JtabWATbk3AG+pQgXEN95AmEX2ZA5gbP9+B+mijsg7Sd/3tboHr7ZHLz/q3SHTvdFJrEw==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@swc/core-win32-arm64-msvc@1.3.107: + resolution: {integrity: sha512-J3P14Ngy/1qtapzbguEH41kY109t6DFxfbK4Ntz9dOWNuVY3o9/RTB841ctnJk0ZHEG+BjfCJjsD2n8H5HcaOA==} + engines: {node: '>=10'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@swc/core-win32-ia32-msvc@1.3.107: + resolution: {integrity: sha512-ZBUtgyjTHlz8TPJh7kfwwwFma+ktr6OccB1oXC8fMSopD0AxVnQasgun3l3099wIsAB9eEsJDQ/3lDkOLs1gBA==} + engines: {node: '>=10'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@swc/core-win32-x64-msvc@1.3.107: + resolution: {integrity: sha512-Eyzo2XRqWOxqhE1gk9h7LWmUf4Bp4Xn2Ttb0ayAXFp6YSTxQIThXcT9kipXZqcpxcmDwoq8iWbbf2P8XL743EA==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@swc/core@1.3.107: + resolution: {integrity: sha512-zKhqDyFcTsyLIYK1iEmavljZnf4CCor5pF52UzLAz4B6Nu/4GLU+2LQVAf+oRHjusG39PTPjd2AlRT3f3QWfsQ==} + engines: {node: '>=10'} + requiresBuild: true + peerDependencies: + '@swc/helpers': ^0.5.0 + peerDependenciesMeta: + '@swc/helpers': + optional: true + dependencies: + '@swc/counter': 0.1.2 + '@swc/types': 0.1.5 + optionalDependencies: + '@swc/core-darwin-arm64': 1.3.107 + '@swc/core-darwin-x64': 1.3.107 + '@swc/core-linux-arm-gnueabihf': 1.3.107 + '@swc/core-linux-arm64-gnu': 1.3.107 + '@swc/core-linux-arm64-musl': 1.3.107 + '@swc/core-linux-x64-gnu': 1.3.107 + '@swc/core-linux-x64-musl': 1.3.107 + '@swc/core-win32-arm64-msvc': 1.3.107 + '@swc/core-win32-ia32-msvc': 1.3.107 + '@swc/core-win32-x64-msvc': 1.3.107 + dev: true + + /@swc/counter@0.1.2: + resolution: {integrity: sha512-9F4ys4C74eSTEUNndnER3VJ15oru2NumfQxS8geE+f3eB5xvfxpWyqE5XlVnxb/R14uoXi6SLbBwwiDSkv+XEw==} + dev: true + /@swc/helpers@0.5.2: resolution: {integrity: sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==} dependencies: tslib: 2.6.2 dev: false + /@swc/jest@0.2.34(@swc/core@1.3.107): + resolution: {integrity: sha512-MrS4m3yHFfnkYjxr3eqxshWi6fVhPViHQsb6XfiTO81niwEqYXeR58YhGJee6R0bfQHC69cv5OJ9+dYTYaYKRg==} + engines: {npm: '>= 7.0.0'} + peerDependencies: + '@swc/core': '*' + dependencies: + '@jest/create-cache-key-function': 29.7.0 + '@swc/core': 1.3.107 + jsonc-parser: 3.2.1 + dev: true + + /@swc/types@0.1.5: + resolution: {integrity: sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==} + dev: true + /@tailwindcss/container-queries@0.1.1(tailwindcss@3.3.6): resolution: {integrity: sha512-p18dswChx6WnTSaJCSGx6lTmrGzNNvm2FtXmiO6AuA1V4U5REyoqwmT6kgAsIMdjo07QdAfYXHJ4hnMtfHzWgA==} peerDependencies: @@ -5730,6 +5974,10 @@ packages: dependencies: '@types/node': 18.19.8 + /@types/cookie@0.6.0: + resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} + dev: false + /@types/cross-spawn@6.0.6: resolution: {integrity: sha512-fXRhhUkG4H3TQk5dBhQ7m/JDdSNHKwR2BBia62lhwEIq9xGiQKLxd6LymNhn47SjXhsUEPmxi+PKw2OkW4LLjA==} dependencies: @@ -5804,6 +6052,13 @@ packages: '@types/node': 18.19.8 dev: true + /@types/fs-extra@11.0.4: + resolution: {integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==} + dependencies: + '@types/jsonfile': 6.1.4 + '@types/node': 18.19.8 + dev: true + /@types/glob@7.2.0: resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} dependencies: @@ -5832,6 +6087,13 @@ packages: dependencies: '@types/istanbul-lib-report': 3.0.3 + /@types/jest@29.5.11: + resolution: {integrity: sha512-S2mHmYIVe13vrm6q4kN6fLYYAka15ALQki/vgDC3mIukEOx8WJlv0kQPM+d4w8Gp6u0uSdKND04IlTXBv0rwnQ==} + dependencies: + expect: 29.7.0 + pretty-format: 29.7.0 + dev: true + /@types/js-yaml@4.0.8: resolution: {integrity: sha512-m6jnPk1VhlYRiLFm3f8X9Uep761f+CK8mHyS65LutH2OhmBF0BeMEjHgg05usH8PLZMWWc/BUR9RPmkvpWnyRA==} dev: true @@ -5858,6 +6120,30 @@ packages: '@types/lodash': 4.14.202 dev: true + /@types/lodash.kebabcase@4.1.9: + resolution: {integrity: sha512-kPrrmcVOhSsjAVRovN0lRfrbuidfg0wYsrQa5IYuoQO1fpHHGSme66oyiYA/5eQPVl8Z95OA3HG0+d2SvYC85w==} + dependencies: + '@types/lodash': 4.14.202 + dev: true + + /@types/lodash.merge@4.6.9: + resolution: {integrity: sha512-23sHDPmzd59kUgWyKGiOMO2Qb9YtqRO/x4IhkgNUiPQ1+5MUVqi6bCZeq9nBJ17msjIMbEIO5u+XW4Kz6aGUhQ==} + dependencies: + '@types/lodash': 4.14.202 + dev: true + + /@types/lodash.set@4.3.9: + resolution: {integrity: sha512-KOxyNkZpbaggVmqbpr82N2tDVTx05/3/j0f50Es1prxrWB0XYf9p3QNxqcbWb7P1Q9wlvsUSlCFnwlPCIJ46PQ==} + dependencies: + '@types/lodash': 4.14.202 + dev: true + + /@types/lodash.unset@4.5.9: + resolution: {integrity: sha512-uyYP6JMM30vKXJtDrPtJyK/t3TdyjhZQ7woJAk1biI/o/sXZvBVqQtiMWsIlYLcn6jSPrG4sjYWTZM34qNM7dA==} + dependencies: + '@types/lodash': 4.14.202 + dev: true + /@types/lodash@4.14.202: resolution: {integrity: sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==} dev: true @@ -5883,7 +6169,6 @@ packages: resolution: {integrity: sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==} dependencies: '@types/node': 18.19.8 - dev: true /@types/node-fetch@2.6.9: resolution: {integrity: sha512-bQVlnMLFJ2d35DkPNjEPmd9ueO/rh5EiaZt2bhqiSarPjZIuIV6bPQVqcrEyvNo+AfTrRGVazle1tl597w3gfA==} @@ -5906,7 +6191,6 @@ packages: resolution: {integrity: sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==} dependencies: undici-types: 5.26.5 - dev: true /@types/normalize-package-data@2.4.4: resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -5914,6 +6198,13 @@ packages: /@types/pretty-hrtime@1.0.3: resolution: {integrity: sha512-nj39q0wAIdhwn7DGUyT9irmsKK1tV0bd5WFEhgpqNTMFZ8cE+jieuTphCW0tfdm47S2zVT5mr09B28b1chmQMA==} + /@types/prompts@2.4.9: + resolution: {integrity: sha512-qTxFi6Buiu8+50/+3DGIWLHM6QuWsEKugJnnP6iv2Mc4ncxE4A/OJkjuVOA+5X0X1S/nq5VJRa8Lu+nwcvbrKA==} + dependencies: + '@types/node': 18.19.8 + kleur: 3.0.3 + dev: true + /@types/prop-types@15.7.11: resolution: {integrity: sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==} @@ -5973,6 +6264,10 @@ packages: /@types/stack-utils@2.0.3: resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + /@types/statuses@2.0.4: + resolution: {integrity: sha512-eqNDvZsCNY49OAXB0Firg/Sc2BgoWsntsLUdybGFOhAfCD6QJ2n9HXUIHGqt5qjrxmMv4wS8WLAw43ZkKcJ8Pw==} + dev: false + /@types/unist@2.0.10: resolution: {integrity: sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==} dev: true @@ -5983,7 +6278,6 @@ packages: /@types/wrap-ansi@3.0.0: resolution: {integrity: sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==} - dev: true /@types/ws@8.5.8: resolution: {integrity: sha512-flUksGIQCnJd6sZ1l5dqCEG/ksaoAg/eUwiLAGTJQcfgvZJKF++Ta4bJA6A5aPSJmsr+xlseHn4KLgVlNnvPTg==} @@ -6941,7 +7235,6 @@ packages: /binary-extensions@2.2.0: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} - dev: true /bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} @@ -7005,7 +7298,7 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001579 + caniuse-lite: 1.0.30001568 electron-to-chromium: 1.4.611 node-releases: 2.0.14 update-browserslist-db: 1.0.13(browserslist@4.22.2) @@ -7096,10 +7389,10 @@ packages: /caniuse-lite@1.0.30001568: resolution: {integrity: sha512-vSUkH84HontZJ88MiNrOau1EBrCqEQYgkC5gIySiDlpsm8sGVrhU7Kx4V6h0tnqaHzIHZv08HlJIwPbL4XL9+A==} - dev: true /caniuse-lite@1.0.30001579: resolution: {integrity: sha512-u5AUVkixruKHJjw/pj9wISlcMpgFWzSrczLZbrqBSxukQixmg0SJ5sZTpvaFvxU0HoQKd4yoyAogyrAz9pzJnA==} + dev: false /capital-case@1.0.4: resolution: {integrity: sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==} @@ -7124,6 +7417,11 @@ packages: ansi-styles: 4.3.0 supports-color: 7.2.0 + /chalk@5.3.0: + resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + dev: false + /change-case-all@1.0.15: resolution: {integrity: sha512-3+GIFhk3sNuvFAJKU46o26OdzudQlPNBCu1ZQi3cMeMHhty1bhDxu2WrEilVNYaGvqUtR1VSigFcJOiS13dRhQ==} dependencies: @@ -7162,7 +7460,6 @@ packages: /chardet@0.7.0: resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} - dev: true /chokidar@3.5.3: resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} @@ -7177,7 +7474,6 @@ packages: readdirp: 3.6.0 optionalDependencies: fsevents: 2.3.3 - dev: true /chownr@1.1.4: resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} @@ -7195,6 +7491,12 @@ packages: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} + /citty@0.1.5: + resolution: {integrity: sha512-AS7n5NSc0OQVMV9v6wt3ByujNIrne0/cTjiC2MYqhvao57VNfiuVksTSr2p17nVOhEr2KtqiAkGwHcgMC/qUuQ==} + dependencies: + consola: 3.2.3 + dev: false + /cjs-module-lexer@1.2.3: resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==} @@ -7214,6 +7516,13 @@ packages: dependencies: restore-cursor: 3.1.0 + /cli-cursor@4.0.0: + resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + restore-cursor: 4.0.0 + dev: false + /cli-spinners@2.9.2: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} @@ -7237,12 +7546,10 @@ packages: /cli-width@3.0.0: resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==} engines: {node: '>= 10'} - dev: true /cli-width@4.1.0: resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} engines: {node: '>= 12'} - dev: true /client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} @@ -7329,6 +7636,11 @@ packages: dependencies: delayed-stream: 1.0.0 + /commander@11.1.0: + resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} + engines: {node: '>=16'} + dev: false + /commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} dev: true @@ -7402,6 +7714,11 @@ packages: yargs: 17.7.2 dev: true + /consola@3.2.3: + resolution: {integrity: sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==} + engines: {node: ^14.18.0 || >=16.10.0} + dev: false + /constant-case@3.0.4: resolution: {integrity: sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==} dependencies: @@ -7883,6 +8200,10 @@ packages: resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} engines: {node: '>=12'} + /emoji-regex@10.3.0: + resolution: {integrity: sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==} + dev: false + /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -8688,6 +9009,21 @@ packages: strip-final-newline: 3.0.0 dev: false + /execa@8.0.1: + resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} + engines: {node: '>=16.17'} + dependencies: + cross-spawn: 7.0.3 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.1.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 + dev: false + /exit@0.1.2: resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} engines: {node: '>= 0.8.0'} @@ -8751,7 +9087,6 @@ packages: chardet: 0.7.0 iconv-lite: 0.4.24 tmp: 0.0.33 - dev: true /extract-files@11.0.0: resolution: {integrity: sha512-FuoE1qtbJ4bBVvv94CC7s0oTnKUGvQs+Rjf1L2SJFfS+HTVVjhPFtehPdQ0JiGPqVNfSSZvL5yzHHQq2Z4WNhQ==} @@ -8848,7 +9183,6 @@ packages: engines: {node: '>=8'} dependencies: escape-string-regexp: 1.0.5 - dev: true /file-entry-cache@6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} @@ -9065,6 +9399,11 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} + /get-east-asian-width@1.2.0: + resolution: {integrity: sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==} + engines: {node: '>=18'} + dev: false + /get-intrinsic@1.2.2: resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==} dependencies: @@ -9093,6 +9432,11 @@ packages: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} + /get-stream@8.0.1: + resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} + engines: {node: '>=16'} + dev: false + /get-symbol-description@1.0.0: resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} engines: {node: '>= 0.4'} @@ -9122,11 +9466,25 @@ packages: https-proxy-agent: 7.0.2 mri: 1.2.0 node-fetch-native: 1.4.1 - pathe: 1.1.1 + pathe: 1.1.2 tar: 6.2.0 transitivePeerDependencies: - supports-color + /giget@1.2.1: + resolution: {integrity: sha512-4VG22mopWtIeHwogGSy1FViXVo0YT+m6BrqZfz0JJFwbSsePsCdOzdLIIli5BtMp7Xe8f/o2OmBpQX2NBOC24g==} + hasBin: true + dependencies: + citty: 0.1.5 + consola: 3.2.3 + defu: 6.1.3 + node-fetch-native: 1.6.1 + nypm: 0.3.6 + ohash: 1.1.3 + pathe: 1.1.1 + tar: 6.2.0 + dev: false + /github-slugger@1.5.0: resolution: {integrity: sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw==} dev: true @@ -9377,6 +9735,10 @@ packages: tslib: 2.6.2 dev: true + /headers-polyfill@4.0.2: + resolution: {integrity: sha512-EWGTfnTqAO2L/j5HZgoM/3z82L7necsJ0pO9Tp0X1wil3PDLrkypTBRgVO2ExehEEvUycejZD3FuRaXpZZc3kw==} + dev: false + /hoist-non-react-statics@3.3.2: resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} dependencies: @@ -9441,6 +9803,11 @@ packages: engines: {node: '>=14.18.0'} dev: false + /human-signals@5.0.0: + resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} + engines: {node: '>=16.17.0'} + dev: false + /iconv-lite@0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} @@ -9539,7 +9906,6 @@ packages: strip-ansi: 6.0.1 through: 2.3.8 wrap-ansi: 6.2.0 - dev: true /internal-slot@1.0.6: resolution: {integrity: sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==} @@ -9611,7 +9977,6 @@ packages: engines: {node: '>=8'} dependencies: binary-extensions: 2.2.0 - dev: true /is-boolean-object@1.1.2: resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} @@ -9694,6 +10059,11 @@ packages: resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} engines: {node: '>=8'} + /is-interactive@2.0.0: + resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==} + engines: {node: '>=12'} + dev: false + /is-lower-case@2.0.2: resolution: {integrity: sha512-bVcMJy4X5Og6VZfdOZstSexlEy20Sr0k/p/b2IlQJlfdKAQuMpiv5w2Ccxb8sKdRUNAG1PnHVHjFSdRDVS6NlQ==} dependencies: @@ -9714,6 +10084,10 @@ packages: resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} engines: {node: '>= 0.4'} + /is-node-process@1.2.0: + resolution: {integrity: sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==} + dev: false + /is-number-object@1.0.7: resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} engines: {node: '>= 0.4'} @@ -9803,6 +10177,16 @@ packages: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} + /is-unicode-supported@1.3.0: + resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} + engines: {node: '>=12'} + dev: false + + /is-unicode-supported@2.0.0: + resolution: {integrity: sha512-FRdAyx5lusK1iHG0TWpVtk9+1i+GjrzRffhDg4ovQ7mcidMQ6mj+MhKPmvh7Xwyv5gIS06ns49CA7Sqg7lC22Q==} + engines: {node: '>=18'} + dev: false + /is-upper-case@2.0.2: resolution: {integrity: sha512-44pxmxAvnnAOwBg4tHPnkfvgjPwbc5QIsSstNU+YcJ1ovxVzCWpSGosPJOZh/a1tdl81fbgnLc9LLv+x2ywbPQ==} dependencies: @@ -10590,6 +10974,10 @@ packages: engines: {node: '>=6'} hasBin: true + /jsonc-parser@3.2.1: + resolution: {integrity: sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==} + dev: true + /jsonfile@6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} dependencies: @@ -10753,16 +11141,28 @@ packages: /lodash.debounce@4.0.8: resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} + /lodash.kebabcase@4.1.1: + resolution: {integrity: sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==} + dev: false + /lodash.last@3.0.0: resolution: {integrity: sha512-14mq7rSkCxG4XMy9lF2FbIOqqgF0aH0NfPuQ3LPR3vIh0kHnUvIYP70dqa1Hf47zyXfQ8FzAg0MYOQeSuE1R7A==} /lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + /lodash.set@4.3.2: + resolution: {integrity: sha512-4hNPN5jlm/N/HLMCO43v8BXKq9Z7QdAGc/VGrRD61w8gN9g/6jF9A4L1pbUgBLCffi0w9VsXfTOij5x8iTyFvg==} + dev: false + /lodash.sortby@4.7.0: resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} dev: true + /lodash.unset@4.5.2: + resolution: {integrity: sha512-bwKX88k2JhCV9D1vtE8+naDKlLiGrSmf8zi/Y9ivFHwbmRfA8RxS/aVJ+sIht2XOwqoNr4xUPUkGZpc1sHFEKg==} + dev: false + /lodash.zipobject@4.1.3: resolution: {integrity: sha512-A9SzX4hMKWS25MyalwcOnNoplyHbkNVsjidhTp8ru0Sj23wY9GWBKS8gAIGDSAqeWjIjvE4KBEl24XXAs+v4wQ==} @@ -10776,6 +11176,14 @@ packages: chalk: 4.1.2 is-unicode-supported: 0.1.0 + /log-symbols@6.0.0: + resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==} + engines: {node: '>=18'} + dependencies: + chalk: 5.3.0 + is-unicode-supported: 1.3.0 + dev: false + /log-update@4.0.0: resolution: {integrity: sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==} engines: {node: '>=10'} @@ -11048,14 +11456,44 @@ packages: /ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + /msw@2.1.7(typescript@5.3.3): + resolution: {integrity: sha512-yTIYqEMqDSrdbVMrfmqP6rTKQsnIbglTvVmAHDWwNegyXPXRcV+RjsaFEqubRS266gwWCDLm9YdOkWSKLdDvJQ==} + engines: {node: '>=18'} + hasBin: true + requiresBuild: true + peerDependencies: + typescript: '>= 4.7.x <= 5.3.x' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@bundled-es-modules/cookie': 2.0.0 + '@bundled-es-modules/statuses': 1.0.1 + '@mswjs/cookies': 1.1.0 + '@mswjs/interceptors': 0.25.16 + '@open-draft/until': 2.1.0 + '@types/cookie': 0.6.0 + '@types/statuses': 2.0.4 + chalk: 4.1.2 + chokidar: 3.5.3 + graphql: 16.8.1 + headers-polyfill: 4.0.2 + inquirer: 8.2.6 + is-node-process: 1.2.0 + outvariant: 1.4.2 + path-to-regexp: 6.2.1 + strict-event-emitter: 0.5.1 + type-fest: 4.10.2 + typescript: 5.3.3 + yargs: 17.7.2 + dev: false + /mute-stream@0.0.8: resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} - dev: true /mute-stream@1.0.0: resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - dev: true /mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} @@ -11168,6 +11606,10 @@ packages: /node-fetch-native@1.4.1: resolution: {integrity: sha512-NsXBU0UgBxo2rQLOeWNZqS3fvflWePMECr8CoSWoSTqCqGbVVsvl9vZu1HfQicYN0g5piV9Gh8RTEvo/uP752w==} + /node-fetch-native@1.6.1: + resolution: {integrity: sha512-bW9T/uJDPAJB2YNYEpWzE54U5O3MQidXsOyTfnbKYtTtFexRvGzb1waphBN4ZwP6EcIvYYEOwW0b72BpAqydTw==} + dev: false + /node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -11226,6 +11668,17 @@ packages: resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==} dev: true + /nypm@0.3.6: + resolution: {integrity: sha512-2CATJh3pd6CyNfU5VZM7qSwFu0ieyabkEdnogE30Obn1czrmOYiZ8DOZLe1yBdLKWoyD3Mcy2maUs+0MR3yVjQ==} + engines: {node: ^14.16.0 || >=16.10.0} + hasBin: true + dependencies: + citty: 0.1.5 + execa: 8.0.1 + pathe: 1.1.2 + ufo: 1.3.2 + dev: false + /oauth4webapi@2.4.0: resolution: {integrity: sha512-ZWl8ov8HeGVyc9Icl1cag76HvIcDAp23eIIT+UVGir+dEu8BMgMlvZeZwqLVd0P8DqaumH4N+QLQXN69G1QjSA==} dev: false @@ -11300,6 +11753,10 @@ packages: define-properties: 1.2.1 es-abstract: 1.22.3 + /ohash@1.1.3: + resolution: {integrity: sha512-zuHHiGTYTA1sYJ/wZN+t5HKZaH23i4yI1HMwbuXm24Nid7Dv0KcuRlKoNKS9UNfAVSBlnGLcuQrnOKWOZoEGaw==} + dev: false + /on-finished@2.4.1: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} @@ -11371,10 +11828,28 @@ packages: strip-ansi: 6.0.1 wcwidth: 1.0.1 + /ora@8.0.1: + resolution: {integrity: sha512-ANIvzobt1rls2BDny5fWZ3ZVKyD6nscLvfFRpQgfWsythlcsVUC9kL0zq6j2Z5z9wwp1kd7wpsD/T9qNPVLCaQ==} + engines: {node: '>=18'} + dependencies: + chalk: 5.3.0 + cli-cursor: 4.0.0 + cli-spinners: 2.9.2 + is-interactive: 2.0.0 + is-unicode-supported: 2.0.0 + log-symbols: 6.0.0 + stdin-discarder: 0.2.2 + string-width: 7.1.0 + strip-ansi: 7.1.0 + dev: false + /os-tmpdir@1.0.2: resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} engines: {node: '>=0.10.0'} - dev: true + + /outvariant@1.4.2: + resolution: {integrity: sha512-Ou3dJ6bA/UJ5GVHxah4LnqDwZRwAmWxrG3wtrHrbGnP4RnLCtA64A4F+ae7Y8ww660JaddSoArUR5HjipWSHAQ==} + dev: false /p-limit@2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} @@ -11519,12 +11994,20 @@ packages: /path-to-regexp@0.1.7: resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} + /path-to-regexp@6.2.1: + resolution: {integrity: sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==} + dev: false + /path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} /pathe@1.1.1: resolution: {integrity: sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==} + dev: false + + /pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} /peek-stream@1.1.3: resolution: {integrity: sha512-FhJ+YbOSBb9/rIl2ZeE/QHEsWn7PqNYt8ARAY3kIgNGOk13g9FGyIY6JIl/xB/3TFRVoTv5as0l11weORrTekA==} @@ -12291,7 +12774,6 @@ packages: engines: {node: '>=8.10.0'} dependencies: picomatch: 2.3.1 - dev: true /recast@0.23.4: resolution: {integrity: sha512-qtEDqIZGVcSZCHniWwZWbRy79Dc6Wp3kT/UmDA2RJKBPg7+7k51aQBZirHmUGn5uvHf2rg8DkjizrN26k61ATw==} @@ -12468,6 +12950,14 @@ packages: onetime: 5.1.2 signal-exit: 3.0.7 + /restore-cursor@4.0.0: + resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + dev: false + /reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -12512,12 +13002,10 @@ packages: /run-async@2.4.1: resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} engines: {node: '>=0.12.0'} - dev: true /run-async@3.0.0: resolution: {integrity: sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==} engines: {node: '>=0.12.0'} - dev: true /run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -12528,7 +13016,6 @@ packages: resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} dependencies: tslib: 2.6.2 - dev: true /safe-array-concat@1.0.1: resolution: {integrity: sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==} @@ -12890,6 +13377,11 @@ packages: resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==} dev: false + /stdin-discarder@0.2.2: + resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==} + engines: {node: '>=18'} + dev: false + /stop-iteration-iterator@1.0.0: resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==} engines: {node: '>= 0.4'} @@ -12920,6 +13412,10 @@ packages: resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} engines: {node: '>=10.0.0'} + /strict-event-emitter@0.5.1: + resolution: {integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==} + dev: false + /string-env-interpolation@1.0.1: resolution: {integrity: sha512-78lwMoCcn0nNu8LszbP1UA7g55OeE4v7rCeWnM5B453rnNr4aq+5it3FEYtZrSEiMvHZOZ9Jlqb0OD0M2VInqg==} dev: true @@ -12947,6 +13443,15 @@ packages: emoji-regex: 9.2.2 strip-ansi: 7.1.0 + /string-width@7.1.0: + resolution: {integrity: sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==} + engines: {node: '>=18'} + dependencies: + emoji-regex: 10.3.0 + get-east-asian-width: 1.2.0 + strip-ansi: 7.1.0 + dev: false + /string.prototype.matchall@4.0.10: resolution: {integrity: sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==} dependencies: @@ -13291,7 +13796,6 @@ packages: /through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} - dev: true /tiny-invariant@1.3.1: resolution: {integrity: sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==} @@ -13312,7 +13816,6 @@ packages: engines: {node: '>=0.6.0'} dependencies: os-tmpdir: 1.0.2 - dev: true /tmpl@1.0.5: resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} @@ -13392,7 +13895,7 @@ packages: /tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} - /tsup@6.7.0(typescript@5.3.3): + /tsup@6.7.0(@swc/core@1.3.107)(typescript@5.3.3): resolution: {integrity: sha512-L3o8hGkaHnu5TdJns+mCqFsDBo83bJ44rlK7e6VdanIvpea4ArPcU3swWGsLVbXak1PqQx/V+SSmFPujBK+zEQ==} engines: {node: '>=14.18'} hasBin: true @@ -13408,6 +13911,7 @@ packages: typescript: optional: true dependencies: + '@swc/core': 1.3.107 bundle-require: 4.0.1(esbuild@0.17.19) cac: 6.7.14 chokidar: 3.5.3 @@ -13531,6 +14035,11 @@ packages: resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} engines: {node: '>=12.20'} + /type-fest@4.10.2: + resolution: {integrity: sha512-anpAG63wSpdEbLwOqH8L84urkL6PiVIov3EMmgIhhThevh9aiMQov+6Btx0wldNcvm4wV+e2/Rt1QdDwKHFbHw==} + engines: {node: '>=16'} + dev: false + /type-is@1.6.18: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} @@ -13590,6 +14099,10 @@ packages: resolution: {integrity: sha512-bhTyI94tZofjo+Dn8SN6Zv8nBDvyXTymAdM3LDI/0IboIUwTu1rEhW7v2TfiVsoYWgkQ4kOVqnI8APUFbIQIFQ==} dev: true + /ufo@1.3.2: + resolution: {integrity: sha512-o+ORpgGwaYQXgqGDwd+hkS4PuZ3QnmqMMxRuajK/a38L6fTpcE5GPIfrf+L/KemFzfUpeUQc1rRS1iDBozvnFA==} + dev: false + /uglify-js@3.17.4: resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==} engines: {node: '>=0.8.0'} @@ -14008,7 +14521,6 @@ packages: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 - dev: true /wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} @@ -14164,6 +14676,15 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + /zod-validation-error@3.0.2(zod@3.22.4): + resolution: {integrity: sha512-21xGaDmnU7lJZ4J63n5GXWqi+rTzGy3gDHbuZ1jP6xrK/DEQGyOqs/xW7eH96tIfCOYm+ecCuT0bfajBRKEVUw==} + engines: {node: '>=18.0.0'} + peerDependencies: + zod: ^3.18.0 + dependencies: + zod: 3.22.4 + dev: false + /zod@3.22.4: resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} dev: false