diff --git a/.cursor/commands/code-review.md b/.cursor/commands/code-review.md new file mode 100644 index 000000000..669fec771 --- /dev/null +++ b/.cursor/commands/code-review.md @@ -0,0 +1,156 @@ +--- +name: code-review +description: Automated PR review using comprehensive checklist tailored for modularized Contentstack CLI +--- + +# Code Review Command + +## Usage Patterns + +### Scope-Based Reviews +- `/code-review` - Review all current changes with full checklist +- `/code-review --scope typescript` - Focus on TypeScript configuration and patterns +- `/code-review --scope testing` - Focus on Mocha/Chai test patterns +- `/code-review --scope oclif` - Focus on command structure and OCLIF patterns +- `/code-review --scope packages` - Focus on package structure and organization + +### Severity Filtering +- `/code-review --severity critical` - Show only critical issues (security, breaking changes) +- `/code-review --severity high` - Show high and critical issues +- `/code-review --severity all` - Show all issues including suggestions + +### Package-Aware Reviews +- `/code-review --package contentstack-import` - Review changes in import package +- `/code-review --package contentstack-export` - Review changes in export package +- `/code-review --package-type plugin` - Review all plugin packages (all 12 packages are plugins) +- `/code-review --package-scope cm` - Review CM (content management) related packages + +### File Type Focus +- `/code-review --files commands` - Review command files only +- `/code-review --files tests` - Review test files only +- `/code-review --files utils` - Review utility files + +## Comprehensive Review Checklist + +### Monorepo Structure Compliance +- **Package organization**: 12 plugin packages under `packages/contentstack-*` +- **pnpm workspace**: Correct `pnpm-workspace.yaml` configuration +- **Build artifacts**: No `lib/` directories committed to version control +- **Dependencies**: Proper use of shared utilities (`@contentstack/cli-command`, `@contentstack/cli-utilities`) +- **Scripts**: Consistent build, test, and lint scripts across packages + +### Package-Specific Structure +- **All packages are plugins**: Each has `oclif.commands` configuration pointing to `./lib/commands` +- **Plugin topics**: All commands under `cm:` topic (content management) +- **Base commands**: Each plugin defines its own `BaseCommand` extending `@contentstack/cli-command` Command +- **Inter-plugin dependencies**: Some plugins depend on others (e.g., import depends on audit) +- **Dependency versions**: Using consistent versions across plugins + +### TypeScript Standards +- **Configuration compliance**: Follows package TypeScript config (`strict: false`, `target: es2017`) +- **Naming conventions**: kebab-case files, PascalCase classes, camelCase functions +- **Import patterns**: ES modules with proper default/named exports +- **Type safety**: No unnecessary `any` types in production code + +### OCLIF Command Patterns +- **Base class usage**: Extends plugin-specific `BaseCommand` or `@contentstack/cli-command` Command +- **Command structure**: Proper `static id`, `static description`, `static examples`, `static flags` +- **Topic organization**: Uses `cm:stacks:*` structure (`cm:stacks:import`, `cm:stacks:export`, `cm:stacks:audit`) +- **Error handling**: Uses `handleAndLogError` from utilities with context +- **Flag validation**: Early validation and user-friendly error messages +- **Service delegation**: Commands are thin, services handle business logic + +### Testing Excellence (Mocha/Chai Stack) +- **Framework compliance**: Uses Mocha + Chai (not Jest) +- **File patterns**: Follows `*.test.ts` naming convention +- **Directory structure**: Proper placement in `test/unit/` +- **Test organization**: Arrange-Act-Assert pattern consistently used +- **Isolation**: Proper setup/teardown with beforeEach/afterEach +- **No real API calls**: All external dependencies properly mocked + +### Error Handling Standards +- **Consistent patterns**: Use `handleAndLogError` from utilities +- **User-friendly messages**: Clear error descriptions for end users +- **Logging**: Proper use of `log.debug` for diagnostic information +- **Status messages**: Use `cliux` for user feedback (success, error, info) + +### Build and Compilation +- **TypeScript compilation**: Clean compilation with no errors +- **OCLIF manifest**: Generated for command discovery +- **README generation**: Commands documented in package README +- **Source maps**: Properly configured for debugging +- **No build artifacts in commit**: `.gitignore` excludes `lib/` directories + +### Testing Coverage +- **Test structure**: Tests in `test/unit/` with descriptive names +- **Command testing**: Uses @oclif/test for command validation +- **Error scenarios**: Tests for both success and failure paths +- **Mocking**: All dependencies properly mocked + +### Package.json Compliance +- **Correct metadata**: name, description, version, author +- **Script definitions**: build, compile, test, lint scripts present +- **Dependencies**: Correct versions of shared packages +- **Main/types**: Properly configured for library packages +- **OCLIF config**: Present for plugin packages + +### Security and Best Practices +- **No secrets**: No API keys or tokens in code or tests +- **Input validation**: Proper validation of user inputs and flags +- **Process management**: Appropriate use of error codes +- **File operations**: Safe handling of file system operations + +### Code Quality +- **Naming consistency**: Follow established conventions +- **Comments**: Only for non-obvious logic (no "narration" comments) +- **Error messages**: Clear, actionable messages for users +- **Module organization**: Proper separation of concerns + +## Review Execution + +### Automated Checks +1. **Lint compliance**: ESLint checks for code style +2. **TypeScript compiler**: Successful compilation to `lib/` directories +3. **Test execution**: All tests pass successfully +4. **Build verification**: Build scripts complete without errors + +### Manual Review Focus Areas +1. **Command usability**: Clear help text and realistic examples +2. **Error handling**: Appropriate error messages and recovery options +3. **Test quality**: Comprehensive test coverage for critical paths +4. **Monorepo consistency**: Consistent patterns across all packages +5. **Flag design**: Intuitive flag names and combinations + +### Common Issues to Flag +- **Inconsistent TypeScript settings**: Mixed strict mode without reason +- **Real API calls in tests**: Unmocked external dependencies +- **Missing error handling**: Commands that fail silently +- **Poor test organization**: Tests without clear Arrange-Act-Assert +- **Build artifacts committed**: `lib/` directories in version control +- **Unclear error messages**: Non-actionable error descriptions +- **Inconsistent flag naming**: Similar flags with different names +- **Missing command examples**: Examples not showing actual usage + +## Repository-Specific Checklist + +### For Modularized CLI +- [ ] Command properly extends `@contentstack/cli-command` Command +- [ ] Flags defined with proper types from `@contentstack/cli-utilities` +- [ ] Error handling uses `handleAndLogError` utility +- [ ] User feedback uses `cliux` utilities +- [ ] Tests use Mocha + Chai pattern with mocked dependencies +- [ ] Package.json has correct scripts (build, compile, test, lint) +- [ ] TypeScript compiles with no errors +- [ ] Tests pass: `pnpm test` +- [ ] No `.only` or `.skip` in test files +- [ ] Build succeeds: `pnpm run build` +- [ ] OCLIF manifest generated successfully + +### Before Merge +- [ ] All review items addressed +- [ ] No build artifacts in commit +- [ ] Tests added for new functionality +- [ ] Documentation updated if needed +- [ ] No console.log() statements (use log.debug instead) +- [ ] Error messages are user-friendly +- [ ] No secrets or credentials in code diff --git a/.cursor/commands/execute-tests.md b/.cursor/commands/execute-tests.md new file mode 100644 index 000000000..a27de0cdc --- /dev/null +++ b/.cursor/commands/execute-tests.md @@ -0,0 +1,252 @@ +--- +name: execute-tests +description: Run tests by scope, file, or module with intelligent filtering for this pnpm monorepo +--- + +# Execute Tests Command + +## Usage Patterns + +### Monorepo-Wide Testing +- `/execute-tests` - Run all tests across all packages +- `/execute-tests --coverage` - Run all tests with coverage reporting +- `/execute-tests --parallel` - Run package tests in parallel using pnpm + +### Package-Specific Testing +- `/execute-tests contentstack-import` - Run tests for import package +- `/execute-tests contentstack-export` - Run tests for export package +- `/execute-tests contentstack-audit` - Run tests for audit package +- `/execute-tests contentstack-clone` - Run tests for clone package +- `/execute-tests packages/contentstack-import/` - Run tests using path + +### Scope-Based Testing +- `/execute-tests unit` - Run unit tests only (`test/unit/**/*.test.ts`) +- `/execute-tests commands` - Run command tests (`test/unit/commands/**/*.test.ts`) +- `/execute-tests services` - Run service layer tests + +### File Pattern Testing +- `/execute-tests *.test.ts` - Run all TypeScript tests +- `/execute-tests test/unit/commands/` - Run tests for specific directory + +### Watch and Development +- `/execute-tests --watch` - Run tests in watch mode with file monitoring +- `/execute-tests --debug` - Run tests with debug output enabled +- `/execute-tests --bail` - Stop on first test failure + +## Intelligent Filtering + +### Repository-Aware Detection +- **Test patterns**: All use `*.test.ts` naming convention +- **Directory structures**: Standard `test/unit/` layout +- **Test locations**: `packages/*/test/unit/**/*.test.ts` +- **Build exclusion**: Ignores `lib/` directories (compiled artifacts) + +### Package Structure +The monorepo contains 12 CLI plugin packages: +- `contentstack-audit` - Stack audit and fix operations +- `contentstack-bootstrap` - Seed/bootstrap stacks +- `contentstack-branches` - Git-based branch management +- `contentstack-bulk-publish` - Bulk publish operations +- `contentstack-clone` - Clone/duplicate stacks +- `contentstack-export` - Export stack content +- `contentstack-export-to-csv` - Export to CSV format +- `contentstack-import` - Import content to stacks +- `contentstack-import-setup` - Import setup and validation +- `contentstack-migration` - Content migration workflows +- `contentstack-seed` - Seed stacks with data +- `contentstack-variants` - Manage content variants + +### Monorepo Integration +- **pnpm workspace support**: Uses `pnpm -r --filter` for package targeting +- **Dependency awareness**: Understands package interdependencies +- **Parallel execution**: Leverages pnpm's parallel capabilities +- **Selective testing**: Can target specific packages or file patterns + +### Framework Detection +- **Mocha configuration**: Respects `.mocharc.json` files per package +- **TypeScript compilation**: Handles test TypeScript setup +- **Test setup**: Detects test helper initialization files +- **Test timeout**: 30 seconds standard (configurable per package) + +## Execution Examples + +### Common Workflows +```bash +# Run all tests with coverage +/execute-tests --coverage + +# Test specific package during development +/execute-tests contentstack-import --watch + +# Run only command tests across all packages +/execute-tests commands + +# Run unit tests with detailed output +/execute-tests --debug + +# Test until first failure (quick feedback) +/execute-tests --bail +``` + +### Package-Specific Commands Generated +```bash +# For contentstack-import package +cd packages/contentstack-import && pnpm test + +# For all packages with parallel execution +pnpm -r run test + +# For specific test file +cd packages/contentstack-import && npx mocha "test/unit/commands/import.test.ts" + +# With coverage +pnpm -r run test:coverage +``` + +## Configuration Awareness + +### Mocha Integration +- Respects individual package `.mocharc.json` configurations +- Handles TypeScript compilation via ts-node/register +- Supports test helpers and initialization files +- Manages timeout settings per package (default 30 seconds) + +### Test Configuration +```json +// .mocharc.json +{ + "require": [ + "test/helpers/init.js", + "ts-node/register", + "source-map-support/register" + ], + "recursive": true, + "timeout": 30000, + "spec": "test/**/*.test.ts" +} +``` + +### pnpm Workspace Features +- Leverages workspace dependency resolution +- Supports filtered execution by package patterns +- Enables parallel test execution across packages +- Respects package-specific scripts and configurations + +## Test Structure + +### Standard Test Organization +``` +packages/*/ +├── test/ +│ └── unit/ +│ ├── commands/ # Command-specific tests +│ ├── services/ # Service/business logic tests +│ └── utils/ # Utility function tests +└── src/ + ├── commands/ # CLI commands + ├── services/ # Business logic + └── utils/ # Utilities +``` + +### Test File Naming +- **Pattern**: `*.test.ts` across all packages +- **Location**: `test/unit/` directories +- **Organization**: Mirrors `src/` structure for easy navigation + +## Performance Optimization + +### Parallel Testing +```bash +# Run tests in parallel for faster feedback +pnpm -r --filter './packages/*' run test + +# Watch mode during development +/execute-tests --watch +``` + +### Selective Testing +- Run only affected packages' tests during development +- Use `--bail` to stop on first failure for quick iteration +- Target specific test files for focused debugging + +## Troubleshooting + +### Common Issues + +**Tests not found** +- Check that files follow `*.test.ts` pattern +- Verify files are in `test/unit/` directory +- Ensure `.mocharc.json` has correct spec pattern + +**TypeScript compilation errors** +- Verify `tsconfig.json` in package root +- Check that `ts-node/register` is in `.mocharc.json` requires +- Run `pnpm compile` to check TypeScript errors + +**Watch mode not detecting changes** +- Verify `--watch` flag is supported in your Mocha version +- Check that file paths are correct +- Ensure no excessive `.gitignore` patterns + +**Port conflicts** +- Tests should not use hard-coded ports +- Use dynamic port allocation or test isolation +- Check for process cleanup in `afterEach` hooks + +## Best Practices + +### Test Execution +- Run tests before committing: `pnpm test` +- Use `--bail` during development for quick feedback +- Run full suite before opening PR +- Check coverage for critical paths + +### Test Organization +- Keep tests close to source code structure +- Use descriptive test names +- Group related tests with `describe` blocks +- Clean up resources in `afterEach` + +### Debugging +- Use `--debug` flag for detailed output +- Add `log.debug()` statements in tests +- Run individual test files for isolation +- Use `--bail` to stop at first failure + +## Integration with CI/CD + +### GitHub Actions +- Runs `pnpm test` on pull requests +- Enforces test passage before merge +- May include coverage reporting +- Runs linting and build verification + +### Local Development +```bash +# Before committing +pnpm test +pnpm run lint +pnpm run build + +# Or use watch mode for faster iteration +pnpm test --watch +``` + +## Coverage Reporting + +### Coverage Commands +```bash +# Run tests with coverage +/execute-tests --coverage + +# Coverage output location +coverage/ +├── index.html # HTML report +├── coverage-summary.json # JSON summary +└── lcov.info # LCOV format +``` + +### Coverage Goals +- **Team aspiration**: 80% minimum coverage +- **Focus on**: Critical business logic and error paths +- **Not critical**: Utility functions and edge cases diff --git a/.cursor/rules/README.md b/.cursor/rules/README.md new file mode 100644 index 000000000..cbb51b61b --- /dev/null +++ b/.cursor/rules/README.md @@ -0,0 +1,99 @@ +# Cursor Rules + +Context-aware rules that load automatically based on the files you're editing, optimized for this CLI plugins monorepo. + +## Rule Files + +| File | Scope | Always Applied | Purpose | +|------|-------|----------------|---------| +| `dev-workflow.md` | `**/*.ts`, `**/*.js`, `**/*.json` | Yes | Monorepo TDD workflow, pnpm workspace patterns (12 plugin packages) | +| `typescript.mdc` | `**/*.ts`, `**/*.tsx` | No | TypeScript configurations and naming conventions | +| `testing.mdc` | `**/test/**/*.ts`, `**/test/**/*.js`, `**/__tests__/**/*.ts`, `**/*.spec.ts`, `**/*.test.ts` | Yes | Mocha, Chai test patterns and test structure | +| `oclif-commands.mdc` | `**/commands/**/*.ts`, `**/base-command.ts` | No | OCLIF command patterns and CLI validation | +| `contentstack-plugin.mdc` | `packages/contentstack-*/src/**/*.ts`, `packages/contentstack-*/src/**/*.js` | No | CLI plugin package patterns, commands, services, and inter-plugin dependencies | + +## Commands + +| File | Trigger | Purpose | +|------|---------|---------| +| `execute-tests.md` | `/execute-tests` | Run tests by scope, package, or module with monorepo awareness | +| `code-review.md` | `/code-review` | Automated PR review with CLI-specific checklist | + +## Loading Behaviour + +### File Type Mapping +- **TypeScript files** → `typescript.mdc` + `dev-workflow.md` +- **Command files** (`packages/*/src/commands/**/*.ts`) → `oclif-commands.mdc` + `typescript.mdc` + `dev-workflow.md` +- **Base command files** (`packages/*/src/base-command.ts`, `packages/*/*base-command.ts`) → `oclif-commands.mdc` + `typescript.mdc` + `dev-workflow.md` +- **Plugin package files** (`packages/contentstack-*/src/**/*.ts`) → `contentstack-plugin.mdc` + `typescript.mdc` + `dev-workflow.md` +- **Test files** (`packages/*/test/**/*.{ts,js}`) → `testing.mdc` + `dev-workflow.md` +- **Utility files** (`packages/*/src/utils/**/*.ts`) → `typescript.mdc` + `dev-workflow.md` + +### Package-Specific Loading +- **Plugin packages** (with `oclif.commands`) → Full command and utility rules +- **Library packages** → TypeScript and utility rules only + +## Repository-Specific Features + +### Monorepo Structure + +This is a **CLI plugins** monorepo with 12 plugin packages under `packages/`: +- `contentstack-audit` - Stack audit and fix operations +- `contentstack-bootstrap` - Seed/bootstrap stacks with content +- `contentstack-branches` - Git-based branch management for stacks +- `contentstack-bulk-publish` - Bulk publish operations for entries/assets +- `contentstack-clone` - Clone/duplicate stacks +- `contentstack-export` - Export stack content to filesystem +- `contentstack-export-to-csv` - Export stack data to CSV format +- `contentstack-import` - Import content into stacks +- `contentstack-import-setup` - Setup and validation for imports +- `contentstack-migration` - Content migration workflows +- `contentstack-seed` - Seed stacks with generated data +- `contentstack-variants` - Manage content variants + +All plugins depend on: +- `@contentstack/cli-command` - Base Command class +- `@contentstack/cli-utilities` - Shared utilities and helpers +- Optionally on each other (e.g., `contentstack-import` depends on `@contentstack/cli-audit`) + +### Build Configuration +- **pnpm workspaces** configuration (all 12 plugins under `packages/`) +- **Shared dependencies**: Each plugin depends on `@contentstack/cli-command` and `@contentstack/cli-utilities` +- **Inter-plugin dependencies**: Some plugins depend on others (e.g., import → audit) +- **Build process**: TypeScript compilation → `lib/` directories +- **OCLIF manifest** generation per plugin for command discovery + +### Actual Patterns Detected +- **Testing**: Mocha + Chai (consistent across all plugins) +- **TypeScript**: Strict mode for type safety +- **Commands**: Extend `@contentstack/cli-command` Command class with plugin-specific base-commands +- **Topics**: All commands under `cm:` topic (content management) +- **Services/Modules**: Domain-specific business logic organized by concern +- **Build artifacts**: `lib/` directories (excluded from rules) + +## Performance Benefits + +- **Lightweight loading** - Only relevant rules activate based on file patterns +- **Precise glob patterns** - Avoid loading rules for build artifacts +- **Context-aware** - Rules load based on actual file structure + +## Design Principles + +### Validated Against Codebase +- Rules reflect **actual patterns** found in repository +- Glob patterns match **real file structure** +- Examples use **actual dependencies** and APIs + +### Lightweight and Focused +- Each rule has **single responsibility** +- Package-specific variations acknowledged +- `alwaysApply: true` only for truly universal patterns + +## Quick Reference + +For detailed patterns: +- **Testing**: See `testing.mdc` for Mocha/Chai test structure +- **Commands**: See `oclif-commands.mdc` for command development +- **Plugins**: See `contentstack-plugin.mdc` for plugin architecture and patterns +- **Development**: See `dev-workflow.md` for TDD and monorepo workflow +- **TypeScript**: See `typescript.mdc` for type safety patterns diff --git a/.cursor/rules/contentstack-plugin.mdc b/.cursor/rules/contentstack-plugin.mdc new file mode 100644 index 000000000..e653d2c57 --- /dev/null +++ b/.cursor/rules/contentstack-plugin.mdc @@ -0,0 +1,475 @@ +--- +description: "Contentstack CLI plugin package patterns — commands, services, base-commands, and inter-plugin dependencies" +globs: ["packages/contentstack-*/src/**/*.ts", "packages/contentstack-*/src/**/*.js"] +alwaysApply: false +--- + +# Contentstack CLI Plugin Standards + +## Overview + +The **cli-plugins** monorepo contains 12 OCLIF plugin packages under `packages/`: +- `contentstack-audit`, `contentstack-bootstrap`, `contentstack-branches`, `contentstack-bulk-publish`, `contentstack-clone`, `contentstack-export`, `contentstack-export-to-csv`, `contentstack-import`, `contentstack-import-setup`, `contentstack-migration`, `contentstack-seed`, `contentstack-variants` + +Each plugin is a self-contained OCLIF package that: +- **Defines commands** — via `oclif.commands` in `package.json` pointing to `./lib/commands` +- **Depends on shared libraries** — `@contentstack/cli-command` (Base Command class), `@contentstack/cli-utilities` (shared utils and services) +- **May depend on other plugins** — e.g., `contentstack-import` depends on `@contentstack/cli-audit` for audit operations +- **Implements business logic** — in services, modules, and utility classes +- **Has a local base-command** — extending `@contentstack/cli-command` Command class with plugin-specific initialization and flags + +## Architecture + +### Package Structure + +``` +packages/contentstack-import/ +├── src/ +│ ├── commands/ +│ │ └── cm/ +│ │ └── stacks/ +│ │ └── import.ts +│ ├── services/ +│ │ ├── import-service.ts +│ │ └── validation-service.ts +│ ├── modules/ +│ │ ├── entries.ts +│ │ ├── assets.ts +│ │ └── ... +│ ├── base-command.ts (or import-base-command.ts) +│ ├── types/ +│ ├── interfaces/ +│ ├── messages/ +│ └── utils/ +├── test/ +│ └── unit/ +│ ├── commands/ +│ ├── services/ +│ └── ... +├── package.json +├── tsconfig.json +└── .mocharc.json +``` + +### Package Configuration + +Each plugin's `package.json` declares its commands and declares itself as an OCLIF plugin: + +```json +{ + "name": "@contentstack/cli-cm-import", + "oclif": { + "commands": "./lib/commands", + "topics": { + "stacks": { + "description": "Manage stacks" + } + } + }, + "dependencies": { + "@contentstack/cli-command": "~1.8.0", + "@contentstack/cli-utilities": "~1.18.0", + "@contentstack/cli-audit": "~1.19.0" + } +} +``` + +## Base Command Pattern + +### Plugin-Specific Base Command + +Each plugin defines its own `BaseCommand` (or specialized variant like `AuditBaseCommand`): + +```typescript +// ✅ GOOD - packages/contentstack-audit/src/base-command.ts +import { Command } from '@contentstack/cli-command'; +import { Flags, FlagInput } from '@contentstack/cli-utilities'; + +export abstract class BaseCommand extends Command { + protected sharedConfig = { + basePath: process.cwd(), + }; + + static baseFlags: FlagInput = { + config: Flags.string({ + char: 'c', + description: 'Path to config file', + }), + 'data-dir': Flags.string({ + char: 'd', + description: 'Data directory path', + }), + }; + + public async init(): Promise { + await super.init(); + const { args, flags } = await this.parse({ + flags: this.ctor.flags, + args: this.ctor.args, + strict: this.ctor.strict !== false, + }); + this.args = args; + this.flags = flags; + } +} +``` + +### Specialized Base Commands + +Some plugins define specialized versions for specific concerns: + +```typescript +// ✅ GOOD - packages/contentstack-audit/src/audit-base-command.ts +// Extends BaseCommand with audit-specific logic +import { BaseCommand } from './base-command'; + +export abstract class AuditBaseCommand extends BaseCommand { + // Audit-specific initialization and helpers + protected async runAudit(): Promise { + // Common audit logic + } +} + +// Usage in commands +export default class AuditFixCommand extends AuditBaseCommand { + async run(): Promise { + await this.runAudit(); + } +} +``` + +## Command Structure + +### CM Topic Commands + +Commands are organized under the `cm` topic with subtopics for domains: + +```typescript +// ✅ GOOD - packages/contentstack-import/src/commands/cm/stacks/import.ts +import { Flags, FlagInput, cliux } from '@contentstack/cli-utilities'; +import { BaseCommand } from '../../../base-command'; + +export default class ImportCommand extends BaseCommand { + static id = 'cm:stacks:import'; + static description = 'Import content into a stack'; + static examples = [ + '$ csdx cm:stacks:import -k -d ', + '$ csdx cm:stacks:import -k -d --content-types entry,asset', + ]; + + static flags: FlagInput = { + 'stack-api-key': Flags.string({ + char: 'k', + description: 'Stack API key', + required: true, + }), + 'data-dir': Flags.string({ + char: 'd', + description: 'Directory with import data', + required: true, + }), + 'content-types': Flags.string({ + description: 'Content types to import (comma-separated)', + default: 'all', + }), + }; + + async run(): Promise { + try { + const { flags } = this; + cliux.loaderV2('Starting import...'); + + // Delegate to service + const importService = new ImportService(flags); + await importService.import(); + + cliux.success('Import completed'); + } catch (error) { + handleAndLogError(error, { + module: 'import', + command: this.id, + }); + } + } +} +``` + +## Service and Module Patterns + +### Service Layer + +Services encapsulate business logic and are used by commands: + +```typescript +// ✅ GOOD - packages/contentstack-import/src/services/import-service.ts +import { cliux, log } from '@contentstack/cli-utilities'; + +export class ImportService { + constructor(private flags: any) {} + + async import(): Promise { + // Orchestrate import workflow + await this.validateInput(); + await this.loadData(); + await this.importContent(); + } + + private async validateInput(): Promise { + log.debug('Validating input', { module: 'import-service' }); + // Validation logic + } + + private async loadData(): Promise { + // Load data from directory + } + + private async importContent(): Promise { + // Import content logic + } +} +``` + +### Module Pattern + +Some plugins use modules for domain-specific operations: + +```typescript +// ✅ GOOD - packages/contentstack-import/src/modules/entries.ts +import isEmpty from 'lodash/isEmpty'; +import { log } from '@contentstack/cli-utilities'; + +export class Entries { + constructor(private client: any, private basePath: string) {} + + async import(entries: any[]): Promise { + if (isEmpty(entries)) { + log.debug('No entries to import'); + return; + } + + for (const entry of entries) { + await this.importEntry(entry); + } + } + + private async importEntry(entry: any): Promise { + // Import individual entry + } +} +``` + +## Shared Dependencies + +All plugins depend on core libraries: + +```json +{ + "dependencies": { + "@contentstack/cli-command": "~1.8.0", + "@contentstack/cli-utilities": "~1.18.0" + } +} +``` + +### Common Utilities Used + +```typescript +// ✅ GOOD - Import and use shared utilities +import { + cliux, // CLI UI helpers (loaders, tables, success/error) + ux, // OCLIF ux utilities + log, // Structured logging + handleAndLogError, // Error handling with context + configHandler, // CLI configuration management + sanitizePath, // Path sanitization + managementSDKClient, // Contentstack API client factory +} from '@contentstack/cli-utilities'; + +import { Command, Interfaces } from '@contentstack/cli-command'; +``` + +## Inter-Plugin Dependencies + +Plugins can depend on other plugins to share functionality: + +```json +{ + "dependencies": { + "@contentstack/cli-audit": "~1.19.0" + } +} +``` + +### Using Shared Plugin Code + +```typescript +// ✅ GOOD - Import from other plugin packages +import { AuditService } from '@contentstack/cli-audit'; + +export class ImportService { + async import(): Promise { + // Do import + await new AuditService().runAudit(); + } +} +``` + +## Error Handling + +Error handling follows a consistent pattern across plugins: + +```typescript +// ✅ GOOD - Comprehensive error handling +import { handleAndLogError, CLIError } from '@contentstack/cli-utilities'; + +async run(): Promise { + try { + // Business logic + const result = await this.importService.import(); + return result; + } catch (error) { + // Log error with module/command context + handleAndLogError(error, { + module: 'import', + command: this.id, + dataDir: this.flags['data-dir'], + }); + this.exit(1); + } +} +``` + +## Build Process + +Each plugin builds independently but follows the same pattern: + +```bash +# In package.json scripts +"build": "pnpm compile && oclif manifest" +``` + +### Build Steps + +1. **compile** — TypeScript → JavaScript in `lib/` +2. **oclif manifest** — Generate `oclif.manifest.json` for command discovery + +### Build Artifacts + +- `lib/` — Compiled commands, services, modules +- `oclif.manifest.json` — Command registry for this plugin +- `README.md` — Generated command documentation (optional) + +## Configuration and Messaging + +### Messages + +Plugins store user-facing strings in centralized message files: + +```typescript +// ✅ GOOD - packages/contentstack-import/src/messages/index.ts +export const importMsg = { + IMPORT_START: 'Starting import...', + IMPORT_SUCCESS: 'Import completed successfully', + VALIDATION_ERROR: 'Validation failed: {{reason}}', +}; +``` + +### Configuration + +Plugin-specific defaults are stored in config files: + +```typescript +// ✅ GOOD - packages/contentstack-import/src/config/index.ts +export default { + batchSize: 50, + retryAttempts: 3, + timeout: 30000, + logLevel: 'info', +}; +``` + +## Testing Patterns + +### Command Testing + +Test commands using `@oclif/test`: + +```typescript +// ✅ GOOD - packages/contentstack-import/test/unit/commands/import.test.ts +import { test } from '@oclif/test'; +import { expect } from 'chai'; + +describe('ImportCommand', () => { + test + .stdout() + .command(['cm:stacks:import', '--help']) + .it('shows help message', (ctx) => { + expect(ctx.stdout).to.contain('Import content'); + }); + + test + .command(['cm:stacks:import', '-k', 'test-key', '-d', '/tmp/data']) + .it('runs import command'); +}); +``` + +### Service Testing + +Test services with unit tests: + +```typescript +// ✅ GOOD - packages/contentstack-import/test/unit/services/import-service.test.ts +import { expect } from 'chai'; +import { ImportService } from '../../../src/services/import-service'; + +describe('ImportService', () => { + let service: ImportService; + + beforeEach(() => { + service = new ImportService({ + 'stack-api-key': 'test-key', + 'data-dir': '/tmp/data', + }); + }); + + it('should validate input before import', async () => { + // Test validation logic + }); + + it('should handle import errors', async () => { + // Test error handling + }); +}); +``` + +## Best Practices + +### Command Design +- Keep commands thin — delegate to services +- Validate flags early and fail fast +- Provide clear error messages with actionable guidance +- Include command examples in static `examples` + +### Service Design +- Keep services focused on a single domain +- Make services testable by accepting dependencies via constructor +- Use modules for complex domain operations +- Document service public API clearly + +### Error Handling +- Always provide context in error logs (module, command, relevant state) +- Use structured error types (CLIError) for user-facing errors +- Include remediation guidance in error messages +- Log all errors, even those caught and handled + +### Testing +- Test commands with @oclif/test +- Test services with unit tests and mocks +- Cover both happy path and error cases +- Use fixtures for test data, not live APIs + +### Dependencies +- Always use `@contentstack/cli-utilities` for CLI concerns +- Use `@contentstack/cli-command` as base for commands +- Depend on other plugins only if truly needed (watch for circular deps) +- Pin dependency versions to minor (`~` semver) for stability diff --git a/.cursor/rules/dev-workflow.md b/.cursor/rules/dev-workflow.md new file mode 100644 index 000000000..4bfe91360 --- /dev/null +++ b/.cursor/rules/dev-workflow.md @@ -0,0 +1,206 @@ +--- +description: "Core development workflow and TDD patterns - always applied" +globs: ["**/*.ts", "**/*.js", "**/*.json"] +alwaysApply: true +--- + +# Development Workflow + +## Monorepo Structure + +### Package Organization +This **CLI plugins** monorepo has 12 packages under `packages/`: + +1. **contentstack-audit** - Stack audit and fix operations +2. **contentstack-bootstrap** - Seed/bootstrap stacks +3. **contentstack-branches** - Git-based branch management +4. **contentstack-bulk-publish** - Bulk publish operations +5. **contentstack-clone** - Clone/duplicate stacks +6. **contentstack-export** - Export stack content +7. **contentstack-export-to-csv** - Export to CSV format +8. **contentstack-import** - Import content to stacks +9. **contentstack-import-setup** - Import setup and validation +10. **contentstack-migration** - Content migration workflows +11. **contentstack-seed** - Seed stacks with data +12. **contentstack-variants** - Manage content variants + +All plugins depend on `@contentstack/cli-command` and `@contentstack/cli-utilities`. Some plugins also depend on each other. + +### pnpm Workspace Configuration +```json +{ + "workspaces": ["packages/*"] +} +``` + +### Development Commands +```bash +# Install dependencies for all packages +pnpm install + +# Run command across all packages +pnpm -r run + +# Run command in specific package +pnpm -r --filter '@contentstack/cli-cm-import' test + +# Work on specific package +cd packages/contentstack-import +pnpm test +``` + +## TDD Workflow - MANDATORY + +1. **RED** → Write ONE failing test in `test/unit/**/*.test.ts` +2. **GREEN** → Write minimal code in `src/` to pass +3. **REFACTOR** → Improve code quality while keeping tests green + +### Test-First Examples +```typescript +// ✅ GOOD - Write test first +describe('ConfigService', () => { + it('should load configuration', async () => { + // Arrange - Set up mocks + const mockConfig = { region: 'us', alias: 'default' }; + + // Act - Call the method + const result = await configService.load(); + + // Assert - Verify behavior + expect(result).to.deep.equal(mockConfig); + }); +}); +``` + +## Critical Rules + +### Testing Standards +- **NO implementation before tests** - Test-driven development only +- **Mock all external dependencies** - No real API calls in tests +- **Use Mocha + Chai** - Standard testing stack +- **Coverage aspiration**: 80% minimum + +### Code Quality +- **TypeScript configuration**: Varies by package +- **NO test.skip or .only in commits** - Clean test suites only +- **Proper error handling** - Clear error messages + +### Build Process +```bash +# Standard build process for each package +pnpm run build # tsc compilation + oclif manifest +pnpm run test # Run test suite +pnpm run lint # ESLint checks +``` + +## Package-Specific Patterns + +### Plugin Packages (auth, config) +- Have `oclif.commands` in `package.json` +- Commands in `src/commands/cm/**/*.ts` +- Built commands in `lib/commands/` +- Extend `@oclif/core` Command class +- Script: `build`: compiles TypeScript, generates OCLIF manifest and README + +### Library Packages (command, utilities, dev-dependencies) +- No OCLIF commands configuration +- Pure TypeScript/JavaScript libraries +- Consumed by other packages +- `main` points to `lib/index.js` + +### Main CLI Package (contentstack) +- Entry point through `bin/run.js` +- Aggregates plugin commands +- Package dependencies reference plugin packages + +## Script Conventions + +### Build Scripts +```json +{ + "build": "pnpm compile && oclif manifest && oclif readme", + "compile": "tsc -b tsconfig.json", + "prepack": "pnpm compile && oclif manifest && oclif readme", + "test": "mocha \"test/unit/**/*.test.ts\"", + "lint": "eslint src/**/*.ts" +} +``` + +### Key Build Steps +1. **compile** - TypeScript compilation to `lib/` +2. **oclif manifest** - Generate command manifest for discovery +3. **oclif readme** - Generate command documentation + +## Quick Reference + +For detailed patterns, see: +- `@testing` - Mocha, Chai test patterns +- `@oclif-commands` - Command structure and validation +- `@dev-workflow` (this document) - Monorepo workflow and TDD + +## Development Checklist + +### Before Starting Work +- [ ] Identify target package in `packages/` +- [ ] Check existing tests in `test/unit/` +- [ ] Understand command structure if working on commands +- [ ] Set up proper TypeScript configuration + +### During Development +- [ ] Write failing test first +- [ ] Implement minimal code to pass +- [ ] Mock external dependencies +- [ ] Follow naming conventions (kebab-case files, PascalCase classes) + +### Before Committing +- [ ] All tests pass: `pnpm test` +- [ ] No `.only` or `.skip` in test files +- [ ] Build succeeds: `pnpm run build` +- [ ] TypeScript compilation clean +- [ ] Proper error handling implemented + +## Common Patterns + +### Service/Class Architecture +```typescript +// ✅ GOOD - Separate concerns +export default class ConfigCommand extends Command { + static description = 'Manage CLI configuration'; + + async run(): Promise { + try { + const service = new ConfigService(); + await service.execute(); + this.log('Configuration updated successfully'); + } catch (error) { + this.error('Configuration update failed'); + } + } +} +``` + +### Error Handling +```typescript +// ✅ GOOD - Clear error messages +try { + await this.performAction(); +} catch (error) { + if (error instanceof ValidationError) { + this.error(`Invalid input: ${error.message}`); + } else { + this.error('Operation failed'); + } +} +``` + +## CI/CD Integration + +### GitHub Actions +- Uses workflow files in `.github/workflows/` +- Runs linting, tests, and builds on pull requests +- Enforces code quality standards + +### Pre-commit Hooks +- Husky integration for pre-commit checks +- Prevents commits with linting errors +- Located in `.husky/` diff --git a/.cursor/rules/oclif-commands.mdc b/.cursor/rules/oclif-commands.mdc new file mode 100644 index 000000000..7ca9bc25a --- /dev/null +++ b/.cursor/rules/oclif-commands.mdc @@ -0,0 +1,352 @@ +--- +description: 'OCLIF command development patterns and CLI best practices' +globs: ['**/commands/**/*.ts', '**/base-command.ts'] +alwaysApply: false +--- + +# OCLIF Command Standards + +## Command Structure + +### Standard Command Pattern +```typescript +// ✅ GOOD - Standard command structure +import { Command } from '@contentstack/cli-command'; +import { cliux, flags, FlagInput, handleAndLogError } from '@contentstack/cli-utilities'; + +export default class ConfigSetCommand extends Command { + static description = 'Set CLI configuration values'; + + static flags: FlagInput = { + region: flags.string({ + char: 'r', + description: 'Set region (us/eu)', + }), + alias: flags.string({ + char: 'a', + description: 'Configuration alias', + }), + }; + + static examples = [ + 'csdx config:set --region eu', + 'csdx config:set --region us --alias default', + ]; + + async run(): Promise { + try { + const { flags: configFlags } = await this.parse(ConfigSetCommand); + // Command logic here + } catch (error) { + handleAndLogError(error, { module: 'config-set' }); + } + } +} +``` + +## Base Classes + +### Command Base Class +```typescript +// ✅ GOOD - Extend Command from @contentstack/cli-command +import { Command } from '@contentstack/cli-command'; + +export default class MyCommand extends Command { + async run(): Promise { + // Command implementation + } +} +``` + +### Custom Base Classes +```typescript +// ✅ GOOD - Create custom base classes for shared functionality +export abstract class BaseCommand extends Command { + protected contextDetails = { + command: this.id || 'unknown', + }; + + async init(): Promise { + await super.init(); + log.debug('Command initialized', this.contextDetails); + } +} +``` + +## OCLIF Configuration + +### Package.json Setup +```json +{ + "oclif": { + "commands": "./lib/commands", + "bin": "csdx", + "topicSeparator": ":" + } +} +``` + +### Command Topics +- All commands use `cm` topic: `cm:config:set`, `cm:auth:login` +- Built commands live in `lib/commands` (compiled from `src/commands`) +- Commands use nested directories: `src/commands/config/set.ts` → `cm:config:set` + +### Command Naming +- **Topic hierarchy**: `config/remove/proxy.ts` → `cm:config:remove:proxy` +- **Descriptive names**: Use verb-noun pattern (`set`, `remove`, `show`) +- **Grouping**: Related commands share parent topics + +## Flag Management + +### Flag Definition Patterns +```typescript +// ✅ GOOD - Define flags clearly +static flags: FlagInput = { + 'stack-api-key': flags.string({ + char: 'k', + description: 'Stack API key', + required: false, + }), + region: flags.string({ + char: 'r', + description: 'Set region', + options: ['us', 'eu'], + }), + verbose: flags.boolean({ + char: 'v', + description: 'Show verbose output', + default: false, + }), +}; +``` + +### Flag Parsing +```typescript +// ✅ GOOD - Parse and validate flags +async run(): Promise { + const { flags: parsedFlags } = await this.parse(MyCommand); + + // Validate flag combinations + if (!parsedFlags['stack-api-key'] && !parsedFlags.alias) { + this.error('Either --stack-api-key or --alias is required'); + } + + // Use parsed flags + const region = parsedFlags.region || 'us'; +} +``` + +## Error Handling + +### Standard Error Pattern +```typescript +// ✅ GOOD - Use handleAndLogError from utilities +try { + await this.executeCommand(); +} catch (error) { + handleAndLogError(error, { module: 'my-command' }); +} +``` + +### User-Friendly Messages +```typescript +// ✅ GOOD - Clear user feedback +import { cliux } from '@contentstack/cli-utilities'; + +// Success message +cliux.success('Configuration updated successfully', { color: 'green' }); + +// Error message +cliux.error('Invalid region specified', { color: 'red' }); + +// Info message +cliux.print('Setting region to eu', { color: 'blue' }); +``` + +## Validation Patterns + +### Early Validation +```typescript +// ✅ GOOD - Validate flags early +async run(): Promise { + const { flags } = await this.parse(MyCommand); + + // Validate required flags + if (!flags.region) { + this.error('--region is required'); + } + + // Validate flag values + if (!['us', 'eu'].includes(flags.region)) { + this.error('Region must be "us" or "eu"'); + } + + // Proceed with validated input +} +``` + +## Progress and Logging + +### User Feedback +```typescript +// ✅ GOOD - Provide user feedback +import { log, cliux } from '@contentstack/cli-utilities'; + +// Regular logging +this.log('Starting configuration update...'); + +// Debug logging +log.debug('Detailed operation information', { context: 'data' }); + +// Status messages +cliux.print('Processing...', { color: 'blue' }); +``` + +### Progress Indication +```typescript +// ✅ GOOD - Show progress for long operations +cliux.print('Processing items...', { color: 'blue' }); +let count = 0; +for (const item of items) { + await this.processItem(item); + count++; + cliux.print(`Processed ${count}/${items.length} items`, { color: 'blue' }); +} +``` + +## Command Delegation + +### Service Layer Separation +```typescript +// ✅ GOOD - Commands orchestrate, services implement +async run(): Promise { + try { + const { flags } = await this.parse(MyCommand); + const config = this.buildConfig(flags); + const service = new ConfigService(config); + + await service.execute(); + cliux.success('Operation completed successfully'); + } catch (error) { + this.handleError(error); + } +} +``` + +## Testing Commands + +### OCLIF Test Support +```typescript +// ✅ GOOD - Use @oclif/test for command testing +import { test } from '@oclif/test'; + +describe('cm:config:set', () => { + test + .stdout() + .command(['cm:config:set', '--help']) + .it('shows help', ctx => { + expect(ctx.stdout).to.contain('Set CLI configuration'); + }); + + test + .stdout() + .command(['cm:config:set', '--region', 'eu']) + .it('sets region to eu', ctx => { + expect(ctx.stdout).to.contain('success'); + }); +}); +``` + +## Log Integration + +### Debug Logging +```typescript +// ✅ GOOD - Use structured debug logging +import { log } from '@contentstack/cli-utilities'; + +log.debug('Command started', { + command: this.id, + flags: this.flags, + timestamp: new Date().toISOString(), +}); + +log.debug('Processing complete', { + itemsProcessed: count, + module: 'my-command', +}); +``` + +### Error Context +```typescript +// ✅ GOOD - Include context in error handling +try { + await operation(); +} catch (error) { + handleAndLogError(error, { + module: 'config-set', + command: 'cm:config:set', + flags: { region: 'eu' }, + }); +} +``` + +## Multi-Topic Commands + +### Nested Command Structure +```typescript +// File: src/commands/config/show.ts +export default class ShowConfigCommand extends Command { + static description = 'Show current configuration'; + static examples = ['csdx config:show']; + async run(): Promise { } +} + +// File: src/commands/config/set.ts +export default class SetConfigCommand extends Command { + static description = 'Set configuration values'; + static examples = ['csdx config:set --region eu']; + async run(): Promise { } +} + +// Generated commands: +// - cm:config:show +// - cm:config:set +``` + +## Best Practices + +### Command Organization +```typescript +// ✅ GOOD - Well-organized command +export default class MyCommand extends Command { + static description = 'Clear, concise description'; + + static flags: FlagInput = { + // Define all flags + }; + + static examples = [ + 'csdx my:command', + 'csdx my:command --flag value', + ]; + + async run(): Promise { + try { + const { flags } = await this.parse(MyCommand); + await this.execute(flags); + } catch (error) { + handleAndLogError(error, { module: 'my-command' }); + } + } + + private async execute(flags: Flags): Promise { + // Implementation + } +} +``` + +### Clear Help Text +- Write description as action-oriented statement +- Provide multiple examples for common use cases +- Document each flag with clear description +- Show output format or examples of results diff --git a/.cursor/rules/testing.mdc b/.cursor/rules/testing.mdc new file mode 100644 index 000000000..daf6de108 --- /dev/null +++ b/.cursor/rules/testing.mdc @@ -0,0 +1,323 @@ +--- +description: 'Testing patterns and TDD workflow' +globs: ['**/test/**/*.ts', '**/test/**/*.js', '**/__tests__/**/*.ts', '**/*.spec.ts', '**/*.test.ts'] +alwaysApply: true +--- + +# Testing Standards + +## Framework Stack + +### Primary Testing Tools +- **Mocha** - Test runner (used across all packages) +- **Chai** - Assertion library +- **@oclif/test** - Command testing support (for plugin packages) + +### Test Setup +- TypeScript compilation via ts-node/register +- Source map support for stack traces +- Global test timeout: 30 seconds (configurable per package) + +## Test File Patterns + +### Naming Conventions +- **Primary**: `*.test.ts` (standard pattern across all packages) +- **Location**: `test/unit/**/*.test.ts` (most packages) + +### Directory Structure +``` +packages/*/ +├── test/ +│ └── unit/ +│ ├── commands/ # Command-specific tests +│ ├── services/ # Service/business logic tests +│ └── utils/ # Utility function tests +└── src/ # Source code + ├── commands/ # CLI commands + ├── services/ # Business logic + └── utils/ # Utilities +``` + +## Mocha Configuration + +### Standard Setup (.mocharc.json) +```json +{ + "require": [ + "test/helpers/init.js", + "ts-node/register", + "source-map-support/register" + ], + "recursive": true, + "timeout": 30000, + "spec": "test/**/*.test.ts" +} +``` + +### TypeScript Compilation +```json +// package.json scripts +{ + "test": "mocha \"test/unit/**/*.test.ts\"", + "test:coverage": "nyc mocha \"test/unit/**/*.test.ts\"" +} +``` + +## Test Structure + +### Standard Test Pattern +```typescript +// ✅ GOOD - Comprehensive test structure +describe('ConfigService', () => { + let service: ConfigService; + + beforeEach(() => { + service = new ConfigService(); + }); + + describe('loadConfig()', () => { + it('should load configuration successfully', async () => { + // Arrange + const expectedConfig = { region: 'us' }; + + // Act + const result = await service.loadConfig(); + + // Assert + expect(result).to.deep.equal(expectedConfig); + }); + + it('should handle missing configuration', async () => { + // Arrange & Act & Assert + await expect(service.loadConfig()).to.be.rejectedWith('Config not found'); + }); + }); +}); +``` + +### Async/Await Pattern +```typescript +// ✅ GOOD - Use async/await in tests +it('should process data asynchronously', async () => { + const result = await service.processAsync(); + expect(result).to.exist; +}); + +// ✅ GOOD - Explicit Promise handling +it('should return a promise', () => { + return service.asyncMethod().then(result => { + expect(result).to.be.true; + }); +}); +``` + +## Mocking Patterns + +### Class Mocking +```typescript +// ✅ GOOD - Mock class dependencies +class MockConfigService { + async loadConfig() { + return { region: 'us' }; + } +} + +it('should use mocked service', async () => { + const mockService = new MockConfigService(); + const result = await mockService.loadConfig(); + expect(result.region).to.equal('us'); +}); +``` + +### Function Stubs +```typescript +// ✅ GOOD - Stub module functions if needed +beforeEach(() => { + // Stub file system operations + // Stub network calls +}); + +afterEach(() => { + // Restore original implementations +}); +``` + +## Command Testing + +### OCLIF Test Pattern +```typescript +// ✅ GOOD - Test commands with @oclif/test +import { test } from '@oclif/test'; + +describe('cm:config:region', () => { + test + .stdout() + .command(['cm:config:region', '--help']) + .it('shows help message', ctx => { + expect(ctx.stdout).to.contain('Display region'); + }); + + test + .stdout() + .command(['cm:config:region']) + .it('shows current region', ctx => { + expect(ctx.stdout).to.contain('us'); + }); +}); +``` + +### Command Flag Testing +```typescript +// ✅ GOOD - Test command flags and arguments +describe('cm:config:set', () => { + test + .command(['cm:config:set', '--help']) + .it('shows usage information'); + + test + .command(['cm:config:set', '--region', 'eu']) + .it('sets region to eu'); +}); +``` + +## Error Testing + +### Error Handling +```typescript +// ✅ GOOD - Test error scenarios +it('should throw ValidationError on invalid input', async () => { + const invalidInput = ''; + await expect(service.validate(invalidInput)) + .to.be.rejectedWith('Invalid input'); +}); + +it('should handle network errors gracefully', async () => { + // Mock network failure + const result = await service.fetchWithRetry(); + expect(result).to.be.null; +}); +``` + +### Error Types +```typescript +// ✅ GOOD - Test specific error types +it('should throw appropriate error', async () => { + try { + await service.failingOperation(); + } catch (error) { + expect(error).to.be.instanceof(ValidationError); + expect(error.code).to.equal('INVALID_CONFIG'); + } +}); +``` + +## Test Data Management + +### Mock Data Organization +```typescript +// ✅ GOOD - Organize test data +const mockData = { + validConfig: { + region: 'us', + timeout: 30000, + }, + invalidConfig: { + region: '', + }, + users: [ + { email: 'user1@example.com', name: 'User 1' }, + { email: 'user2@example.com', name: 'User 2' }, + ], +}; +``` + +### Test Helpers +```typescript +// ✅ GOOD - Create reusable test utilities +export function createMockConfig(overrides?: Partial): Config { + return { + region: 'us', + timeout: 30000, + ...overrides, + }; +} + +export function createMockService( + config: Config = createMockConfig() +): ConfigService { + return new ConfigService(config); +} +``` + +## Coverage + +### Coverage Goals +- **Team aspiration**: 80% minimum coverage +- **Current enforcement**: Applied consistently across packages +- **Focus areas**: Critical business logic and error paths + +### Coverage Reporting +```bash +# Run tests with coverage +pnpm test:coverage + +# Coverage reports generated in: +# - coverage/index.html (HTML report) +# - coverage/coverage-summary.json (JSON report) +``` + +## Critical Testing Rules + +- **No real external calls** - Mock all dependencies +- **Test both success and failure paths** - Cover error scenarios completely +- **One assertion per test** - Focus each test on single behavior +- **Use descriptive test names** - Test name should explain what's tested +- **Arrange-Act-Assert** - Follow AAA pattern consistently +- **Test command validation** - Verify flag validation and error messages +- **Clean up after tests** - Restore any mocked state + +## Best Practices + +### Test Organization +```typescript +// ✅ GOOD - Organize related tests +describe('AuthCommand', () => { + describe('login', () => { + it('should authenticate user'); + it('should save token'); + }); + + describe('logout', () => { + it('should clear token'); + it('should reset config'); + }); +}); +``` + +### Async Test Patterns +```typescript +// ✅ GOOD - Handle async operations properly +it('should complete async operation', async () => { + const promise = service.asyncMethod(); + expect(promise).to.be.instanceof(Promise); + + const result = await promise; + expect(result).to.equal('success'); +}); +``` + +### Isolation +```typescript +// ✅ GOOD - Ensure test isolation +describe('ConfigService', () => { + let service: ConfigService; + + beforeEach(() => { + service = new ConfigService(); + }); + + afterEach(() => { + // Clean up resources + }); +}); +``` diff --git a/.cursor/rules/typescript.mdc b/.cursor/rules/typescript.mdc new file mode 100644 index 000000000..ea4d82a26 --- /dev/null +++ b/.cursor/rules/typescript.mdc @@ -0,0 +1,246 @@ +--- +description: 'TypeScript strict mode standards and naming conventions' +globs: ['**/*.ts', '**/*.tsx'] +alwaysApply: false +--- + +# TypeScript Standards + +## Configuration + +### Standard Configuration (All Packages) +```json +{ + "compilerOptions": { + "declaration": true, + "importHelpers": true, + "module": "commonjs", + "outDir": "lib", + "rootDir": "src", + "strict": false, // Relaxed for compatibility + "target": "es2017", + "sourceMap": false, + "allowJs": true, // Mixed JS/TS support + "skipLibCheck": true, + "esModuleInterop": true + }, + "include": ["src/**/*"] +} +``` + +### Root Configuration +```json +// tsconfig.json - Baseline configuration +{ + "compilerOptions": { + "strict": false, + "module": "commonjs", + "target": "es2017", + "declaration": true, + "outDir": "lib", + "rootDir": "src" + } +} +``` + +## Naming Conventions (Actual Usage) + +### Files +- **Primary pattern**: `kebab-case.ts` (e.g., `base-command.ts`, `config-handler.ts`) +- **Single-word modules**: `index.ts`, `types.ts` +- **Commands**: Follow OCLIF topic structure (`cm/auth/login.ts`, `cm/config/region.ts`) + +### Classes +```typescript +// ✅ GOOD - PascalCase for classes +export default class ConfigCommand extends Command { } +export class AuthService { } +export class ValidationError extends Error { } +``` + +### Functions and Methods +```typescript +// ✅ GOOD - camelCase for functions +export async function loadConfig(): Promise { } +async validateInput(input: string): Promise { } +createCommandContext(): CommandContext { } +``` + +### Constants +```typescript +// ✅ GOOD - SCREAMING_SNAKE_CASE for constants +const DEFAULT_REGION = 'us'; +const MAX_RETRIES = 3; +const API_BASE_URL = 'https://api.contentstack.io'; +``` + +### Interfaces and Types +```typescript +// ✅ GOOD - PascalCase for types +export interface CommandConfig { + region: string; + alias?: string; +} + +export type CommandResult = { + success: boolean; + message?: string; +}; +``` + +## Import/Export Patterns + +### ES Modules (Preferred) +```typescript +// ✅ GOOD - ES import/export syntax +import { Command } from '@oclif/core'; +import type { CommandConfig } from '../types'; +import { loadConfig } from '../utils'; + +export default class ConfigCommand extends Command { } +export { CommandConfig }; +``` + +### Default Exports +```typescript +// ✅ GOOD - Default export for commands and main classes +export default class ConfigCommand extends Command { } +``` + +### Named Exports +```typescript +// ✅ GOOD - Named exports for utilities and types +export async function delay(ms: number): Promise { } +export interface CommandOptions { } +export type ActionResult = 'success' | 'failure'; +``` + +## Type Definitions + +### Local Types +```typescript +// ✅ GOOD - Define types close to usage +export interface AuthOptions { + email: string; + password: string; + token?: string; +} + +export type ConfigResult = { + success: boolean; + config?: Record; +}; +``` + +### Type Organization +```typescript +// ✅ GOOD - Organize types in dedicated files +// src/types/index.ts +export interface CommandConfig { } +export interface AuthConfig { } +export type ConfigValue = string | number | boolean; +``` + +## Null Safety + +### Function Return Types +```typescript +// ✅ GOOD - Explicit return types +export async function getConfig(): Promise { + return await this.loadFromFile(); +} + +export function createDefaults(): CommandConfig { + return { + region: 'us', + timeout: 30000, + }; +} +``` + +### Null/Undefined Handling +```typescript +// ✅ GOOD - Handle null/undefined explicitly +function processConfig(config: CommandConfig | null): void { + if (!config) { + throw new Error('Configuration is required'); + } + // Process config safely +} +``` + +## Error Handling Types + +### Custom Error Classes +```typescript +// ✅ GOOD - Typed error classes +export class ValidationError extends Error { + constructor( + message: string, + public readonly code?: string + ) { + super(message); + this.name = 'ValidationError'; + } +} +``` + +### Error Union Types +```typescript +// ✅ GOOD - Model expected errors +type AuthResult = { + success: true; + data: T; +} | { + success: false; + error: string; +}; +``` + +## Strict Mode Adoption + +### Current Status +- Most packages use `strict: false` for compatibility +- Gradual migration path available +- Team working toward stricter TypeScript + +### Gradual Adoption +```typescript +// ✅ ACCEPTABLE - Comments for known issues +// TODO: Fix type issues in legacy code +const legacyData = unknownData as unknown; +``` + +## Package-Specific Patterns + +### Command Packages (auth, config) +- Extend `@oclif/core` Command +- Define command flags with `static flags` +- Use @oclif/core flag utilities +- Define command-specific types + +### Library Packages (command, utilities) +- No OCLIF dependencies +- Pure TypeScript interfaces +- Consumed by command packages +- Focus on type safety for exports + +### Main Package (contentstack) +- Aggregates command plugins +- May have common types +- Shared interfaces for plugin integration + +## Export Patterns + +### Package Exports (lib/index.js) +```typescript +// ✅ GOOD - Barrel exports for libraries +export { Command } from './command'; +export { loadConfig } from './config'; +export type { CommandConfig, AuthOptions } from './types'; +``` + +### Entry Points +- Libraries export from `lib/index.js` +- Commands export directly as default classes +- Type definitions included via `types` field in package.json diff --git a/.cursor/skills/SKILL.md b/.cursor/skills/SKILL.md new file mode 100644 index 000000000..db406d53e --- /dev/null +++ b/.cursor/skills/SKILL.md @@ -0,0 +1,32 @@ +--- +name: contentstack-cli-skills +description: Collection of project-specific skills for Contentstack CLI plugins monorepo development. Use when working with CLI commands, testing, framework utilities, or reviewing code changes. +--- + +# Contentstack CLI Skills + +Project-specific skills for the pnpm monorepo containing 12 CLI plugin packages. + +## Skills Overview + +| Skill | Purpose | Trigger | +|-------|---------|---------| +| **testing** | Testing patterns, TDD workflow, and test automation for CLI development | When writing tests or debugging test failures | +| **framework** | Core utilities, configuration, logging, and framework patterns | When working with utilities, config, or error handling | +| **contentstack-cli** | CLI commands, OCLIF patterns, authentication and configuration workflows | When implementing commands or integrating APIs | +| **code-review** | PR review guidelines and monorepo-aware checks | When reviewing code or pull requests | + +## Quick Links + +- **[Testing Skill](./testing/SKILL.md)** — TDD patterns, test structure, mocking strategies +- **[Framework Skill](./framework/SKILL.md)** — Utilities, configuration, logging, error handling +- **[Contentstack CLI Skill](./contentstack-cli/SKILL.md)** — Command development, API integration, auth/config patterns +- **[Code Review Skill](./code-review/SKILL.md)** — Review checklist with monorepo awareness + +## Repository Context + +- **Monorepo**: 12 pnpm workspace packages under `packages/` (all CLI plugins for content management) +- **Tech Stack**: TypeScript, OCLIF v4, Mocha+Chai, pnpm workspaces +- **Packages**: `@contentstack/cli-cm-*` scope (import, export, audit, bootstrap, branches, bulk-publish, clone, export-to-csv, import-setup, migration, seed, variants) +- **Dependencies**: All plugins depend on `@contentstack/cli-command` and `@contentstack/cli-utilities` +- **Build**: TypeScript → `lib/` directories, OCLIF manifest generation per plugin diff --git a/.cursor/skills/code-review/SKILL.md b/.cursor/skills/code-review/SKILL.md new file mode 100644 index 000000000..bc647259c --- /dev/null +++ b/.cursor/skills/code-review/SKILL.md @@ -0,0 +1,77 @@ +--- +name: code-review +description: Automated PR review checklist covering security, performance, architecture, and code quality. Use when reviewing pull requests, examining code changes, or performing code quality assessments. +--- + +# Code Review Skill + +## Quick Reference + +For comprehensive review guidelines, see: +- **[Code Review Checklist](./references/code-review-checklist.md)** - Complete PR review guidelines with severity levels and checklists + +## Review Process + +### Severity Levels +- 🔴 **Critical**: Must fix before merge (security, correctness, breaking changes) +- 🟡 **Important**: Should fix (performance, maintainability, best practices) +- 🟢 **Suggestion**: Consider improving (style, optimization, readability) + +### Quick Review Categories + +1. **Security** - No hardcoded secrets, input validation, secure error handling +2. **Correctness** - Logic validation, error scenarios, data integrity +3. **Architecture** - Code organization, design patterns, modularity +4. **Performance** - Efficiency, resource management, concurrency +5. **Testing** - Test coverage, quality tests, TDD compliance +6. **Conventions** - TypeScript standards, code style, documentation +7. **Monorepo** - Cross-package imports, workspace dependencies, manifest validity + +## Quick Checklist Template + +```markdown +## Security Review +- [ ] No hardcoded secrets or tokens +- [ ] Input validation present +- [ ] Error handling secure (no sensitive data in logs) + +## Correctness Review +- [ ] Logic correctly implemented +- [ ] Edge cases handled +- [ ] Error scenarios covered +- [ ] Async/await chains correct + +## Architecture Review +- [ ] Proper code organization +- [ ] Design patterns followed +- [ ] Good modularity +- [ ] No circular dependencies + +## Performance Review +- [ ] Efficient implementation +- [ ] No unnecessary API calls +- [ ] Memory leaks avoided +- [ ] Concurrency handled correctly + +## Testing Review +- [ ] Adequate test coverage (80%+) +- [ ] Quality tests (not just passing) +- [ ] TDD compliance +- [ ] Both success and failure paths tested + +## Code Conventions +- [ ] TypeScript strict mode +- [ ] Consistent naming conventions +- [ ] No unused imports or variables +- [ ] Documentation adequate + +## Monorepo Checks +- [ ] Cross-package imports use published names +- [ ] Workspace dependencies declared correctly +- [ ] OCLIF manifest updated if commands changed +- [ ] No breaking changes to exported APIs +``` + +## Usage + +Use the comprehensive checklist guide for detailed review guidelines, common issues, severity assessment, and best practices for code quality in the Contentstack CLI monorepo. diff --git a/.cursor/skills/code-review/references/code-review-checklist.md b/.cursor/skills/code-review/references/code-review-checklist.md new file mode 100644 index 000000000..682cc86a4 --- /dev/null +++ b/.cursor/skills/code-review/references/code-review-checklist.md @@ -0,0 +1,373 @@ +# Code Review Checklist + +Automated PR review guidelines covering security, performance, architecture, and code quality for the Contentstack CLI monorepo. + +## Review Process + +### Severity Levels +- **🔴 Critical** (must fix before merge): + - Security vulnerabilities + - Logic errors causing incorrect behavior + - Breaking API changes + - Hardcoded secrets or credentials + - Data loss scenarios + +- **🟡 Important** (should fix): + - Performance regressions + - Code maintainability issues + - Missing error handling + - Test coverage gaps + - Best practice violations + +- **🟢 Suggestion** (consider improving): + - Code readability improvements + - Minor optimizations + - Documentation enhancements + - Style inconsistencies + +## Security Review + +### Secrets and Credentials +- [ ] No hardcoded API keys, tokens, or passwords +- [ ] No secrets in environment variables exposed in logs +- [ ] No secrets in test data or fixtures +- [ ] Sensitive data not logged or exposed in error messages +- [ ] Config files don't contain real credentials + +### Input Validation +```typescript +// ✅ GOOD - Validate all user input +if (!region || typeof region !== 'string') { + throw new CLIError('Region must be a non-empty string'); +} + +if (!['us', 'eu', 'au'].includes(region)) { + throw new CLIError('Invalid region specified'); +} + +// ❌ BAD - No validation +const result = await client.setRegion(region); +``` + +### Error Handling +- [ ] No sensitive data in error messages +- [ ] Stack traces don't leak system information +- [ ] Error messages are user-friendly +- [ ] All errors properly caught and handled +- [ ] No raw error objects exposed to users + +### Authentication +- [ ] OAuth/token handling is secure +- [ ] No storing plaintext passwords +- [ ] Session tokens validated +- [ ] Auth state properly managed +- [ ] Rate limiting respected + +## Correctness Review + +### Logic Validation +- [ ] Business logic correctly implemented +- [ ] Algorithm is correct for the problem +- [ ] State transitions valid +- [ ] Data types used correctly +- [ ] Comparisons use correct operators (=== not ==) + +### Error Scenarios +- [ ] API failures handled (404, 429, 500, etc.) +- [ ] Network timeouts managed +- [ ] Empty/null responses handled +- [ ] Invalid input rejected +- [ ] Partial failures handled gracefully + +### Async/Await and Promises +```typescript +// ✅ GOOD - Proper async handling +async run(): Promise { + try { + const result = await this.fetchData(); + await this.processData(result); + } catch (error) { + handleAndLogError(error, this.contextDetails); + } +} + +// ❌ BAD - Missing await +async run(): Promise { + const result = this.fetchData(); // Missing await! + await this.processData(result); +} +``` + +### Data Integrity +- [ ] No race conditions +- [ ] State mutations atomic +- [ ] Data validation before mutations +- [ ] Rollback strategy for failures +- [ ] Concurrent operations safe + +## Architecture Review + +### Code Organization +- [ ] Classes/functions have single responsibility +- [ ] No circular dependencies +- [ ] Proper module structure +- [ ] Clear separation of concerns +- [ ] Commands delegate to services/utils + +### Design Patterns +```typescript +// ✅ GOOD - Service layer separation +export default class MyCommand extends BaseCommand { + async run(): Promise { + const service = new MyService(this.contextDetails); + const result = await service.execute(); + } +} + +// ❌ BAD - Logic in command +export default class MyCommand extends BaseCommand { + async run(): Promise { + const data = await client.fetch(); + for (const item of data) { + // Complex business logic here + } + } +} +``` + +### Modularity +- [ ] Services are reusable +- [ ] Utils are generic and testable +- [ ] Dependencies injected +- [ ] No tight coupling +- [ ] Easy to test in isolation + +### Type Safety +- [ ] TypeScript strict mode enabled +- [ ] No `any` types without justification +- [ ] Interfaces defined for contracts +- [ ] Generic types used appropriately +- [ ] Type narrowing correct + +## Performance Review + +### API Calls +- [ ] Rate limiting respected (10 req/sec for Contentstack) +- [ ] No unnecessary API calls in loops +- [ ] Pagination implemented for large datasets +- [ ] Caching used where appropriate +- [ ] Batch operations considered + +### Memory Management +- [ ] No memory leaks in event listeners +- [ ] Large arrays streamed not loaded fully +- [ ] Cleanup in try/finally blocks +- [ ] File handles properly closed +- [ ] Resources released after use + +### Concurrency +```typescript +// ✅ GOOD - Controlled concurrency +const results = await Promise.all( + items.map(item => processItem(item)) +); + +// ❌ BAD - Unbounded concurrency +for (const item of items) { + promises.push(processItem(item)); // No limit! +} +``` + +### Efficiency +- [ ] Algorithms are efficient for scale +- [ ] String concatenation uses proper methods +- [ ] Unnecessary computations avoided +- [ ] Data structures appropriate +- [ ] No repeated lookups without caching + +## Testing Review + +### Coverage +- [ ] 80%+ line coverage achieved +- [ ] 80%+ branch coverage +- [ ] Critical paths fully tested +- [ ] Error paths tested +- [ ] Edge cases included + +### Test Quality +```typescript +// ✅ GOOD - Quality test +it('should throw error when region is empty', () => { + expect(() => validateRegion('')) + .to.throw('Region is required'); +}); + +// ❌ BAD - Weak test +it('should validate region', () => { + validateRegion('us'); // No assertion! +}); +``` + +### Testing Patterns +- [ ] Descriptive test names +- [ ] Arrange-Act-Assert pattern +- [ ] One assertion per test (focus) +- [ ] Mocks properly isolated +- [ ] No test interdependencies + +### TDD Compliance +- [ ] Tests written before implementation +- [ ] All tests pass +- [ ] Code coverage requirements met +- [ ] Tests are maintainable +- [ ] Both success and failure paths covered + +## Code Conventions + +### TypeScript Standards +- [ ] `strict: true` in tsconfig +- [ ] No `any` types (use `unknown` if needed) +- [ ] Proper null/undefined handling +- [ ] Type annotations on public APIs +- [ ] Generics used appropriately + +### Naming Conventions +- [ ] Classes: PascalCase (`MyClass`) +- [ ] Functions: camelCase (`myFunction`) +- [ ] Constants: UPPER_SNAKE_CASE (`MY_CONST`) +- [ ] Booleans start with verb (`isActive`, `hasData`) +- [ ] Descriptive names (not `x`, `temp`, `data`) + +### Code Style +- [ ] No unused imports +- [ ] No unused variables +- [ ] Proper indentation (consistent spacing) +- [ ] Line length reasonable (<100 chars) +- [ ] Imports organized (group by type) + +### Documentation +- [ ] Complex logic documented +- [ ] Public APIs have JSDoc comments +- [ ] Non-obvious decisions explained +- [ ] Examples provided where helpful +- [ ] README updated if needed + +## Monorepo-Specific Checks + +### Cross-Package Imports +```typescript +// ✅ GOOD - Use published package names +import { configHandler } from '@contentstack/cli-utilities'; +import { BaseCommand } from '@contentstack/cli-command'; + +// ❌ BAD - Relative paths across packages +import { configHandler } from '../../../contentstack-utilities/src'; +``` + +### Workspace Dependencies +- [ ] Dependencies declared in correct `package.json` +- [ ] Versions consistent across packages +- [ ] No circular dependencies between packages +- [ ] Shared deps in root if used by multiple packages +- [ ] No installing globally when local version exists + +### OCLIF Configuration +- [ ] Command file paths correct in `package.json` +- [ ] OCLIF manifest regenerated (`pnpm build && pnpm oclif manifest`) +- [ ] New commands registered in plugin list if needed +- [ ] Topic separators consistent (`:`) +- [ ] Command names follow pattern + +### Build and Publishing +- [ ] TypeScript compiles without errors +- [ ] Build output in `lib/` directory +- [ ] No build artifacts committed +- [ ] ESLint passes without warnings +- [ ] Tests pass in CI environment + +## Common Issues to Look For + +### Security +- [ ] Config with default passwords +- [ ] API keys in client-side code +- [ ] SQL injection (N/A here, but parameterization pattern) +- [ ] XSS in CLI output (escape HTML if needed) + +### Performance +- [ ] API calls in loops +- [ ] Synchronous file I/O on large files +- [ ] Memory not released properly +- [ ] Rate limiting ignored + +### Logic +- [ ] Off-by-one errors in loops +- [ ] Wrong comparison operators +- [ ] Async/await chains broken +- [ ] Null/undefined not handled + +### Testing +- [ ] Tests pass locally but fail in CI +- [ ] Mocks not properly restored +- [ ] Race conditions in tests +- [ ] Hardcoded timeouts + +## Review Checklist Template + +```markdown +## Security +- [ ] No hardcoded secrets +- [ ] Input validation present +- [ ] Error handling secure + +## Correctness +- [ ] Logic is correct +- [ ] Edge cases handled +- [ ] Error scenarios covered + +## Architecture +- [ ] Good code organization +- [ ] Design patterns followed +- [ ] Modularity intact + +## Performance +- [ ] Efficient implementation +- [ ] Rate limits respected +- [ ] Memory managed properly + +## Testing +- [ ] Adequate coverage +- [ ] Quality tests +- [ ] Both paths tested + +## Conventions +- [ ] TypeScript standards met +- [ ] Code style consistent +- [ ] Documentation adequate + +## Monorepo +- [ ] Package imports correct +- [ ] Dependencies declared properly +- [ ] Manifest/build updated +- [ ] No breaking changes +``` + +## Approval Criteria + +**APPROVE when:** +- ✅ All 🔴 Critical items addressed +- ✅ Most 🟡 Important items addressed (document exceptions) +- ✅ Code follows team conventions +- ✅ Tests pass and coverage sufficient +- ✅ Monorepo integrity maintained + +**REQUEST CHANGES when:** +- ❌ Any 🔴 Critical issues present +- ❌ Multiple 🟡 Important issues unaddressed +- ❌ Test coverage below 80% +- ❌ Architecture concerns not resolved +- ❌ Breaking changes not documented + +**COMMENT for:** +- 💬 🟢 Suggestions (non-blocking) +- 💬 Questions about implementation +- 💬 Appreciation for good patterns diff --git a/.cursor/skills/contentstack-cli/SKILL.md b/.cursor/skills/contentstack-cli/SKILL.md new file mode 100644 index 000000000..df6691042 --- /dev/null +++ b/.cursor/skills/contentstack-cli/SKILL.md @@ -0,0 +1,178 @@ +--- +name: contentstack-cli +description: Contentstack CLI development patterns, OCLIF commands, API integration, and authentication/configuration workflows. Use when working with Contentstack CLI plugins, OCLIF commands, CLI commands, or Contentstack API integration. +--- + +# Contentstack CLI Development + +## Quick Reference + +For comprehensive patterns, see: +- **[Contentstack Patterns](./references/contentstack-patterns.md)** - Complete CLI commands, API integration, and configuration patterns +- **[Framework Patterns](../framework/references/framework-patterns.md)** - Utilities, configuration, and error handling + +## Key Patterns Summary + +### OCLIF Command Structure +- Extend plugin-specific `BaseCommand` or `Command` from `@contentstack/cli-command` +- Validate flags early: `if (!flags['stack-api-key']) this.error('Stack API key is required')` +- Delegate to services/modules: commands handle CLI, services handle business logic +- Show progress: `cliux.success('✅ Operation completed')` +- Include command examples: `static examples = ['$ csdx cm:stacks:import -k -d ./data', '$ csdx cm:stacks:export -k ']` + +### Command Topics +- CM topic commands: `cm:stacks:import`, `cm:stacks:export`, `cm:stacks:audit`, `cm:stacks:clone`, etc. +- File pattern: `src/commands/cm/stacks/import.ts` → command `cm:stacks:import` +- Plugin structure: Each package defines commands in `oclif.commands` pointing to `./lib/commands` + +### Flag Patterns +```typescript +static flags: FlagInput = { + username: flags.string({ + char: 'u', + description: 'Email address', + required: false + }), + oauth: flags.boolean({ + description: 'Enable SSO', + default: false, + exclusive: ['username', 'password'] + }) +}; +``` + +### Logging and Error Handling +- Use structured logging: `log.debug('Message', { context: 'data' })` +- Include contextDetails: `handleAndLogError(error, { ...this.contextDetails, module: 'auth-login' })` +- User feedback: `cliux.success()`, `cliux.error()`, `throw new CLIError()` + +### I18N Messages +- Store user-facing strings in `messages/*.json` files +- Load with `messageHandler` from utilities +- Example: `messages/en.json` for English strings + +## Command Base Class Pattern + +Each plugin defines its own `BaseCommand` extending `@contentstack/cli-command`: + +```typescript +export abstract class BaseCommand extends Command { + protected sharedConfig = { basePath: process.cwd() }; + + static baseFlags: FlagInput = { + config: Flags.string({ + char: 'c', + description: 'Path to config file', + }), + 'data-dir': Flags.string({ + char: 'd', + description: 'Data directory path', + }), + }; + + async init(): Promise { + await super.init(); + const { args, flags } = await this.parse({ + flags: this.ctor.flags, + args: this.ctor.args, + }); + this.args = args; + this.flags = flags; + } +} +``` + +Specialized base commands extend this for domain-specific concerns (e.g., `AuditBaseCommand` for audit operations). + +## Plugin Development Patterns + +### Import Plugin Example +```typescript +// packages/contentstack-import/src/commands/cm/stacks/import.ts +export default class ImportCommand extends BaseCommand { + static id = 'cm:stacks:import'; + static description = 'Import content into a stack'; + + static flags: FlagInput = { + 'stack-api-key': Flags.string({ + char: 'k', + description: 'Stack API key', + required: true, + }), + 'data-dir': Flags.string({ + char: 'd', + description: 'Directory with import data', + required: true, + }), + }; + + async run(): Promise { + const { flags } = this; + const importService = new ImportService(flags); + await importService.import(); + cliux.success('✅ Import completed'); + } +} +``` + +### Service Layer Pattern +Services encapsulate business logic separate from CLI concerns: + +```typescript +export class ImportService { + async import(): Promise { + await this.validateInput(); + await this.loadData(); + await this.importContent(); + } +} +``` + +### Module Pattern +Complex domains split work across modules: + +```typescript +export class Entries { + async import(entries: any[]): Promise { + for (const entry of entries) { + await this.importEntry(entry); + } + } +} +``` + +## API Integration + +### Management SDK Client +```typescript +import { managementSDKClient } from '@contentstack/cli-utilities'; + +const client = await managementSDKClient({ + host: this.cmaHost, + skipTokenValidity: true +}); + +const stack = client.stack({ api_key: stackApiKey }); +const entries = await stack.entry().query().find(); +``` + +### Error Handling for API Calls +```typescript +try { + const result = await this.client.stack().entry().fetch(); +} catch (error) { + if (error.status === 401) { + throw new CLIError('Authentication failed. Please login again.'); + } else if (error.status === 404) { + throw new CLIError('Entry not found.'); + } + handleAndLogError(error, { + module: 'entry-fetch', + entryId: entryUid + }); +} +``` + +## Usage + +Reference the comprehensive patterns guide above for detailed implementations, examples, and best practices for CLI command development, authentication flows, configuration management, and API integration. diff --git a/.cursor/skills/contentstack-cli/references/contentstack-patterns.md b/.cursor/skills/contentstack-cli/references/contentstack-patterns.md new file mode 100644 index 000000000..2ee74721e --- /dev/null +++ b/.cursor/skills/contentstack-cli/references/contentstack-patterns.md @@ -0,0 +1,476 @@ +# Contentstack CLI Patterns + +Contentstack CLI plugin development patterns, OCLIF commands, API integration, and workflows. + +## OCLIF Command Structure + +### Plugin Base Command Pattern +```typescript +import { BaseCommand } from '../../base-command'; +import { FlagInput, Flags } from '@contentstack/cli-utilities'; +import { cliux, handleAndLogError } from '@contentstack/cli-utilities'; + +export default class ImportCommand extends BaseCommand { + static id = 'cm:stacks:import'; + static description = 'Import content into a stack'; + + static flags: FlagInput = { + 'stack-api-key': Flags.string({ + char: 'k', + description: 'Stack API key', + required: true, + }), + 'data-dir': Flags.string({ + char: 'd', + description: 'Directory with import data', + required: true, + }), + verbose: Flags.boolean({ + char: 'v', + description: 'Show verbose output', + default: false + }) + }; + + static examples = [ + '$ csdx cm:stacks:import -k -d ./data', + '$ csdx cm:stacks:import -k -d ./data --verbose', + ]; + + async run(): Promise { + try { + const { flags: parsedFlags } = await this.parse(ImportCommand); + + // Validate flags + if (!parsedFlags['stack-api-key']) { + this.error('Stack API key is required'); + } + + // Delegate to service + cliux.print('Starting import...', { color: 'blue' }); + const importService = new ImportService(parsedFlags); + const result = await importService.import(); + + cliux.success('✅ Import completed successfully'); + } catch (error) { + handleAndLogError(error, { + module: 'import-command', + stackApiKey: this.flags['stack-api-key'] + }); + } + } +} +``` + +### Command Topics and Naming +Commands are organized by topic hierarchy under `cm`: +- `src/commands/cm/stacks/import.ts` → command `cm:stacks:import` +- `src/commands/cm/stacks/export.ts` → command `cm:stacks:export` +- `src/commands/cm/stacks/audit/index.ts` → command `cm:stacks:audit` +- `src/commands/cm/stacks/audit/fix.ts` → command `cm:stacks:audit:fix` + +### Flag Validation Patterns + +#### Early Validation +```typescript +async run(): Promise { + const { flags } = await this.parse(MyCommand); + + // Validate required flags + if (!flags.region) { + this.error('--region is required'); + } + + // Validate flag values + const validRegions = ['us', 'eu', 'au']; + if (!validRegions.includes(flags.region)) { + this.error(`Region must be one of: ${validRegions.join(', ')}`); + } +} +``` + +#### Exclusive Flags +```typescript +static flags: FlagInput = { + username: flags.string({ + char: 'u', + exclusive: ['oauth'] // Cannot use with oauth flag + }), + oauth: flags.boolean({ + exclusive: ['username', 'password'] + }) +}; +``` + +#### Dependent Flags +```typescript +static flags: FlagInput = { + cma: flags.string({ + dependsOn: ['cda', 'name'] + }), + cda: flags.string({ + dependsOn: ['cma', 'name'] + }) +}; +``` + +## Authentication Commands + +### Login Command +```typescript +export default class LoginCommand extends BaseCommand { + static description = 'User sessions login'; + static aliases = ['login']; + + static flags: FlagInput = { + username: flags.string({ + char: 'u', + description: 'Email address of your Contentstack account', + exclusive: ['oauth'] + }), + password: flags.string({ + char: 'p', + description: 'Password of your Contentstack account', + exclusive: ['oauth'] + }), + oauth: flags.boolean({ + description: 'Enable single sign-on (SSO)', + default: false, + exclusive: ['username', 'password'] + }) + }; + + async run(): Promise { + try { + const managementAPIClient = await managementSDKClient({ + host: this.cmaHost, + skipTokenValidity: true + }); + + const { flags: loginFlags } = await this.parse(LoginCommand); + authHandler.client = managementAPIClient; + + if (loginFlags.oauth) { + log.debug('Starting OAuth flow', this.contextDetails); + oauthHandler.host = this.cmaHost; + await oauthHandler.oauth(); + } else { + const username = loginFlags.username || await interactive.askUsername(); + const password = loginFlags.password || await interactive.askPassword(); + await authHandler.login(username, password); + } + + cliux.success('✅ Authenticated successfully'); + } catch (error) { + handleAndLogError(error, this.contextDetails); + } + } +} +``` + +### Logout Command +```typescript +export default class LogoutCommand extends BaseCommand { + static description = 'Logout from Contentstack'; + + async run(): Promise { + try { + await authHandler.setConfigData('logout'); + cliux.success('✅ Logged out successfully'); + } catch (error) { + handleAndLogError(error, this.contextDetails); + } + } +} +``` + +### Token Management +```typescript +// Add token +export default class TokenAddCommand extends BaseCommand { + static description = 'Add authentication token'; + + static flags: FlagInput = { + email: flags.string({ + char: 'e', + description: 'Email address', + required: true + }), + label: flags.string({ + char: 'l', + description: 'Token label', + required: false + }) + }; + + async run(): Promise { + const { flags } = await this.parse(TokenAddCommand); + // Add token logic + cliux.success('✅ Token added successfully'); + } +} +``` + +## Configuration Commands + +### Config Get Command +```typescript +export default class ConfigGetCommand extends BaseCommand { + static description = 'Get CLI configuration values'; + + async run(): Promise { + try { + const region = configHandler.get('region'); + cliux.print(`Region: ${region}`); + } catch (error) { + handleAndLogError(error, { ...this.contextDetails, module: 'config-get' }); + } + } +} +``` + +### Config Set Command +```typescript +export default class RegionSetCommand extends BaseCommand { + static description = 'Set region for CLI'; + + static args = { + region: args.string({ description: 'Region name (AWS-NA, AWS-EU, etc.)' }) + }; + + static examples = [ + '$ csdx config:set:region', + '$ csdx config:set:region AWS-NA', + '$ csdx config:set:region --cma --cda --ui-host --name "Custom"' + ]; + + async run(): Promise { + try { + const { args, flags } = await this.parse(RegionSetCommand); + + let selectedRegion = args.region; + if (!selectedRegion) { + selectedRegion = await interactive.askRegions(); + } + + const regionDetails = regionHandler.setRegion(selectedRegion); + await authHandler.setConfigData('logout'); // Reset auth on region change + + cliux.success(`✅ Region set to ${regionDetails.name}`); + cliux.print(`CMA host: ${regionDetails.cma}`); + cliux.print(`CDA host: ${regionDetails.cda}`); + } catch (error) { + handleAndLogError(error, { ...this.contextDetails, module: 'config-set-region' }); + } + } +} +``` + +### Config Remove Command +```typescript +export default class ProxyRemoveCommand extends BaseCommand { + static description = 'Remove proxy configuration'; + + async run(): Promise { + try { + configHandler.remove('proxy'); + cliux.success('✅ Proxy configuration removed'); + } catch (error) { + handleAndLogError(error, this.contextDetails); + } + } +} +``` + +## API Integration + +### Using Management SDK Client +```typescript +import { managementSDKClient } from '@contentstack/cli-utilities'; + +// Initialize client +const managementClient = await managementSDKClient({ + host: this.cmaHost, + skipTokenValidity: false +}); + +// Get stack +const stack = managementClient.stack({ api_key: stackApiKey }); + +// Fetch entry +const entry = await stack.entry(entryUid).fetch(); + +// Query entries +const entries = await stack + .entry() + .query({ query: { title: 'My Entry' } }) + .find(); + +// Update entry +const updatedEntry = await stack.entry(entryUid).update({ ...entry }); +``` + +### Error Handling for API Calls +```typescript +try { + const stack = client.stack({ api_key: apiKey }); + const entry = await stack.entry(uid).fetch(); +} catch (error: any) { + if (error.status === 401) { + throw new CLIError('Authentication failed. Please login again.'); + } else if (error.status === 404) { + throw new CLIError(`Entry with UID "${uid}" not found.`); + } else if (error.status === 429) { + throw new CLIError('Rate limited. Please try again later.'); + } + + handleAndLogError(error, { + module: 'entry-service', + entryUid: uid, + stackApiKey: apiKey + }); +} +``` + +## User Input and Interaction + +### Interactive Prompts +```typescript +import { interactive } from '../../utils'; + +// Ask for region selection +const region = await interactive.askRegions(); + +// Ask for username +const username = await interactive.askUsername(); + +// Ask for password +const password = await interactive.askPassword(); + +// Ask custom question +const customResponse = await cliux.prompt('Enter your choice:'); +``` + +### User Feedback +```typescript +// Success message +cliux.success('✅ Operation completed'); + +// Error message +cliux.error('❌ Operation failed'); + +// Info message +cliux.print('Processing...', { color: 'blue' }); + +// Show data +cliux.table([ + { name: 'Alice', region: 'us', status: 'active' }, + { name: 'Bob', region: 'eu', status: 'inactive' } +]); +``` + +## Logging Patterns + +### Structured Logging +```typescript +log.debug('LoginCommand started', this.contextDetails); +log.debug('Management API client initialized', this.contextDetails); +log.debug('Token parsed', { + ...this.contextDetails, + flags: loginFlags +}); + +try { + await this.performOperation(); +} catch (error) { + log.debug('Operation failed', { + ...this.contextDetails, + error: error.message, + errorCode: error.code + }); +} +``` + +### Context Details +The `BaseCommand` provides `contextDetails` with: +```typescript +contextDetails = { + command: 'auth:login', + userId: '12345', + email: 'user@example.com', + sessionId: 'session-123' +}; +``` + +## Messages (i18n) + +### Store User Strings +```json +// messages/en.json +{ + "auth": { + "login": { + "success": "Authentication successful", + "failed": "Authentication failed" + }, + "logout": { + "success": "Logged out successfully" + } + }, + "config": { + "region": { + "set": "Region set to {{name}}" + } + } +} +``` + +### Use Message Handler +```typescript +import { messageHandler } from '@contentstack/cli-utilities'; + +const message = messageHandler.get(['auth', 'login', 'success']); +cliux.success(message); +``` + +## Best Practices + +### Command Organization +```typescript +export default class MyCommand extends BaseCommand { + // 1. Static properties + static description = '...'; + static examples = [...]; + static flags = {...}; + + // 2. Instance variables + private someHelper: Helper; + + // 3. run method + async run(): Promise { + try { + const { flags } = await this.parse(MyCommand); + await this.execute(flags); + } catch (error) { + handleAndLogError(error, this.contextDetails); + } + } + + // 4. Private helper methods + private async execute(flags: any): Promise {} + private validate(input: any): void {} +} +``` + +### Error Messages +- Be specific about what went wrong +- Provide actionable feedback +- Example: "Region must be AWS-NA, AWS-EU, or AWS-AU" +- Not: "Invalid region" + +### Progress Indication +```typescript +cliux.print('🔄 Processing...', { color: 'blue' }); +// ... operation ... +cliux.success('✅ Completed successfully'); +``` diff --git a/.cursor/skills/framework/SKILL.md b/.cursor/skills/framework/SKILL.md new file mode 100644 index 000000000..80be284d9 --- /dev/null +++ b/.cursor/skills/framework/SKILL.md @@ -0,0 +1,142 @@ +--- +name: framework +description: Core utilities, configuration, logging, and framework patterns for CLI development. Use when working with utilities, configuration management, error handling, or core framework components. +--- + +# Framework Patterns + +## Quick Reference + +For comprehensive framework guidance, see: +- **[Framework Patterns](./references/framework-patterns.md)** - Complete utilities, configuration, logging, and framework patterns + +## Core Utilities from @contentstack/cli-utilities + +### Configuration Management +```typescript +import { configHandler } from '@contentstack/cli-utilities'; + +// Get config values +const region = configHandler.get('region'); +const email = configHandler.get('email'); +const authToken = configHandler.get('authenticationMethod'); + +// Set config values +configHandler.set('region', 'us'); +``` + +### Logging Framework +```typescript +import { log } from '@contentstack/cli-utilities'; + +// Use structured logging +log.debug('Debug message', { context: 'data' }); +log.info('Information message', { userId: '123' }); +log.warn('Warning message'); +log.error('Error message', { errorCode: 'ERR_001' }); +``` + +### Error Handling +```typescript +import { handleAndLogError, CLIError } from '@contentstack/cli-utilities'; + +try { + await operation(); +} catch (error) { + handleAndLogError(error, { + module: 'my-command', + command: 'cm:auth:login' + }); +} + +// Or throw CLI errors +throw new CLIError('User-friendly error message'); +``` + +### CLI UX / User Output +```typescript +import { cliux } from '@contentstack/cli-utilities'; + +// Success message +cliux.success('Operation completed successfully'); + +// Error message +cliux.error('Something went wrong'); + +// Print message with color +cliux.print('Processing...', { color: 'blue' }); + +// Prompt user for input +const response = await cliux.prompt('Enter region:'); + +// Show table +cliux.table([ + { name: 'Alice', region: 'us' }, + { name: 'Bob', region: 'eu' } +]); +``` + +### HTTP Client +```typescript +import { httpClient } from '@contentstack/cli-utilities'; + +// Make HTTP requests with built-in error handling +const response = await httpClient.request({ + url: 'https://api.contentstack.io/v3/stacks', + method: 'GET', + headers: { 'Authorization': `Bearer ${token}` } +}); +``` + +## Command Base Class + +```typescript +import { Command } from '@contentstack/cli-command'; + +export default class MyCommand extends Command { + static description = 'My command description'; + + static flags = { + region: flags.string({ + char: 'r', + description: 'Set region' + }) + }; + + async run(): Promise { + const { flags } = await this.parse(MyCommand); + // Command logic here + } +} +``` + +## Error Handling Patterns + +### With Context +```typescript +try { + const result = await this.client.stack().entry().fetch(); +} catch (error) { + handleAndLogError(error, { + module: 'auth-service', + command: 'cm:auth:login', + userId: this.contextDetails.userId, + email: this.contextDetails.email + }); +} +``` + +### Custom Errors +```typescript +if (response.status === 401) { + throw new CLIError('Authentication failed. Please login again.'); +} + +if (response.status === 429) { + throw new CLIError('Rate limited. Please try again later.'); +} +``` + +## Usage + +Reference the comprehensive patterns guide above for detailed implementations of configuration, logging, error handling, utilities, and dependency injection patterns. diff --git a/.cursor/skills/framework/references/framework-patterns.md b/.cursor/skills/framework/references/framework-patterns.md new file mode 100644 index 000000000..8c1d4fc19 --- /dev/null +++ b/.cursor/skills/framework/references/framework-patterns.md @@ -0,0 +1,399 @@ +# Framework Patterns + +Core utilities, configuration, logging, and framework patterns for Contentstack CLI development. + +## Configuration Management + +The `@contentstack/cli-utilities` package exports `configHandler` for centralized configuration access. + +### Using configHandler +```typescript +import { configHandler } from '@contentstack/cli-utilities'; + +// Get config values (no arguments returns all config) +const allConfig = configHandler.get(); + +// Get specific config +const region = configHandler.get('region'); +const email = configHandler.get('email'); +const authToken = configHandler.get('authenticationMethod'); +const userUid = configHandler.get('userUid'); +const oauthOrgUid = configHandler.get('oauthOrgUid'); + +// Set config +configHandler.set('region', 'us'); +configHandler.set('email', 'user@example.com'); +``` + +### Config Keys +- `region` - Current region setting (us, eu, etc.) +- `email` - User email address +- `authenticationMethod` - Auth method used +- `userUid` - User unique identifier +- `oauthOrgUid` - OAuth organization UID +- `authenticationMethod` - Authentication method + +## Logging Framework + +The `@contentstack/cli-utilities` exports a winston-based `log` (v2Logger) for structured logging. + +### Structured Logging +```typescript +import { log } from '@contentstack/cli-utilities'; + +// Debug level +log.debug('Starting operation', { + command: 'cm:auth:login', + timestamp: new Date().toISOString() +}); + +// Info level +log.info('Operation completed', { + itemsProcessed: 100, + duration: 5000 +}); + +// Warn level +log.warn('Deprecated flag used', { + flag: '--old-flag', + alternative: '--new-flag' +}); + +// Error level +log.error('Operation failed', { + errorCode: 'ERR_AUTH_001', + message: 'Invalid credentials' +}); +``` + +### Log Context Creation +```typescript +import { createLogContext } from '@contentstack/cli-utilities'; + +// Create context for logging +const logContext = createLogContext( + command, // command name + module, // module name + authMethod // authentication method +); + +// Use in command +const contextDetails = { + ...logContext, + userId: configHandler.get('userUid'), + email: configHandler.get('email') +}; +``` + +## Error Handling Framework + +The utilities provide error handling functions and error classes. + +### handleAndLogError Function +```typescript +import { handleAndLogError } from '@contentstack/cli-utilities'; + +try { + await risky operation(); +} catch (error) { + handleAndLogError(error, { + module: 'config-set-region', + command: 'cm:config:set:region', + flags: { region: 'eu' } + }); +} +``` + +### CLIError Class +```typescript +import { CLIError } from '@contentstack/cli-utilities'; + +// Throw user-friendly errors +if (!region) { + throw new CLIError('Region is required'); +} + +if (invalidEnvironments.length > 0) { + throw new CLIError(`Invalid environments: ${invalidEnvironments.join(', ')}`); +} +``` + +### Error Context +```typescript +// Include context for debugging +try { + const response = await this.client.fetch(); +} catch (error) { + handleAndLogError(error, { + module: 'asset-service', + command: this.id, + context: { + userId: this.contextDetails.userId, + email: this.contextDetails.email, + region: configHandler.get('region') + } + }); +} +``` + +## CLI UX / User Output + +The `cliux` utility provides user-friendly output functions. + +### Success Messages +```typescript +import { cliux } from '@contentstack/cli-utilities'; + +// Simple success +cliux.success('Configuration updated successfully'); + +// Success with details +cliux.success('Region set to us'); +cliux.success('CMA host: https://api.contentstack.io'); +cliux.success('CDA host: https://cdn.contentstack.io'); +``` + +### Error Messages +```typescript +cliux.error('Authentication failed'); +cliux.error('Invalid region: custom'); +cliux.error('Environment not found or inaccessible'); +``` + +### Print with Color +```typescript +// Blue for info +cliux.print('Processing items...', { color: 'blue' }); + +// Show progress +cliux.print(`Progress: ${completed}/${total} items`, { color: 'blue' }); + +// Status messages +cliux.print('✅ Operation completed', { color: 'green' }); +cliux.print('🔄 Syncing configuration...', { color: 'blue' }); +``` + +### User Input +```typescript +// Prompt for string input +const region = await cliux.prompt('Enter region:'); + +// Prompt with choices (using inquirer) +const response = await cliux.prompt('Select action:', { + choices: ['publish', 'unpublish', 'delete'] +}); +``` + +### Display Tables +```typescript +// Display data in table format +cliux.table([ + { name: 'Alice', region: 'us', status: 'active' }, + { name: 'Bob', region: 'eu', status: 'inactive' } +]); + +// With custom columns +const data = [ + { uid: 'entry-1', title: 'Entry 1', locale: 'en' }, + { uid: 'entry-2', title: 'Entry 2', locale: 'en' } +]; +cliux.table(data); +``` + +## HTTP Client + +The `httpClient` provides HTTP request functionality with error handling. + +### Basic Requests +```typescript +import { httpClient } from '@contentstack/cli-utilities'; + +// GET request +const response = await httpClient.request({ + url: 'https://api.contentstack.io/v3/stacks', + method: 'GET', + headers: { 'Authorization': `Bearer ${token}` } +}); + +// POST request +const postResponse = await httpClient.request({ + url: 'https://api.contentstack.io/v3/stacks', + method: 'POST', + headers: { + 'Authorization': `Bearer ${token}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ name: 'My Stack' }) +}); +``` + +### Error Handling +```typescript +try { + const response = await httpClient.request({ + url: endpoint, + method: 'GET', + headers: getAuthHeaders() + }); +} catch (error: any) { + if (error.status === 429) { + cliux.error('Rate limited. Please try again later.'); + } else if (error.status === 401) { + cliux.error('Authentication failed. Please login again.'); + } else { + handleAndLogError(error, { module: 'http-client' }); + } +} +``` + +## Command Base Class + +Commands should extend `Command` from `@contentstack/cli-command`. + +### Basic Command Structure +```typescript +import { Command } from '@contentstack/cli-command'; +import { FlagInput, args } from '@contentstack/cli-utilities'; + +export default class MyCommand extends Command { + static description = 'Clear description of what this command does'; + + static flags: FlagInput = { + region: flags.string({ + char: 'r', + description: 'Target region (us/eu)', + required: false + }), + verbose: flags.boolean({ + char: 'v', + description: 'Show verbose output', + default: false + }) + }; + + static args = { + name: args.string({ description: 'Name of item', required: false }) + }; + + static examples = [ + '$ csdx my:command', + '$ csdx my:command --region eu' + ]; + + async run(): Promise { + try { + const { args, flags } = await this.parse(MyCommand); + // Validate flags + if (!flags.region) { + this.error('--region is required'); + } + + // Implementation + this.log('Starting operation...'); + // ... perform operation ... + cliux.success('Operation completed'); + } catch (error) { + handleAndLogError(error, { module: 'my-command' }); + } + } +} +``` + +### Command Lifecycle +```typescript +export abstract class BaseCommand extends Command { + public async init(): Promise { + await super.init(); + // Initialize context, config, logging + this.contextDetails = createLogContext( + this.context?.info?.command, + '', + configHandler.get('authenticationMethod') + ); + } + + protected async catch(err: Error & { exitCode?: number }): Promise { + // Custom error handling + return super.catch(err); + } + + protected async finally(_: Error | undefined): Promise { + // Cleanup after command + return super.finally(_); + } +} +``` + +## Authentication Patterns + +### Auth Handler +```typescript +import { authHandler } from '@contentstack/cli-utilities'; + +// Check if authenticated +const isAuthenticated = !!configHandler.get('authenticationMethod'); + +// Get auth token +const token = await authHandler.getToken(); + +// Set config data (e.g., during logout) +await authHandler.setConfigData('logout'); +``` + +### Checking Authentication in Commands +```typescript +if (!configHandler.get('authenticationMethod')) { + throw new CLIError('Authentication required. Please login first.'); +} +``` + +## Common Patterns + +### Error and Success Pattern +```typescript +async run(): Promise { + try { + this.log('Starting operation...'); + const result = await this.performOperation(); + cliux.success(`✅ Success: ${result}`); + } catch (error) { + handleAndLogError(error, { + module: 'my-command', + command: this.id + }); + } +} +``` + +### Progress Reporting Pattern +```typescript +cliux.print('Processing items...', { color: 'blue' }); +let count = 0; +for (const item of items) { + await this.processItem(item); + count++; + cliux.print(`Progress: ${count}/${items.length} items`, { color: 'blue' }); +} +cliux.success(`✅ Processed ${count} items`); +``` + +### Dependency Injection Pattern +```typescript +export class MyService { + constructor( + private configHandler: any, + private logger: any, + private httpClient: any + ) {} + + async execute(): Promise { + this.logger.debug('Starting service'); + const config = this.configHandler.get('region'); + // Use injected dependencies + } +} + +// In command +const service = new MyService(configHandler, log, httpClient); +await service.execute(); +``` diff --git a/.cursor/skills/testing/SKILL.md b/.cursor/skills/testing/SKILL.md new file mode 100644 index 000000000..d53591924 --- /dev/null +++ b/.cursor/skills/testing/SKILL.md @@ -0,0 +1,200 @@ +--- +name: testing +description: Testing patterns, TDD workflow, and test automation for CLI development. Use when writing tests, implementing TDD, setting up test coverage, or debugging test failures. +--- + +# Testing Patterns + +## Quick Reference + +For comprehensive testing guidance, see: +- **[Testing Patterns](./references/testing-patterns.md)** - Complete testing best practices and TDD workflow +- See also `.cursor/rules/testing.mdc` for workspace-wide testing standards + +## TDD Workflow Summary + +**Simple RED-GREEN-REFACTOR:** +1. **RED** → Write failing test +2. **GREEN** → Make it pass with minimal code +3. **REFACTOR** → Improve code quality while keeping tests green + +## Key Testing Rules + +- **80% minimum coverage** (lines, branches, functions) +- **Class-based mocking** (no external libraries; extend and override methods) +- **Never make real API calls** in tests +- **Mock at service boundaries**, not implementation details +- **Test both success and failure paths** +- **Use descriptive test names**: "should [behavior] when [condition]" + +## Quick Test Template + +```typescript +describe('[ServiceName]', () => { + let service: [ServiceName]; + + beforeEach(() => { + service = new [ServiceName](); + }); + + afterEach(() => { + // Clean up any resources + }); + + it('should [expected behavior] when [condition]', async () => { + // Arrange + const input = { /* test data */ }; + + // Act + const result = await service.method(input); + + // Assert + expect(result).to.deep.equal(expectedOutput); + }); + + it('should throw error when [error condition]', async () => { + // Arrange & Act & Assert + await expect(service.failingMethod()) + .to.be.rejectedWith('Expected error message'); + }); +}); +``` + +## Common Mock Patterns + +### Class-Based Mocking +```typescript +// Mock a service by extending it +class MockContentstackClient extends ContentstackClient { + async fetch() { + return mockData; + } +} + +it('should use mocked client', async () => { + const mockClient = new MockContentstackClient(config); + const result = await mockClient.fetch(); + expect(result).to.deep.equal(mockData); +}); +``` + +### Constructor Injection +```typescript +class RateLimiter { + async execute(operation: () => Promise): Promise { + return operation(); + } +} + +class MyService { + constructor(private rateLimiter: RateLimiter) {} + + async doWork() { + return this.rateLimiter.execute(() => this.performWork()); + } +} + +it('should rate limit operations', () => { + const mockLimiter = { execute: () => Promise.resolve('result') }; + const service = new MyService(mockLimiter as any); + // test service behavior +}); +``` + +## Running Tests + +### Run all tests in workspace +```bash +pnpm test +``` + +### Run tests for specific package +```bash +pnpm --filter @contentstack/cli-auth test +pnpm --filter @contentstack/cli-config test +``` + +### Run tests with coverage +```bash +pnpm test:coverage +``` + +### Run tests in watch mode +```bash +pnpm test:watch +``` + +### Run specific test file +```bash +pnpm test -- test/unit/commands/auth/login.test.ts +``` + +## Test Organization + +### File Structure +- Mirror source structure: `test/unit/commands/auth/`, `test/unit/services/`, `test/unit/utils/` +- Use consistent naming: `[module-name].test.ts` +- Integration tests: `test/integration/` + +### Test Data Management +```typescript +// Create mock data factories in test/fixtures/ +const mockAuthToken = { token: 'abc123', expiresAt: Date.now() + 3600000 }; +const mockConfig = { region: 'us', email: 'test@example.com' }; +``` + +## Error Testing + +### Rate Limit Handling +```typescript +it('should handle rate limit errors', async () => { + const error = new Error('Rate limited'); + (error as any).status = 429; + + class MockClient { + fetch() { throw error; } + } + + try { + await new MockClient().fetch(); + expect.fail('Should have thrown'); + } catch (err: any) { + expect(err.status).to.equal(429); + } +}); +``` + +### Validation Error Testing +```typescript +it('should throw validation error for invalid input', () => { + expect(() => service.validateRegion('')) + .to.throw('Region is required'); +}); +``` + +## Coverage and Quality + +### Coverage Requirements +```json +"nyc": { + "check-coverage": true, + "lines": 80, + "functions": 80, + "branches": 80, + "statements": 80 +} +``` + +### Quality Checklist +- [ ] All public methods tested +- [ ] Error paths covered (success + failure) +- [ ] Edge cases included +- [ ] No real API calls +- [ ] Descriptive test names +- [ ] Minimal test setup +- [ ] Tests run < 5s per test file +- [ ] 80%+ coverage achieved + +## Usage + +Reference the comprehensive patterns guide above for detailed test structures, mocking strategies, error testing patterns, and coverage requirements. diff --git a/.cursor/skills/testing/references/testing-patterns.md b/.cursor/skills/testing/references/testing-patterns.md new file mode 100644 index 000000000..fa4d48109 --- /dev/null +++ b/.cursor/skills/testing/references/testing-patterns.md @@ -0,0 +1,358 @@ +# Testing Patterns + +Testing best practices and TDD workflow for Contentstack CLI monorepo development. + +## TDD Workflow + +**Simple RED-GREEN-REFACTOR:** +1. **RED** → Write failing test +2. **GREEN** → Make it pass with minimal code +3. **REFACTOR** → Improve code quality while keeping tests green + +## Test Structure Standards + +### Basic Test Template +```typescript +describe('[ComponentName]', () => { + let component: [ComponentName]; + + beforeEach(() => { + // Setup mocks and test data + component = new [ComponentName](); + }); + + afterEach(() => { + // Clean up resources + }); + + it('should [expected behavior] when [condition]', async () => { + // Arrange + const input = { /* test data */ }; + + // Act + const result = await component.method(input); + + // Assert + expect(result).to.deep.equal(expectedOutput); + }); +}); +``` + +### Command Testing Example +```typescript +import { test } from '@oclif/test'; + +describe('config:set:region', () => { + test + .stdout() + .command(['config:set:region', '--help']) + .it('shows help', ctx => { + expect(ctx.stdout).to.contain('Set CLI region'); + }); + + test + .stdout() + .command(['config:set:region', 'AWS-NA']) + .it('sets region to AWS-NA', ctx => { + expect(ctx.stdout).to.contain('success'); + }); +}); +``` + +### Service Testing Example +```typescript +describe('AuthService', () => { + let authService: AuthService; + let mockConfig: any; + + beforeEach(() => { + mockConfig = { region: 'us', email: 'test@example.com' }; + authService = new AuthService(mockConfig); + }); + + it('should authenticate user with valid credentials', async () => { + const result = await authService.login('test@example.com', 'password'); + expect(result).to.have.property('token'); + }); + + it('should throw error on invalid credentials', async () => { + await expect(authService.login('test@example.com', 'wrong')) + .to.be.rejectedWith('Authentication failed'); + }); +}); +``` + +## Key Testing Rules + +### Coverage Requirements +- **80% minimum** coverage (lines, branches, functions) +- Test both success and failure paths +- Include edge cases and error scenarios + +### Mocking Standards +- **Use class-based mocking** (extend and override methods) +- **Never make real API calls** in tests +- **Mock at service boundaries**, not implementation details +- Clean up resources in `afterEach()` to prevent test pollution + +### Test Patterns +- Use descriptive test names: "should [behavior] when [condition]" +- Keep test setup minimal and focused +- Prefer async/await patterns +- Group related tests in `describe` blocks + +## Common Mock Patterns + +### Service Mocking +```typescript +// Mock a service by extending and overriding methods +class MockContentstackClient { + async fetch() { + return { + uid: 'entry-1', + title: 'Mock Entry', + content_type: 'page' + }; + } +} + +it('should process entry', async () => { + const mockClient = new MockContentstackClient(); + const result = await mockClient.fetch(); + expect(result.uid).to.equal('entry-1'); +}); +``` + +### Dependency Injection Mocking +```typescript +class RateLimiter { + constructor(private maxConcurrent: number = 1) {} + + async execute(operation: () => Promise): Promise { + return operation(); + } +} + +class MyService { + constructor(private rateLimiter: RateLimiter) {} + + async doWork() { + return this.rateLimiter.execute(() => this.performWork()); + } +} + +it('should use rate limiter', async () => { + // Pass in mock with minimal implementation + const mockLimiter = { execute: (fn) => fn() } as any; + const service = new MyService(mockLimiter); + + const result = await service.doWork(); + expect(result).to.exist; +}); +``` + +### API Error Simulation +```typescript +class MockClient { + fetch(endpoint: string) { + if (endpoint === '/rate-limited') { + const error = new Error('Rate limited'); + (error as any).status = 429; + throw error; + } + return Promise.resolve({ data: 'ok' }); + } +} + +it('should handle rate limit errors', async () => { + const client = new MockClient(); + + try { + await client.fetch('/rate-limited'); + expect.fail('Should have thrown'); + } catch (error: any) { + expect(error.status).to.equal(429); + expect(error.message).to.include('Rate limited'); + } +}); +``` + +### Configuration Mocking +```typescript +it('should load config from mock', async () => { + const mockConfig = { + region: 'us', + email: 'test@example.com', + authToken: 'token-123', + get: (key: string) => mockConfig[key as keyof typeof mockConfig] + }; + + const service = new ConfigService(mockConfig); + expect(service.region).to.equal('us'); +}); +``` + +## Error Testing Patterns + +### Rate Limit Handling +```typescript +it('should retry on rate limit error', async () => { + let callCount = 0; + + class MockService { + async call() { + callCount++; + if (callCount === 1) { + const error = new Error('Rate limited'); + (error as any).status = 429; + throw error; + } + return 'success'; + } + } + + const service = new MockService(); + + // First call throws, simulate retry + try { await service.call(); } catch (e) { /* expected */ } + const result = await service.call(); + + expect(result).to.equal('success'); + expect(callCount).to.equal(2); +}); +``` + +### Validation Error Testing +```typescript +it('should throw validation error for invalid input', () => { + class Validator { + validate(region: string): void { + if (!region || region === '') { + throw new Error('Region is required'); + } + } + } + + const validator = new Validator(); + expect(() => validator.validate('')) + .to.throw('Region is required'); +}); +``` + +### Async Error Handling +```typescript +it('should handle async operation failures', async () => { + class FailingService { + async performAsync() { + throw new Error('Operation failed'); + } + } + + const service = new FailingService(); + + try { + await service.performAsync(); + expect.fail('Should have thrown error'); + } catch (error: any) { + expect(error.message).to.include('Operation failed'); + } +}); +``` + +## Test Organization + +### File Structure +- Mirror source structure: `test/unit/services/auth-service.test.ts` +- Use consistent naming: `[module-name].test.ts` +- Group integration tests: `test/integration/` +- Commands: `test/unit/commands/auth/login.test.ts` +- Services: `test/unit/services/config-service.test.ts` +- Utils: `test/unit/utils/region-handler.test.ts` + +### Test Data Management +- Create mock data in test files or in `test/fixtures/` for reuse +- Use realistic test data that matches actual API responses +- Share common mocks across test files in a factory pattern + +### Test Configuration +```javascript +// .mocharc.json +{ + "require": [ + "test/helpers/init.js", + "ts-node/register", + "source-map-support/register" + ], + "recursive": true, + "timeout": 30000, + "spec": "test/**/*.test.ts" +} +``` + +## Monorepo Testing Commands + +### Run all tests across workspace +```bash +pnpm test +``` + +### Run tests for specific package +```bash +pnpm --filter @contentstack/cli-auth test +pnpm --filter @contentstack/cli-config test +pnpm --filter @contentstack/cli-command test +``` + +### Run tests with coverage +```bash +pnpm test:coverage +``` + +### Run tests in watch mode +```bash +pnpm test:watch +``` + +### Run specific test file +```bash +pnpm test -- test/unit/commands/config/set/region.test.ts +``` + +### Run tests matching pattern +```bash +pnpm test -- --grep "should authenticate user" +``` + +## Coverage and Quality + +### Coverage Enforcement +```json +"nyc": { + "check-coverage": true, + "lines": 80, + "functions": 80, + "branches": 80, + "statements": 80 +} +``` + +### Coverage Report Generation +```bash +# Generate coverage reports +pnpm test:coverage + +# HTML report available at coverage/index.html +open coverage/index.html +``` + +### Quality Checklist +- [ ] All public methods tested +- [ ] Error paths covered (success + failure) +- [ ] Edge cases included +- [ ] No real API calls in tests +- [ ] Descriptive test names +- [ ] Minimal test setup (fast to run) +- [ ] Tests complete in < 5 seconds per file +- [ ] 80%+ coverage achieved +- [ ] Mocks properly isolated per test +- [ ] No test pollution (afterEach cleanup) diff --git a/.talismanrc b/.talismanrc index 6cbd26fc6..45de773ac 100644 --- a/.talismanrc +++ b/.talismanrc @@ -1,4 +1,22 @@ fileignoreconfig: - - filename: pnpm-lock.yaml - checksum: 78b7fca30ae03e2570a384c5432c10f0e6b023f492b68929795adcb4613e8673 -version: '1.0' +- filename: pnpm-lock.yaml + checksum: e4c0b8eff5a2fbb954e207e1b341b6fa9e7c838695ccf829158f7203df91e56a +- filename: .cursor/skills/contentstack-cli/SKILL.md + checksum: 45f0d0c81086eaee850311e0caae198cf6dd2a7bc73bd1340b320b15047c6dae +- filename: .cursor/skills/code-review/SKILL.md + checksum: 29d812ac5c2ed4c55490f8d31e15eb592851601a6a141354cb458b1b9f1daa7a +- filename: .cursor/skills/testing/references/testing-patterns.md + checksum: 0a6cb66f27eda46b40508517063a2f43fea1b4b8df878e7ddff404ab7fc126f8 +- filename: .cursor/skills/code-review/references/code-review-checklist.md + checksum: bdf7453f08d7209deaee411f47a1132ee872b28f0eb082563dfe20aa56eab057 +- filename: .cursor/skills/contentstack-cli/references/contentstack-patterns.md + checksum: 9888d481b6a1ae8c7102d9efed0fdbae2b7592f582a62c8bff6deccf03fdf341 +- filename: .cursor/rules/dev-workflow.md + checksum: 3c3a483b44901bb440b4ce311a40d6e8c11decf9795f6d2d1d3a3787aa9981c3 +- filename: .cursor/commands/code-review.md + checksum: a2737c43d58de842cf48c06b0471648a7c38b5fa8854d7c30f3d9258cd8b48f9 +- filename: .cursor/rules/contentstack-plugin.mdc + checksum: 4d41211088c2302a533559bb1e7e80fe69e6980f23c9a2e90b8ea9d03ba3f040 +- filename: .cursor/rules/oclif-commands.mdc + checksum: 8e269309cbfc9687e4a889c4a7983f145e77066d515dae53968d7553ae726b41 +version: "1.0" \ No newline at end of file diff --git a/packages/contentstack-variants/test/unit/import/audiences.test.ts b/packages/contentstack-variants/test/unit/import/audiences.test.ts new file mode 100644 index 000000000..1f7296c1a --- /dev/null +++ b/packages/contentstack-variants/test/unit/import/audiences.test.ts @@ -0,0 +1,118 @@ +import { expect } from '@oclif/test'; +import cloneDeep from 'lodash/cloneDeep'; +import { fancy } from '@contentstack/cli-dev-dependencies'; + +import importConf from '../mock/import-config.json'; +import { Import, ImportConfig } from '../../../src'; + +describe('Audiences Import', () => { + let config: ImportConfig; + let createAudienceCalls: Array<{ name: string }> = []; + + const test = fancy.stdout({ print: process.env.PRINT === 'true' || false }); + + beforeEach(() => { + config = cloneDeep(importConf) as unknown as ImportConfig; + createAudienceCalls = []; + // Audiences uses modules.personalize and region - add them for tests + config.modules.personalize = { + ...(config.modules as any).personalization, + dirName: 'personalize', + baseURL: { + na: 'https://personalization.na-api.contentstack.com', + eu: 'https://personalization.eu-api.contentstack.com', + }, + } as any; + config.region = { name: 'eu' } as any; + config.context = config.context || {}; + }); + + describe('import method - Lytics audience skip', () => { + test + .stub(Import.Audiences.prototype, 'init', async () => {}) + .stub(Import.Audiences.prototype, 'createAudience', (async (payload: any) => { + createAudienceCalls.push({ name: payload.name }); + return { uid: `new-${payload.name.replace(/\s/g, '-')}`, name: payload.name }; + }) as any) + .it('should skip Lytics audiences and not call createAudience for them', async () => { + const audiencesInstance = new Import.Audiences(config); + await audiencesInstance.import(); + + const lyticsNames = createAudienceCalls.filter( + (c) => c.name === 'Lytics Audience' || c.name === 'Lytics Lowercase', + ); + expect(lyticsNames.length).to.equal(0); + }); + + test + .stub(Import.Audiences.prototype, 'init', async () => {}) + .stub(Import.Audiences.prototype, 'createAudience', (async (payload: any) => { + createAudienceCalls.push({ name: payload.name }); + return { uid: `new-${payload.name.replace(/\s/g, '-')}`, name: payload.name }; + }) as any) + .it('should process audiences with undefined source', async () => { + const audiencesInstance = new Import.Audiences(config); + await audiencesInstance.import(); + + const noSourceCall = createAudienceCalls.find((c) => c.name === 'No Source Audience'); + expect(noSourceCall).to.not.be.undefined; + }); + + test + .stub(Import.Audiences.prototype, 'init', async () => {}) + .stub(Import.Audiences.prototype, 'createAudience', (async (payload: any) => { + createAudienceCalls.push({ name: payload.name }); + return { uid: `new-${payload.name.replace(/\s/g, '-')}`, name: payload.name }; + }) as any) + .it('should skip audience with source "lytics" (lowercase)', async () => { + const audiencesInstance = new Import.Audiences(config); + await audiencesInstance.import(); + + const lyticsLowercaseCall = createAudienceCalls.find((c) => c.name === 'Lytics Lowercase'); + expect(lyticsLowercaseCall).to.be.undefined; + }); + + test + .stub(Import.Audiences.prototype, 'init', async () => {}) + .stub(Import.Audiences.prototype, 'createAudience', (async (payload: any) => { + createAudienceCalls.push({ name: payload.name }); + return { uid: `new-uid-${payload.name}`, name: payload.name }; + }) as any) + .it('should call createAudience only for non-Lytics audiences', async () => { + const audiencesInstance = new Import.Audiences(config); + await audiencesInstance.import(); + + // 4 audiences in mock: 2 Lytics (skip), 2 non-Lytics (Contentstack Test, No Source) + expect(createAudienceCalls.length).to.equal(2); + }); + + test + .stub(Import.Audiences.prototype, 'init', async () => {}) + .stub(Import.Audiences.prototype, 'createAudience', (async (payload: any) => { + createAudienceCalls.push({ name: payload.name }); + return { uid: 'new-contentstack-uid', name: payload.name }; + }) as any) + .it('should not add Lytics audiences to audiencesUidMapper', async () => { + const audiencesInstance = new Import.Audiences(config); + await audiencesInstance.import(); + + const mapper = (audiencesInstance as any).audiencesUidMapper; + expect(mapper['lytics-audience-001']).to.be.undefined; + expect(mapper['lytics-lowercase-001']).to.be.undefined; + }); + + test + .stub(Import.Audiences.prototype, 'init', async () => {}) + .stub(Import.Audiences.prototype, 'createAudience', (async (payload: any) => { + createAudienceCalls.push({ name: payload.name }); + return { uid: 'new-contentstack-uid', name: payload.name }; + }) as any) + .it('should add Contentstack audiences to audiencesUidMapper', async () => { + const audiencesInstance = new Import.Audiences(config); + await audiencesInstance.import(); + + const mapper = (audiencesInstance as any).audiencesUidMapper; + expect(mapper['contentstack-audience-001']).to.equal('new-contentstack-uid'); + }); + }); +}); diff --git a/packages/contentstack-variants/test/unit/mock/contents/mapper/personalize/attributes/uid-mapping.json b/packages/contentstack-variants/test/unit/mock/contents/mapper/personalize/attributes/uid-mapping.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/packages/contentstack-variants/test/unit/mock/contents/mapper/personalize/attributes/uid-mapping.json @@ -0,0 +1 @@ +{} diff --git a/packages/contentstack-variants/test/unit/mock/contents/mapper/personalize/audiences/uid-mapping.json b/packages/contentstack-variants/test/unit/mock/contents/mapper/personalize/audiences/uid-mapping.json new file mode 100644 index 000000000..5ef9e31e5 --- /dev/null +++ b/packages/contentstack-variants/test/unit/mock/contents/mapper/personalize/audiences/uid-mapping.json @@ -0,0 +1 @@ +{"contentstack-audience-001":"new-contentstack-uid","no-source-audience-001":"new-contentstack-uid"} \ No newline at end of file diff --git a/packages/contentstack-variants/test/unit/mock/contents/personalize/audiences/audiences.json b/packages/contentstack-variants/test/unit/mock/contents/personalize/audiences/audiences.json new file mode 100644 index 000000000..68e17beaa --- /dev/null +++ b/packages/contentstack-variants/test/unit/mock/contents/personalize/audiences/audiences.json @@ -0,0 +1,44 @@ +[ + { + "uid": "contentstack-audience-001", + "name": "Contentstack Test Audience", + "description": "Audience with rules", + "definition": { + "__type": "RuleCombination", + "combinationType": "AND", + "rules": [ + { + "__type": "Rule", + "attribute": { "__type": "PresetAttributeReference", "ref": "DEVICE_TYPE" }, + "attributeMatchOptions": { "__type": "StringMatchOptions", "value": "MOBILE" }, + "attributeMatchCondition": "STRING_EQUALS", + "invertCondition": false + } + ] + } + }, + { + "uid": "lytics-audience-001", + "name": "Lytics Audience", + "description": "From Lytics", + "slug": "lytics_audience", + "source": "LYTICS" + }, + { + "uid": "lytics-lowercase-001", + "name": "Lytics Lowercase", + "description": "source is lowercase", + "slug": "lytics_lowercase", + "source": "lytics" + }, + { + "uid": "no-source-audience-001", + "name": "No Source Audience", + "description": "Audience without source field", + "definition": { + "__type": "RuleCombination", + "combinationType": "AND", + "rules": [] + } + } +] diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index edb3beaf9..39e262f0f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -966,123 +966,123 @@ packages: resolution: {integrity: sha512-0XLrOT4Cm3NEhhiME7l/8LbTXS4KdsbR4dSrY207KNKTcHLLTZ9EXt4ZpgnTfLvWQF3pGP2us4Zi1fYLo0N+Ow==} engines: {node: '>=20.0.0'} - '@aws-sdk/core@3.973.27': - resolution: {integrity: sha512-CUZ5m8hwMCH6OYI4Li/WgMfIEx10Q2PLI9Y3XOUTPGZJ53aZ0007jCv+X/ywsaERyKPdw5MRZWk877roQksQ4A==} + '@aws-sdk/core@3.974.0': + resolution: {integrity: sha512-8j+dMtyDqNXFmi09CBdz8TY6Ltf2jhfHuP6ZvG4zVjndRc6JF0aeBUbRwQLndbptFCsdctRQgdNWecy4TIfXAw==} engines: {node: '>=20.0.0'} - '@aws-sdk/crc64-nvme@3.972.6': - resolution: {integrity: sha512-NMbiqKdruhwwgI6nzBVe2jWMkXjaoQz2YOs3rFX+2F3gGyrJDkDPwMpV/RsTFeq2vAQ055wZNtOXFK4NYSkM8g==} + '@aws-sdk/crc64-nvme@3.972.7': + resolution: {integrity: sha512-QUagVVBbC8gODCF6e1aV0mE2TXWB9Opz4k8EJFdNrujUVQm5R4AjJa1mpOqzwOuROBzqJU9zawzig7M96L8Ejg==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-env@3.972.25': - resolution: {integrity: sha512-6QfI0wv4jpG5CrdO/AO0JfZ2ux+tKwJPrUwmvxXF50vI5KIypKVGNF6b4vlkYEnKumDTI1NX2zUBi8JoU5QU3A==} + '@aws-sdk/credential-provider-env@3.972.26': + resolution: {integrity: sha512-WBHAMxyPdgeJY6ZGLvq9mJwzZ+GaNUROQbfdVshtMsDVBrZTj5ZuFjKclSjSHvKSHJ4Y4O2yvI/aA/hrJbYfng==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-http@3.972.27': - resolution: {integrity: sha512-3V3Usj9Gs93h865DqN4M2NWJhC5kXU9BvZskfN3+69omuYlE3TZxOEcVQtBGLOloJB7BVfJKXVLqeNhOzHqSlQ==} + '@aws-sdk/credential-provider-http@3.972.28': + resolution: {integrity: sha512-+1DwCjjpo1WoiZTN08yGitI3nUwZUSQWVWFrW4C46HqZwACjcUQ7C66tnKPBTVxrEYYDOP11A6Afmu1L6ylt3g==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-ini@3.972.29': - resolution: {integrity: sha512-SiBuAnXecCbT/OpAf3vqyI/AVE3mTaYr9ShXLybxZiPLBiPCCOIWSGAtYYGQWMRvobBTiqOewaB+wcgMMZI2Aw==} + '@aws-sdk/credential-provider-ini@3.972.30': + resolution: {integrity: sha512-Fg1oJcoijwOZjTxdbx+ubqbQl8YEQ4Cwhjw6TWzQjuDEvQYNhnCXW2pN7eKtdTrdE4a6+5TVKGSm2I+i2BKIQg==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-login@3.972.29': - resolution: {integrity: sha512-OGOslTbOlxXexKMqhxCEbBQbUIfuhGxU5UXw3Fm56ypXHvrXH4aTt/xb5Y884LOoteP1QST1lVZzHfcTnWhiPQ==} + '@aws-sdk/credential-provider-login@3.972.30': + resolution: {integrity: sha512-nchIrrI/7dgjG1bW/DEWOJc00K9n+kkl6B8Mk0KO6d4GfWBOXlVr9uHp7CJR9FIrjmov5SGjHXG2q9XAtkRw6Q==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-node@3.972.30': - resolution: {integrity: sha512-FMnAnWxc8PG+ZrZ2OBKzY4luCUJhe9CG0B9YwYr4pzrYGLXBS2rl+UoUvjGbAwiptxRL6hyA3lFn03Bv1TLqTw==} + '@aws-sdk/credential-provider-node@3.972.31': + resolution: {integrity: sha512-99OHVQ6eZ5DTxiOWgHdjBMvLqv7xoY4jLK6nZ1NcNSQbAnYZkQNIHi/VqInc9fnmg7of9si/z+waE6YL9OQIlw==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-process@3.972.25': - resolution: {integrity: sha512-HR7ynNRdNhNsdVCOCegy1HsfsRzozCOPtD3RzzT1JouuaHobWyRfJzCBue/3jP7gECHt+kQyZUvwg/cYLWurNQ==} + '@aws-sdk/credential-provider-process@3.972.26': + resolution: {integrity: sha512-jibxNld3m+vbmQwn98hcQ+fLIVrx3cQuhZlSs1/hix48SjDS5/pjMLwpmtLD/lFnd6ve1AL4o1bZg3X1WRa2SQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-sso@3.972.29': - resolution: {integrity: sha512-HWv4SEq3jZDYPlwryZVef97+U8CxxRos5mK8sgGO1dQaFZpV5giZLzqGE5hkDmh2csYcBO2uf5XHjPTpZcJlig==} + '@aws-sdk/credential-provider-sso@3.972.30': + resolution: {integrity: sha512-honYIM17F/+QSWJRE84T4u//ofqEi7rLbnwmIpu7fgFX5PML78wbtdSAy5Xwyve3TLpE9/f9zQx0aBVxSjAOPw==} engines: {node: '>=20.0.0'} - '@aws-sdk/credential-provider-web-identity@3.972.29': - resolution: {integrity: sha512-PdMBza1WEKEUPFEmMGCfnU2RYCz9MskU2e8JxjyUOsMKku7j9YaDKvbDi2dzC0ihFoM6ods2SbhfAAro+Gwlew==} + '@aws-sdk/credential-provider-web-identity@3.972.30': + resolution: {integrity: sha512-CyL4oWUlONQRN2SsYMVrA9Z3i3QfLWTQctI8tuKbjNGCVVDCnJf/yMbSJCOZgpPFRtxh7dgQwvpqwmJm+iytmw==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-bucket-endpoint@3.972.9': - resolution: {integrity: sha512-COToYKgquDyligbcAep7ygs48RK+mwe/IYprq4+TSrVFzNOYmzWvHf6werpnKV5VYpRiwdn+Wa5ZXkPqLVwcTg==} + '@aws-sdk/middleware-bucket-endpoint@3.972.10': + resolution: {integrity: sha512-Vbc2frZH7wXlMNd+ZZSXUEs/l1Sv8Jj4zUnIfwrYF5lwaLdXHZ9xx4U3rjUcaye3HRhFVc+E5DbBxpRAbB16BA==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-expect-continue@3.972.9': - resolution: {integrity: sha512-V/FNCjFxnh4VGu+HdSiW4Yg5GELihA1MIDSAdsEPvuayXBVmr0Jaa6jdLAZLH38KYXl/vVjri9DQJWnTAujHEA==} + '@aws-sdk/middleware-expect-continue@3.972.10': + resolution: {integrity: sha512-2Yn0f1Qiq/DjxYR3wfI3LokXnjOhFM7Ssn4LTdFDIxRMCE6I32MAsVnhPX1cUZsuVA9tiZtwwhlSLAtFGxAZlQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-flexible-checksums@3.974.7': - resolution: {integrity: sha512-uU4/ch2CLHB8Phu1oTKnnQ4e8Ujqi49zEnQYBhWYT53zfFvtJCdGsaOoypBr8Fm/pmCBssRmGoIQ4sixgdLP9w==} + '@aws-sdk/middleware-flexible-checksums@3.974.8': + resolution: {integrity: sha512-c+bD9J3f56oOPmmseCfT6PhkykiC5vtq0/ZDaK7U1Da/u/b7ZhhidfTHGnqa1pMCro9ZkM4QBcJ70lP7RgnPWg==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-host-header@3.972.9': - resolution: {integrity: sha512-je5vRdNw4SkuTnmRbFZLdye4sQ0faLt8kwka5wnnSU30q1mHO4X+idGEJOOE+Tn1ME7Oryn05xxkDvIb3UaLaQ==} + '@aws-sdk/middleware-host-header@3.972.10': + resolution: {integrity: sha512-IJSsIMeVQ8MMCPbuh1AbltkFhLBLXn7aejzfX5YKT/VLDHn++Dcz8886tXckE+wQssyPUhaXrJhdakO2VilRhg==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-location-constraint@3.972.9': - resolution: {integrity: sha512-TyfOi2XNdOZpNKeTJwRUsVAGa+14nkyMb2VVGG+eDgcWG/ed6+NUo72N3hT6QJioxym80NSinErD+LBRF0Ir1w==} + '@aws-sdk/middleware-location-constraint@3.972.10': + resolution: {integrity: sha512-rI3NZvJcEvjoD0+0PI0iUAwlPw2IlSlhyvgBK/3WkKJQE/YiKFedd9dMN2lVacdNxPNhxL/jzQaKQdrGtQagjQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-logger@3.972.9': - resolution: {integrity: sha512-HsVgDrruhqI28RkaXALm8grJ7Agc1wF6Et0xh6pom8NdO2VdO/SD9U/tPwUjewwK/pVoka+EShBxyCvgsPCtog==} + '@aws-sdk/middleware-logger@3.972.10': + resolution: {integrity: sha512-OOuGvvz1Dm20SjZo5oEBePFqxt5nf8AwkNDSyUHvD9/bfNASmstcYxFAHUowy4n6Io7mWUZ04JURZwSBvyQanQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-recursion-detection@3.972.10': - resolution: {integrity: sha512-RVQQbq5orQ/GHUnXvqEOj2HHPBJm+mM+ySwZKS5UaLBwra5ugRtiH09PLUoOZRl7a1YzaOzXSuGbn9iD5j60WQ==} + '@aws-sdk/middleware-recursion-detection@3.972.11': + resolution: {integrity: sha512-+zz6f79Kj9V5qFK2P+D8Ehjnw4AhphAlCAsPjUqEcInA9umtSSKMrHbSagEeOIsDNuvVrH98bjRHcyQukTrhaQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-sdk-s3@3.972.28': - resolution: {integrity: sha512-qJHcJQH9UNPUrnPlRtCozKjtqAaypQ5IgQxTNoPsVYIQeuwNIA8Rwt3NvGij1vCDYDfCmZaPLpnJEHlZXeFqmg==} + '@aws-sdk/middleware-sdk-s3@3.972.29': + resolution: {integrity: sha512-ayk68penP1WDZmyDZVeUQzq+HI3iDq5xezohUxIQoKFKE0KdCnDcxLCNnLanhBfgQDaKiGHVXhxZMDWJAEEBsQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-ssec@3.972.9': - resolution: {integrity: sha512-wSA2BR7L0CyBNDJeSrleIIzC+DzL93YNTdfU0KPGLiocK6YsRv1nPAzPF+BFSdcs0Qa5ku5Kcf4KvQcWwKGenQ==} + '@aws-sdk/middleware-ssec@3.972.10': + resolution: {integrity: sha512-Gli9A0u8EVVb+5bFDGS/QbSVg28w/wpEidg1ggVcSj65BDTdGR6punsOcVjqdiu1i42WHWo51MCvARPIIz9juw==} engines: {node: '>=20.0.0'} - '@aws-sdk/middleware-user-agent@3.972.29': - resolution: {integrity: sha512-f/sIRzuTfEjg6NsbMYvye2VsmnQoNgntntleQyx5uGacUYzszbfIlO3GcI6G6daWUmTm0IDZc11qMHWwF0o0mQ==} + '@aws-sdk/middleware-user-agent@3.972.30': + resolution: {integrity: sha512-lCz6JfelhjD6Eco1urXM2rOYRaxROSqeoY6IEKx+soegFJOajmIBCMHTAWuJl25Wf9IAST+i0/yOk9G3rMV26A==} engines: {node: '>=20.0.0'} - '@aws-sdk/nested-clients@3.996.19': - resolution: {integrity: sha512-uFkmCDXvmQYLanlYdOFS0+MQWkrj9wPMt/ZCc/0J0fjPim6F5jBVBmEomvGY/j77ILW6GTPwN22Jc174Mhkw6Q==} + '@aws-sdk/nested-clients@3.996.20': + resolution: {integrity: sha512-bzPdsNQnCh6TvvUmTHLZlL8qgyME6mNiUErcRMyJPywIl1BEu2VZRShel3mUoSh89bOBEXEWtjocDMolFxd/9A==} engines: {node: '>=20.0.0'} - '@aws-sdk/region-config-resolver@3.972.11': - resolution: {integrity: sha512-6Q8B1dcx6BBqUTY1Mc/eROKA0FImEEY5VPSd6AGPEUf0ErjExz4snVqa9kNJSoVDV1rKaNf3qrWojgcKW+SdDg==} + '@aws-sdk/region-config-resolver@3.972.12': + resolution: {integrity: sha512-QQI43Mxd53nBij0pm8HXC+t4IOC6gnhhZfzxE0OATQyO6QfPV4e+aTIRRuAJKA6Nig/cR8eLwPryqYTX9ZrjAQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/signature-v4-multi-region@3.996.16': - resolution: {integrity: sha512-EMdXYB4r/k5RWq86fugjRhid5JA+Z6MpS7n4sij4u5/C+STrkvuf9aFu41rJA9MjUzxCLzv8U2XL8cH2GSRYpQ==} + '@aws-sdk/signature-v4-multi-region@3.996.17': + resolution: {integrity: sha512-qDwhXw+SIM5vMAMgflA8LPRa7xP+/wgXYr++llzCOwp7kkM2v7GGGWzoRW8e1CACaO4ljZd/NSQbsRLKm1sMWw==} engines: {node: '>=20.0.0'} - '@aws-sdk/token-providers@3.1026.0': - resolution: {integrity: sha512-Ieq/HiRrbEtrYP387Nes0XlR7H1pJiJOZKv+QyQzMYpvTiDs0VKy2ZB3E2Zf+aFovWmeE7lRE4lXyF7dYM6GgA==} + '@aws-sdk/token-providers@3.1031.0': + resolution: {integrity: sha512-zj/PvnbQK/2KJNln5K2QRI9HSsy+B4emz2gbQyUHkk6l7Lidu83P/9tfmC2cJXkcC3vdmyKH2DP3Iw/FDfKQuQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/types@3.973.7': - resolution: {integrity: sha512-reXRwoJ6CfChoqAsBszUYajAF8Z2LRE+CRcKocvFSMpIiLOtYU3aJ9trmn6VVPAzbbY5LXF+FfmUslbXk1SYFg==} + '@aws-sdk/types@3.973.8': + resolution: {integrity: sha512-gjlAdtHMbtR9X5iIhVUvbVcy55KnznpC6bkDUWW9z915bi0ckdUr5cjf16Kp6xq0bP5HBD2xzgbL9F9Quv5vUw==} engines: {node: '>=20.0.0'} '@aws-sdk/util-arn-parser@3.972.3': resolution: {integrity: sha512-HzSD8PMFrvgi2Kserxuff5VitNq2sgf3w9qxmskKDiDTThWfVteJxuCS9JXiPIPtmCrp+7N9asfIaVhBFORllA==} engines: {node: '>=20.0.0'} - '@aws-sdk/util-endpoints@3.996.6': - resolution: {integrity: sha512-2nUQ+2ih7CShuKHpGSIYvvAIOHy52dOZguYG36zptBukhw6iFwcvGfG0tes0oZFWQqEWvgZe9HLWaNlvXGdOrg==} + '@aws-sdk/util-endpoints@3.996.7': + resolution: {integrity: sha512-ty4LQxN1QC+YhUP28NfEgZDEGXkyqOQy+BDriBozqHsrYO4JMgiPhfizqOGF7P+euBTZ5Ez6SKlLAMCLo8tzmw==} engines: {node: '>=20.0.0'} '@aws-sdk/util-locate-window@3.965.5': resolution: {integrity: sha512-WhlJNNINQB+9qtLtZJcpQdgZw3SCDCpXdUJP7cToGwHbCWCnRckGlc6Bx/OhWwIYFNAn+FIydY8SZ0QmVu3xTQ==} engines: {node: '>=20.0.0'} - '@aws-sdk/util-user-agent-browser@3.972.9': - resolution: {integrity: sha512-sn/LMzTbGjYqCCF24390WxPd6hkpoSptiUn5DzVp4cD71yqw+yGEGm1YCxyEoPXyc8qciM8UzLJcZBFslxo5Uw==} + '@aws-sdk/util-user-agent-browser@3.972.10': + resolution: {integrity: sha512-FAzqXvfEssGdSIz8ejatan0bOdx1qefBWKF/gWmVBXIP1HkS7v/wjjaqrAGGKvyihrXTXW00/2/1nTJtxpXz7g==} - '@aws-sdk/util-user-agent-node@3.973.15': - resolution: {integrity: sha512-fYn3s9PtKdgQkczGZCFMgkNEe8aq1JCVbnRqjqN9RSVW43xn2RV9xdcZ3z01a48Jpkuh/xCmBKJxdLOo4Ozg7w==} + '@aws-sdk/util-user-agent-node@3.973.16': + resolution: {integrity: sha512-ccvu0FNCI0C6OqmxI/tWn7BD8qGooWuURssiIM+6vbksFO8opXR4JOGtGYPj8QYzN/vfwNYrcK344PPbYuvzRg==} engines: {node: '>=20.0.0'} peerDependencies: aws-crt: '>=1.0.0' @@ -1090,8 +1090,8 @@ packages: aws-crt: optional: true - '@aws-sdk/xml-builder@3.972.17': - resolution: {integrity: sha512-Ra7hjqAZf1OXRRMueB13qex7mFJRDK/pgCvdSFemXBT8KCGnQDPoKzHY1SjN+TjJVmnpSF14W5tJ1vDamFu+Gg==} + '@aws-sdk/xml-builder@3.972.18': + resolution: {integrity: sha512-BMDNVG1ETXRhl1tnisQiYBef3RShJ1kfZA7x7afivTFMLirfHNTb6U71K569HNXhSXbQZsweHvSDZ6euBw8hPA==} engines: {node: '>=20.0.0'} '@aws/lambda-invoke-store@0.2.4': @@ -1984,56 +1984,56 @@ packages: resolution: {integrity: sha512-St+kVicSyayWQca+I1rGitaOEH6uKgE8IUWoYnnEX26SWdWQcL6LvMSD19Lg+vYHKdT9B2Zuu7rd3i6Wnyb/iw==} engines: {node: '>=18.0.0'} - '@smithy/config-resolver@4.4.15': - resolution: {integrity: sha512-BJdMBY5YO9iHh+lPLYdHv6LbX+J8IcPCYMl1IJdBt2KDWNHwONHrPVHk3ttYBqJd9wxv84wlbN0f7GlQzcQtNQ==} + '@smithy/config-resolver@4.4.16': + resolution: {integrity: sha512-GFlGPNLZKrGfqWpqVb31z7hvYCA9ZscfX1buYnvvMGcRYsQQnhH+4uN6mWWflcD5jB4OXP/LBrdpukEdjl41tg==} engines: {node: '>=18.0.0'} - '@smithy/core@3.23.14': - resolution: {integrity: sha512-vJ0IhpZxZAkFYOegMKSrxw7ujhhT2pass/1UEcZ4kfl5srTAqtPU5I7MdYQoreVas3204ykCiNhY1o7Xlz6Yyg==} + '@smithy/core@3.23.15': + resolution: {integrity: sha512-E7GVCgsQttzfujEZb6Qep005wWf4xiL4x06apFEtzQMWYBPggZh/0cnOxPficw5cuK/YjjkehKoIN4YUaSh0UQ==} engines: {node: '>=18.0.0'} - '@smithy/credential-provider-imds@4.2.13': - resolution: {integrity: sha512-wboCPijzf6RJKLOvnjDAiBxGSmSnGXj35o5ZAWKDaHa/cvQ5U3ZJ13D4tMCE8JG4dxVAZFy/P0x/V9CwwdfULQ==} + '@smithy/credential-provider-imds@4.2.14': + resolution: {integrity: sha512-Au28zBN48ZAoXdooGUHemuVBrkE+Ie6RPmGNIAJsFqj33Vhb6xAgRifUydZ2aY+M+KaMAETAlKk5NC5h1G7wpg==} engines: {node: '>=18.0.0'} - '@smithy/eventstream-codec@4.2.13': - resolution: {integrity: sha512-vYahwBAtRaAcFbOmE9aLr12z7RiHYDSLcnogSdxfm7kKfsNa3wH+NU5r7vTeB5rKvLsWyPjVX8iH94brP7umiQ==} + '@smithy/eventstream-codec@4.2.14': + resolution: {integrity: sha512-erZq0nOIpzfeZdCyzZjdJb4nVSKLUmSkaQUVkRGQTXs30gyUGeKnrYEg+Xe1W5gE3aReS7IgsvANwVPxSzY6Pw==} engines: {node: '>=18.0.0'} - '@smithy/eventstream-serde-browser@4.2.13': - resolution: {integrity: sha512-wwybfcOX0tLqCcBP378TIU9IqrDuZq/tDV48LlZNydMpCnqnYr+hWBAYbRE+rFFf/p7IkDJySM3bgiMKP2ihPg==} + '@smithy/eventstream-serde-browser@4.2.14': + resolution: {integrity: sha512-8IelTCtTctWRbb+0Dcy+C0aICh1qa0qWXqgjcXDmMuCvPJRnv26hiDZoAau2ILOniki65mCPKqOQs/BaWvO4CQ==} engines: {node: '>=18.0.0'} - '@smithy/eventstream-serde-config-resolver@4.3.13': - resolution: {integrity: sha512-ied1lO559PtAsMJzg2TKRlctLnEi1PfkNeMMpdwXDImk1zV9uvS/Oxoy/vcy9uv1GKZAjDAB5xT6ziE9fzm5wA==} + '@smithy/eventstream-serde-config-resolver@4.3.14': + resolution: {integrity: sha512-sqHiHpYRYo3FJlaIxD1J8PhbcmJAm7IuM16mVnwSkCToD7g00IBZzKuiLNMGmftULmEUX6/UAz8/NN5uMP8bVA==} engines: {node: '>=18.0.0'} - '@smithy/eventstream-serde-node@4.2.13': - resolution: {integrity: sha512-hFyK+ORJrxAN3RYoaD6+gsGDQjeix8HOEkosoajvXYZ4VeqonM3G4jd9IIRm/sWGXUKmudkY9KdYjzosUqdM8A==} + '@smithy/eventstream-serde-node@4.2.14': + resolution: {integrity: sha512-Ht/8BuGlKfFTy0H3+8eEu0vdpwGztCnaLLXtpXNdQqiR7Hj4vFScU3T436vRAjATglOIPjJXronY+1WxxNLSiw==} engines: {node: '>=18.0.0'} - '@smithy/eventstream-serde-universal@4.2.13': - resolution: {integrity: sha512-kRrq4EKLGeOxhC2CBEhRNcu1KSzNJzYY7RK3S7CxMPgB5dRrv55WqQOtRwQxQLC04xqORFLUgnDlc6xrNUULaA==} + '@smithy/eventstream-serde-universal@4.2.14': + resolution: {integrity: sha512-lWyt4T2XQZUZgK3tQ3Wn0w3XBvZsK/vjTuJl6bXbnGZBHH0ZUSONTYiK9TgjTTzU54xQr3DRFwpjmhp0oLm3gg==} engines: {node: '>=18.0.0'} - '@smithy/fetch-http-handler@5.3.16': - resolution: {integrity: sha512-nYDRUIvNd4mFmuXraRWt6w5UsZTNqtj4hXJA/iiOD4tuseIdLP9Lq38teH/SZTcIFCa2f+27o7hYpIsWktJKEQ==} + '@smithy/fetch-http-handler@5.3.17': + resolution: {integrity: sha512-bXOvQzaSm6MnmLaWA1elgfQcAtN4UP3vXqV97bHuoOrHQOJiLT3ds6o9eo5bqd0TJfRFpzdGnDQdW3FACiAVdw==} engines: {node: '>=18.0.0'} - '@smithy/hash-blob-browser@4.2.14': - resolution: {integrity: sha512-rtQ5es8r/5v4rav7q5QTsfx9CtCyzrz/g7ZZZBH2xtMmd6G/KQrLOWfSHTvFOUPlVy59RQvxeBYJaLRoybMEyA==} + '@smithy/hash-blob-browser@4.2.15': + resolution: {integrity: sha512-0PJ4Al3fg2nM4qKrAIxyNcApgqHAXcBkN8FeizOz69z0rb26uZ6lMESYtxegaTlXB5Hj84JfwMPavMrwDMjucA==} engines: {node: '>=18.0.0'} - '@smithy/hash-node@4.2.13': - resolution: {integrity: sha512-4/oy9h0jjmY80a2gOIo75iLl8TOPhmtx4E2Hz+PfMjvx/vLtGY4TMU/35WRyH2JHPfT5CVB38u4JRow7gnmzJA==} + '@smithy/hash-node@4.2.14': + resolution: {integrity: sha512-8ZBDY2DD4wr+GGjTpPtiglEsqr0lUP+KHqgZcWczFf6qeZ/YRjMIOoQWVQlmwu7EtxKTd8YXD8lblmYcpBIA1g==} engines: {node: '>=18.0.0'} - '@smithy/hash-stream-node@4.2.13': - resolution: {integrity: sha512-WdQ7HwUjINXETeh6dqUeob1UHIYx8kAn9PSp1HhM2WWegiZBYVy2WXIs1lB07SZLan/udys9SBnQGt9MQbDpdg==} + '@smithy/hash-stream-node@4.2.14': + resolution: {integrity: sha512-tw4GANWkZPb6+BdD4Fgucqzey2+r73Z/GRo9zklsCdwrnxxumUV83ZIaBDdudV4Ylazw3EPTiJZhpX42105ruQ==} engines: {node: '>=18.0.0'} - '@smithy/invalid-dependency@4.2.13': - resolution: {integrity: sha512-jvC0RB/8BLj2SMIkY0Npl425IdnxZJxInpZJbu563zIRnVjpDMXevU3VMCRSabaLB0kf/eFIOusdGstrLJ8IDg==} + '@smithy/invalid-dependency@4.2.14': + resolution: {integrity: sha512-c21qJiTSb25xvvOp+H2TNZzPCngrvl5vIPqPB8zQ/DmJF4QWXO19x1dWfMJZ6wZuuWUPPm0gV8C0cU3+ifcWuw==} engines: {node: '>=18.0.0'} '@smithy/is-array-buffer@2.2.0': @@ -2044,76 +2044,76 @@ packages: resolution: {integrity: sha512-n6rQ4N8Jj4YTQO3YFrlgZuwKodf4zUFs7EJIWH86pSCWBaAtAGBFfCM7Wx6D2bBJ2xqFNxGBSrUWswT3M0VJow==} engines: {node: '>=18.0.0'} - '@smithy/md5-js@4.2.13': - resolution: {integrity: sha512-cNm7I9NXolFxtS20ojROddOEpSAeI1Obq6pd1Kj5HtHws3s9Fkk8DdHDfQSs5KuxCewZuVK6UqrJnfJmiMzDuQ==} + '@smithy/md5-js@4.2.14': + resolution: {integrity: sha512-V2v0vx+h0iUSNG1Alt+GNBMSLGCrl9iVsdd+Ap67HPM9PN479x12V8LkuMoKImNZxn3MXeuyUjls+/7ZACZghA==} engines: {node: '>=18.0.0'} - '@smithy/middleware-content-length@4.2.13': - resolution: {integrity: sha512-IPMLm/LE4AZwu6qiE8Rr8vJsWhs9AtOdySRXrOM7xnvclp77Tyh7hMs/FRrMf26kgIe67vFJXXOSmVxS7oKeig==} + '@smithy/middleware-content-length@4.2.14': + resolution: {integrity: sha512-xhHq7fX4/3lv5NHxLUk3OeEvl0xZ+Ek3qIbWaCL4f9JwgDZEclPBElljaZCAItdGPQl/kSM4LPMOpy1MYgprpw==} engines: {node: '>=18.0.0'} - '@smithy/middleware-endpoint@4.4.29': - resolution: {integrity: sha512-R9Q/58U+qBiSARGWbAbFLczECg/RmysRksX6Q8BaQEpt75I7LI6WGDZnjuC9GXSGKljEbA7N118LhGaMbfrTXw==} + '@smithy/middleware-endpoint@4.4.30': + resolution: {integrity: sha512-qS2XqhKeXmdZ4nEQ4cOxIczSP/Y91wPAHYuRwmWDCh975B7/57uxsm5d6sisnUThn2u2FwzMdJNM7AbO1YPsPg==} engines: {node: '>=18.0.0'} - '@smithy/middleware-retry@4.5.1': - resolution: {integrity: sha512-/zY+Gp7Qj2D2hVm3irkCyONER7E9MiX3cUUm/k2ZmhkzZkrPgwVS4aJ5NriZUEN/M0D1hhjrgjUmX04HhRwdWA==} + '@smithy/middleware-retry@4.5.3': + resolution: {integrity: sha512-TE8dJNi6JuxzGSxMCVd3i9IEWDndCl3bmluLsBNDWok8olgj65OfkndMhl9SZ7m14c+C5SQn/PcUmrDl57rSFw==} engines: {node: '>=18.0.0'} - '@smithy/middleware-serde@4.2.17': - resolution: {integrity: sha512-0T2mcaM6v9W1xku86Dk0bEW7aEseG6KenFkPK98XNw0ZhOqOiD1MrMsdnQw9QsL3/Oa85T53iSMlm0SZdSuIEQ==} + '@smithy/middleware-serde@4.2.18': + resolution: {integrity: sha512-M6CSgnp3v4tYz9ynj2JHbA60woBZcGqEwNjTKjBsNHPV26R1ZX52+0wW8WsZU18q45jD0tw2wL22S17Ze9LpEw==} engines: {node: '>=18.0.0'} - '@smithy/middleware-stack@4.2.13': - resolution: {integrity: sha512-g72jN/sGDLyTanrCLH9fhg3oysO3f7tQa6eWWsMyn2BiYNCgjF24n4/I9wff/5XidFvjj9ilipAoQrurTUrLvw==} + '@smithy/middleware-stack@4.2.14': + resolution: {integrity: sha512-2dvkUKLuFdKsCRmOE4Mn63co0Djtsm+JMh0bYZQupN1pJwMeE8FmQmRLLzzEMN0dnNi7CDCYYH8F0EVwWiPBeA==} engines: {node: '>=18.0.0'} - '@smithy/node-config-provider@4.3.13': - resolution: {integrity: sha512-iGxQ04DsKXLckbgnX4ipElrOTk+IHgTyu0q0WssZfYhDm9CQWHmu6cOeI5wmWRxpXbBDhIIfXMWz5tPEtcVqbw==} + '@smithy/node-config-provider@4.3.14': + resolution: {integrity: sha512-S+gFjyo/weSVL0P1b9Ts8C/CwIfNCgUPikk3sl6QVsfE/uUuO+QsF+NsE/JkpvWqqyz1wg7HFdiaZuj5CoBMRg==} engines: {node: '>=18.0.0'} - '@smithy/node-http-handler@4.5.2': - resolution: {integrity: sha512-/oD7u8M0oj2ZTFw7GkuuHWpIxtWdLlnyNkbrWcyVYhd5RJNDuczdkb0wfnQICyNFrVPlr8YHOhamjNy3zidhmA==} + '@smithy/node-http-handler@4.5.3': + resolution: {integrity: sha512-lc5jFL++x17sPhIwMWJ3YOnqmSjw/2Po6VLDlUIXvxVWRuJwRXnJ4jOBBLB0cfI5BB5ehIl02Fxr1PDvk/kxDw==} engines: {node: '>=18.0.0'} - '@smithy/property-provider@4.2.13': - resolution: {integrity: sha512-bGzUCthxRmezuxkbu9wD33wWg9KX3hJpCXpQ93vVkPrHn9ZW6KNNdY5xAUWNuRCwQ+VyboFuWirG1lZhhkcyRQ==} + '@smithy/property-provider@4.2.14': + resolution: {integrity: sha512-WuM31CgfsnQ/10i7NYr0PyxqknD72Y5uMfUMVSniPjbEPceiTErb4eIqJQ+pdxNEAUEWrewrGjIRjVbVHsxZiQ==} engines: {node: '>=18.0.0'} - '@smithy/protocol-http@5.3.13': - resolution: {integrity: sha512-+HsmuJUF4u8POo6s8/a2Yb/AQ5t/YgLovCuHF9oxbocqv+SZ6gd8lC2duBFiCA/vFHoHQhoq7QjqJqZC6xOxxg==} + '@smithy/protocol-http@5.3.14': + resolution: {integrity: sha512-dN5F8kHx8RNU0r+pCwNmFZyz6ChjMkzShy/zup6MtkRmmix4vZzJdW+di7x//b1LiynIev88FM18ie+wwPcQtQ==} engines: {node: '>=18.0.0'} - '@smithy/querystring-builder@4.2.13': - resolution: {integrity: sha512-tG4aOYFCZdPMjbgfhnIQ322H//ojujldp1SrHPHpBSb3NqgUp3dwiUGRJzie87hS1DYwWGqDuPaowoDF+rYCbQ==} + '@smithy/querystring-builder@4.2.14': + resolution: {integrity: sha512-XYA5Z0IqTeF+5XDdh4BBmSA0HvbgVZIyv4cmOoUheDNR57K1HgBp9ukUMx3Cr3XpDHHpLBnexPE3LAtDsZkj2A==} engines: {node: '>=18.0.0'} - '@smithy/querystring-parser@4.2.13': - resolution: {integrity: sha512-hqW3Q4P+CDzUyQ87GrboGMeD7XYNMOF+CuTwu936UQRB/zeYn3jys8C3w+wMkDfY7CyyyVwZQ5cNFoG0x1pYmA==} + '@smithy/querystring-parser@4.2.14': + resolution: {integrity: sha512-hr+YyqBD23GVvRxGGrcc/oOeNlK3PzT5Fu4dzrDXxzS1LpFiuL2PQQqKPs87M79aW7ziMs+nvB3qdw77SqE7Lw==} engines: {node: '>=18.0.0'} - '@smithy/service-error-classification@4.2.13': - resolution: {integrity: sha512-a0s8XZMfOC/qpqq7RCPvJlk93rWFrElH6O++8WJKz0FqnA4Y7fkNi/0mnGgSH1C4x6MFsuBA8VKu4zxFrMe5Vw==} + '@smithy/service-error-classification@4.2.14': + resolution: {integrity: sha512-vVimoUnGxlx4eLLQbZImdOZFOe+Zh+5ACntv8VxZuGP72LdWu5GV3oEmCahSEReBgRJoWjypFkrehSj7BWx1HQ==} engines: {node: '>=18.0.0'} - '@smithy/shared-ini-file-loader@4.4.8': - resolution: {integrity: sha512-VZCZx2bZasxdqxVgEAhREvDSlkatTPnkdWy1+Kiy8w7kYPBosW0V5IeDwzDUMvWBt56zpK658rx1cOBFOYaPaw==} + '@smithy/shared-ini-file-loader@4.4.9': + resolution: {integrity: sha512-495/V2I15SHgedSJoDPD23JuSfKAp726ZI1V0wtjB07Wh7q/0tri/0e0DLefZCHgxZonrGKt/OCTpAtP1wE1kQ==} engines: {node: '>=18.0.0'} - '@smithy/signature-v4@5.3.13': - resolution: {integrity: sha512-YpYSyM0vMDwKbHD/JA7bVOF6kToVRpa+FM5ateEVRpsTNu564g1muBlkTubXhSKKYXInhpADF46FPyrZcTLpXg==} + '@smithy/signature-v4@5.3.14': + resolution: {integrity: sha512-1D9Y/nmlVjCeSivCbhZ7hgEpmHyY1h0GvpSZt3l0xcD9JjmjVC1CHOozS6+Gh+/ldMH8JuJ6cujObQqfayAVFA==} engines: {node: '>=18.0.0'} - '@smithy/smithy-client@4.12.9': - resolution: {integrity: sha512-ovaLEcTU5olSeHcRXcxV6viaKtpkHZumn6Ps0yn7dRf2rRSfy794vpjOtrWDO0d1auDSvAqxO+lyhERSXQ03EQ==} + '@smithy/smithy-client@4.12.11': + resolution: {integrity: sha512-wzz/Wa1CH/Tlhxh0s4DQPEcXSxSVfJ59AZcUh9Gu0c6JTlKuwGf4o/3P2TExv0VbtPFt8odIBG+eQGK2+vTECg==} engines: {node: '>=18.0.0'} - '@smithy/types@4.14.0': - resolution: {integrity: sha512-OWgntFLW88kx2qvf/c/67Vno1yuXm/f9M7QFAtVkkO29IJXGBIg0ycEaBTH0kvCtwmvZxRujrgP5a86RvsXJAQ==} + '@smithy/types@4.14.1': + resolution: {integrity: sha512-59b5HtSVrVR/eYNei3BUj3DCPKD/G7EtDDe7OEJE7i7FtQFugYo6MxbotS8mVJkLNVf8gYaAlEBwwtJ9HzhWSg==} engines: {node: '>=18.0.0'} - '@smithy/url-parser@4.2.13': - resolution: {integrity: sha512-2G03yoboIRZlZze2+PT4GZEjgwQsJjUgn6iTsvxA02bVceHR6vp4Cuk7TUnPFWKF+ffNUk3kj4COwkENS2K3vw==} + '@smithy/url-parser@4.2.14': + resolution: {integrity: sha512-p06BiBigJ8bTA3MgnOfCtDUWnAMY0YfedO/GRpmc7p+wg3KW8vbXy1xwSu5ASy0wV7rRYtlfZOIKH4XqfhjSQQ==} engines: {node: '>=18.0.0'} '@smithy/util-base64@4.3.2': @@ -2140,32 +2140,32 @@ packages: resolution: {integrity: sha512-dWU03V3XUprJwaUIFVv4iOnS1FC9HnMHDfUrlNDSh4315v0cWyaIErP8KiqGVbf5z+JupoVpNM7ZB3jFiTejvQ==} engines: {node: '>=18.0.0'} - '@smithy/util-defaults-mode-browser@4.3.45': - resolution: {integrity: sha512-ag9sWc6/nWZAuK3Wm9KlFJUnRkXLrXn33RFjIAmCTFThqLHY+7wCst10BGq56FxslsDrjhSie46c8OULS+BiIw==} + '@smithy/util-defaults-mode-browser@4.3.47': + resolution: {integrity: sha512-zlIuXai3/SHjQUQ8y3g/woLvrH573SK2wNjcDaHu5e9VOcC0JwM1MI0Sq0GZJyN3BwSUneIhpjZ18nsiz5AtQw==} engines: {node: '>=18.0.0'} - '@smithy/util-defaults-mode-node@4.2.50': - resolution: {integrity: sha512-xpjncL5XozFA3No7WypTsPU1du0fFS8flIyO+Wh2nhCy7bpEapvU7BR55Bg+wrfw+1cRA+8G8UsTjaxgzrMzXg==} + '@smithy/util-defaults-mode-node@4.2.52': + resolution: {integrity: sha512-cQBz8g68Vnw1W2meXlkb3D/hXJU+Taiyj9P8qLJtjREEV9/Td65xi4A/H1sRQ8EIgX5qbZbvdYPKygKLholZ3w==} engines: {node: '>=18.0.0'} - '@smithy/util-endpoints@3.4.0': - resolution: {integrity: sha512-QQHGPKkw6NPcU6TJ1rNEEa201srPtZiX4k61xL163vvs9sTqW/XKz+UEuJ00uvPqoN+5Rs4Ka1UJ7+Mp03IXJw==} + '@smithy/util-endpoints@3.4.1': + resolution: {integrity: sha512-wMxNDZJrgS5mQV9oxCs4TWl5767VMgOfqfZ3JHyCkMtGC2ykW9iPqMvFur695Otcc5yxLG8OKO/80tsQBxrhXg==} engines: {node: '>=18.0.0'} '@smithy/util-hex-encoding@4.2.2': resolution: {integrity: sha512-Qcz3W5vuHK4sLQdyT93k/rfrUwdJ8/HZ+nMUOyGdpeGA1Wxt65zYwi3oEl9kOM+RswvYq90fzkNDahPS8K0OIg==} engines: {node: '>=18.0.0'} - '@smithy/util-middleware@4.2.13': - resolution: {integrity: sha512-GTooyrlmRTqvUen4eK7/K1p6kryF7bnDfq6XsAbIsf2mo51B/utaH+XThY6dKgNCWzMAaH/+OLmqaBuLhLWRow==} + '@smithy/util-middleware@4.2.14': + resolution: {integrity: sha512-1Su2vj9RYNDEv/V+2E+jXkkwGsgR7dc4sfHn9Z7ruzQHJIEni9zzw5CauvRXlFJfmgcqYP8fWa0dkh2Q2YaQyw==} engines: {node: '>=18.0.0'} - '@smithy/util-retry@4.3.1': - resolution: {integrity: sha512-FwmicpgWOkP5kZUjN3y+3JIom8NLGqSAJBeoIgK0rIToI817TEBHCrd0A2qGeKQlgDeP+Jzn4i0H/NLAXGy9uQ==} + '@smithy/util-retry@4.3.2': + resolution: {integrity: sha512-2+KTsJEwTi63NUv4uR9IQ+IFT1yu6Rf6JuoBK2WKaaJ/TRvOiOVGcXAsEqX/TQN2thR9yII21kPUJq1UV/WI2A==} engines: {node: '>=18.0.0'} - '@smithy/util-stream@4.5.22': - resolution: {integrity: sha512-3H8iq/0BfQjUs2/4fbHZ9aG9yNzcuZs24LPkcX1Q7Z+qpqaGM8+qbGmE8zo9m2nCRgamyvS98cHdcWvR6YUsew==} + '@smithy/util-stream@4.5.23': + resolution: {integrity: sha512-N6on1+ngJ3RznZOnDWNveIwnTSlqxNnXuNAh7ez889ZZaRdXoNRTXKgmYOLe6dB0gCmAVtuRScE1hymQFl4hpg==} engines: {node: '>=18.0.0'} '@smithy/util-uri-escape@4.2.2': @@ -2180,8 +2180,8 @@ packages: resolution: {integrity: sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw==} engines: {node: '>=18.0.0'} - '@smithy/util-waiter@4.2.15': - resolution: {integrity: sha512-oUt9o7n8hBv3BL56sLSneL0XeigZSuem0Hr78JaoK33D9oKieyCvVP8eTSe3j7g2mm/S1DvzxKieG7JEWNJUNg==} + '@smithy/util-waiter@4.2.16': + resolution: {integrity: sha512-GtclrKoZ3Lt7jPQ7aTIYKfjY92OgceScftVnkTsG8e1KV8rkvZgN+ny6YSRhd9hxB8rZtwVbmln7NTvE5O3GmQ==} engines: {node: '>=18.0.0'} '@smithy/uuid@1.1.2': @@ -3460,8 +3460,8 @@ packages: engines: {node: '>=0.10.0'} hasBin: true - electron-to-chromium@1.5.339: - resolution: {integrity: sha512-Is+0BBHJ4NrdpAYiperrmp53pLywG/yV/6lIMTAnhxvzj/Cmn5Q/ogSHC6AKe7X+8kPLxxFk0cs5oc/3j/fxIg==} + electron-to-chromium@1.5.340: + resolution: {integrity: sha512-908qahOGocRMinT2nM3ajCEM99H4iPdv84eagPP3FfZy/1ZGeOy2CZYzjhms81ckOPCXPlW7LkY4XpxD8r1DrA==} elegant-spinner@1.0.1: resolution: {integrity: sha512-B+ZM+RXvRqQaAmkMlO/oSe5nMUOaUnyfGYCEHoR8wrXsZR2mA0XVibsxV1bvTwxdRWah1PkQqso2EzhILGHtEQ==} @@ -3849,8 +3849,8 @@ packages: fast-uri@3.1.0: resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} - fast-xml-builder@1.1.4: - resolution: {integrity: sha512-f2jhpN4Eccy0/Uz9csxh3Nu6q4ErKxf0XIsasomfOihuSUa3/xw6w8dnOtCDgEItQFJG8KyXPzQXzcODDrrbOg==} + fast-xml-builder@1.1.5: + resolution: {integrity: sha512-4TJn/8FKLeslLAH3dnohXqE3QSoxkhvaMzepOIZytwJXZO69Bfz0HBdDHzOTOon6G59Zrk6VQ2bEiv1t61rfkA==} fast-xml-parser@5.5.8: resolution: {integrity: sha512-Z7Fh2nVQSb2d+poDViM063ix2ZGt9jmY1nWhPfHBOK2Hgnb/OW3P4Et3P/81SEej0J7QbWtJqxO05h8QYfK7LQ==} @@ -6522,20 +6522,20 @@ snapshots: '@aws-crypto/crc32@5.2.0': dependencies: '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.973.7 + '@aws-sdk/types': 3.973.8 tslib: 2.8.1 '@aws-crypto/crc32c@5.2.0': dependencies: '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.973.7 + '@aws-sdk/types': 3.973.8 tslib: 2.8.1 '@aws-crypto/sha1-browser@5.2.0': dependencies: '@aws-crypto/supports-web-crypto': 5.2.0 '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.973.7 + '@aws-sdk/types': 3.973.8 '@aws-sdk/util-locate-window': 3.965.5 '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 @@ -6545,7 +6545,7 @@ snapshots: '@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.973.7 + '@aws-sdk/types': 3.973.8 '@aws-sdk/util-locate-window': 3.965.5 '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 @@ -6553,7 +6553,7 @@ snapshots: '@aws-crypto/sha256-js@5.2.0': dependencies: '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.973.7 + '@aws-sdk/types': 3.973.8 tslib: 2.8.1 '@aws-crypto/supports-web-crypto@5.2.0': @@ -6562,7 +6562,7 @@ snapshots: '@aws-crypto/util@5.2.0': dependencies: - '@aws-sdk/types': 3.973.7 + '@aws-sdk/types': 3.973.8 '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 @@ -6570,44 +6570,44 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.973.27 - '@aws-sdk/credential-provider-node': 3.972.30 - '@aws-sdk/middleware-host-header': 3.972.9 - '@aws-sdk/middleware-logger': 3.972.9 - '@aws-sdk/middleware-recursion-detection': 3.972.10 - '@aws-sdk/middleware-user-agent': 3.972.29 - '@aws-sdk/region-config-resolver': 3.972.11 - '@aws-sdk/types': 3.973.7 - '@aws-sdk/util-endpoints': 3.996.6 - '@aws-sdk/util-user-agent-browser': 3.972.9 - '@aws-sdk/util-user-agent-node': 3.973.15 - '@smithy/config-resolver': 4.4.15 - '@smithy/core': 3.23.14 - '@smithy/fetch-http-handler': 5.3.16 - '@smithy/hash-node': 4.2.13 - '@smithy/invalid-dependency': 4.2.13 - '@smithy/middleware-content-length': 4.2.13 - '@smithy/middleware-endpoint': 4.4.29 - '@smithy/middleware-retry': 4.5.1 - '@smithy/middleware-serde': 4.2.17 - '@smithy/middleware-stack': 4.2.13 - '@smithy/node-config-provider': 4.3.13 - '@smithy/node-http-handler': 4.5.2 - '@smithy/protocol-http': 5.3.13 - '@smithy/smithy-client': 4.12.9 - '@smithy/types': 4.14.0 - '@smithy/url-parser': 4.2.13 + '@aws-sdk/core': 3.974.0 + '@aws-sdk/credential-provider-node': 3.972.31 + '@aws-sdk/middleware-host-header': 3.972.10 + '@aws-sdk/middleware-logger': 3.972.10 + '@aws-sdk/middleware-recursion-detection': 3.972.11 + '@aws-sdk/middleware-user-agent': 3.972.30 + '@aws-sdk/region-config-resolver': 3.972.12 + '@aws-sdk/types': 3.973.8 + '@aws-sdk/util-endpoints': 3.996.7 + '@aws-sdk/util-user-agent-browser': 3.972.10 + '@aws-sdk/util-user-agent-node': 3.973.16 + '@smithy/config-resolver': 4.4.16 + '@smithy/core': 3.23.15 + '@smithy/fetch-http-handler': 5.3.17 + '@smithy/hash-node': 4.2.14 + '@smithy/invalid-dependency': 4.2.14 + '@smithy/middleware-content-length': 4.2.14 + '@smithy/middleware-endpoint': 4.4.30 + '@smithy/middleware-retry': 4.5.3 + '@smithy/middleware-serde': 4.2.18 + '@smithy/middleware-stack': 4.2.14 + '@smithy/node-config-provider': 4.3.14 + '@smithy/node-http-handler': 4.5.3 + '@smithy/protocol-http': 5.3.14 + '@smithy/smithy-client': 4.12.11 + '@smithy/types': 4.14.1 + '@smithy/url-parser': 4.2.14 '@smithy/util-base64': 4.3.2 '@smithy/util-body-length-browser': 4.2.2 '@smithy/util-body-length-node': 4.2.3 - '@smithy/util-defaults-mode-browser': 4.3.45 - '@smithy/util-defaults-mode-node': 4.2.50 - '@smithy/util-endpoints': 3.4.0 - '@smithy/util-middleware': 4.2.13 - '@smithy/util-retry': 4.3.1 - '@smithy/util-stream': 4.5.22 + '@smithy/util-defaults-mode-browser': 4.3.47 + '@smithy/util-defaults-mode-node': 4.2.52 + '@smithy/util-endpoints': 3.4.1 + '@smithy/util-middleware': 4.2.14 + '@smithy/util-retry': 4.3.2 + '@smithy/util-stream': 4.5.23 '@smithy/util-utf8': 4.2.2 - '@smithy/util-waiter': 4.2.15 + '@smithy/util-waiter': 4.2.16 tslib: 2.8.1 transitivePeerDependencies: - aws-crt @@ -6617,393 +6617,393 @@ snapshots: '@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.973.27 - '@aws-sdk/credential-provider-node': 3.972.30 - '@aws-sdk/middleware-bucket-endpoint': 3.972.9 - '@aws-sdk/middleware-expect-continue': 3.972.9 - '@aws-sdk/middleware-flexible-checksums': 3.974.7 - '@aws-sdk/middleware-host-header': 3.972.9 - '@aws-sdk/middleware-location-constraint': 3.972.9 - '@aws-sdk/middleware-logger': 3.972.9 - '@aws-sdk/middleware-recursion-detection': 3.972.10 - '@aws-sdk/middleware-sdk-s3': 3.972.28 - '@aws-sdk/middleware-ssec': 3.972.9 - '@aws-sdk/middleware-user-agent': 3.972.29 - '@aws-sdk/region-config-resolver': 3.972.11 - '@aws-sdk/signature-v4-multi-region': 3.996.16 - '@aws-sdk/types': 3.973.7 - '@aws-sdk/util-endpoints': 3.996.6 - '@aws-sdk/util-user-agent-browser': 3.972.9 - '@aws-sdk/util-user-agent-node': 3.973.15 - '@smithy/config-resolver': 4.4.15 - '@smithy/core': 3.23.14 - '@smithy/eventstream-serde-browser': 4.2.13 - '@smithy/eventstream-serde-config-resolver': 4.3.13 - '@smithy/eventstream-serde-node': 4.2.13 - '@smithy/fetch-http-handler': 5.3.16 - '@smithy/hash-blob-browser': 4.2.14 - '@smithy/hash-node': 4.2.13 - '@smithy/hash-stream-node': 4.2.13 - '@smithy/invalid-dependency': 4.2.13 - '@smithy/md5-js': 4.2.13 - '@smithy/middleware-content-length': 4.2.13 - '@smithy/middleware-endpoint': 4.4.29 - '@smithy/middleware-retry': 4.5.1 - '@smithy/middleware-serde': 4.2.17 - '@smithy/middleware-stack': 4.2.13 - '@smithy/node-config-provider': 4.3.13 - '@smithy/node-http-handler': 4.5.2 - '@smithy/protocol-http': 5.3.13 - '@smithy/smithy-client': 4.12.9 - '@smithy/types': 4.14.0 - '@smithy/url-parser': 4.2.13 + '@aws-sdk/core': 3.974.0 + '@aws-sdk/credential-provider-node': 3.972.31 + '@aws-sdk/middleware-bucket-endpoint': 3.972.10 + '@aws-sdk/middleware-expect-continue': 3.972.10 + '@aws-sdk/middleware-flexible-checksums': 3.974.8 + '@aws-sdk/middleware-host-header': 3.972.10 + '@aws-sdk/middleware-location-constraint': 3.972.10 + '@aws-sdk/middleware-logger': 3.972.10 + '@aws-sdk/middleware-recursion-detection': 3.972.11 + '@aws-sdk/middleware-sdk-s3': 3.972.29 + '@aws-sdk/middleware-ssec': 3.972.10 + '@aws-sdk/middleware-user-agent': 3.972.30 + '@aws-sdk/region-config-resolver': 3.972.12 + '@aws-sdk/signature-v4-multi-region': 3.996.17 + '@aws-sdk/types': 3.973.8 + '@aws-sdk/util-endpoints': 3.996.7 + '@aws-sdk/util-user-agent-browser': 3.972.10 + '@aws-sdk/util-user-agent-node': 3.973.16 + '@smithy/config-resolver': 4.4.16 + '@smithy/core': 3.23.15 + '@smithy/eventstream-serde-browser': 4.2.14 + '@smithy/eventstream-serde-config-resolver': 4.3.14 + '@smithy/eventstream-serde-node': 4.2.14 + '@smithy/fetch-http-handler': 5.3.17 + '@smithy/hash-blob-browser': 4.2.15 + '@smithy/hash-node': 4.2.14 + '@smithy/hash-stream-node': 4.2.14 + '@smithy/invalid-dependency': 4.2.14 + '@smithy/md5-js': 4.2.14 + '@smithy/middleware-content-length': 4.2.14 + '@smithy/middleware-endpoint': 4.4.30 + '@smithy/middleware-retry': 4.5.3 + '@smithy/middleware-serde': 4.2.18 + '@smithy/middleware-stack': 4.2.14 + '@smithy/node-config-provider': 4.3.14 + '@smithy/node-http-handler': 4.5.3 + '@smithy/protocol-http': 5.3.14 + '@smithy/smithy-client': 4.12.11 + '@smithy/types': 4.14.1 + '@smithy/url-parser': 4.2.14 '@smithy/util-base64': 4.3.2 '@smithy/util-body-length-browser': 4.2.2 '@smithy/util-body-length-node': 4.2.3 - '@smithy/util-defaults-mode-browser': 4.3.45 - '@smithy/util-defaults-mode-node': 4.2.50 - '@smithy/util-endpoints': 3.4.0 - '@smithy/util-middleware': 4.2.13 - '@smithy/util-retry': 4.3.1 - '@smithy/util-stream': 4.5.22 + '@smithy/util-defaults-mode-browser': 4.3.47 + '@smithy/util-defaults-mode-node': 4.2.52 + '@smithy/util-endpoints': 3.4.1 + '@smithy/util-middleware': 4.2.14 + '@smithy/util-retry': 4.3.2 + '@smithy/util-stream': 4.5.23 '@smithy/util-utf8': 4.2.2 - '@smithy/util-waiter': 4.2.15 + '@smithy/util-waiter': 4.2.16 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/core@3.973.27': - dependencies: - '@aws-sdk/types': 3.973.7 - '@aws-sdk/xml-builder': 3.972.17 - '@smithy/core': 3.23.14 - '@smithy/node-config-provider': 4.3.13 - '@smithy/property-provider': 4.2.13 - '@smithy/protocol-http': 5.3.13 - '@smithy/signature-v4': 5.3.13 - '@smithy/smithy-client': 4.12.9 - '@smithy/types': 4.14.0 + '@aws-sdk/core@3.974.0': + dependencies: + '@aws-sdk/types': 3.973.8 + '@aws-sdk/xml-builder': 3.972.18 + '@smithy/core': 3.23.15 + '@smithy/node-config-provider': 4.3.14 + '@smithy/property-provider': 4.2.14 + '@smithy/protocol-http': 5.3.14 + '@smithy/signature-v4': 5.3.14 + '@smithy/smithy-client': 4.12.11 + '@smithy/types': 4.14.1 '@smithy/util-base64': 4.3.2 - '@smithy/util-middleware': 4.2.13 + '@smithy/util-middleware': 4.2.14 '@smithy/util-utf8': 4.2.2 tslib: 2.8.1 - '@aws-sdk/crc64-nvme@3.972.6': + '@aws-sdk/crc64-nvme@3.972.7': dependencies: - '@smithy/types': 4.14.0 + '@smithy/types': 4.14.1 tslib: 2.8.1 - '@aws-sdk/credential-provider-env@3.972.25': + '@aws-sdk/credential-provider-env@3.972.26': dependencies: - '@aws-sdk/core': 3.973.27 - '@aws-sdk/types': 3.973.7 - '@smithy/property-provider': 4.2.13 - '@smithy/types': 4.14.0 + '@aws-sdk/core': 3.974.0 + '@aws-sdk/types': 3.973.8 + '@smithy/property-provider': 4.2.14 + '@smithy/types': 4.14.1 tslib: 2.8.1 - '@aws-sdk/credential-provider-http@3.972.27': - dependencies: - '@aws-sdk/core': 3.973.27 - '@aws-sdk/types': 3.973.7 - '@smithy/fetch-http-handler': 5.3.16 - '@smithy/node-http-handler': 4.5.2 - '@smithy/property-provider': 4.2.13 - '@smithy/protocol-http': 5.3.13 - '@smithy/smithy-client': 4.12.9 - '@smithy/types': 4.14.0 - '@smithy/util-stream': 4.5.22 + '@aws-sdk/credential-provider-http@3.972.28': + dependencies: + '@aws-sdk/core': 3.974.0 + '@aws-sdk/types': 3.973.8 + '@smithy/fetch-http-handler': 5.3.17 + '@smithy/node-http-handler': 4.5.3 + '@smithy/property-provider': 4.2.14 + '@smithy/protocol-http': 5.3.14 + '@smithy/smithy-client': 4.12.11 + '@smithy/types': 4.14.1 + '@smithy/util-stream': 4.5.23 tslib: 2.8.1 - '@aws-sdk/credential-provider-ini@3.972.29': - dependencies: - '@aws-sdk/core': 3.973.27 - '@aws-sdk/credential-provider-env': 3.972.25 - '@aws-sdk/credential-provider-http': 3.972.27 - '@aws-sdk/credential-provider-login': 3.972.29 - '@aws-sdk/credential-provider-process': 3.972.25 - '@aws-sdk/credential-provider-sso': 3.972.29 - '@aws-sdk/credential-provider-web-identity': 3.972.29 - '@aws-sdk/nested-clients': 3.996.19 - '@aws-sdk/types': 3.973.7 - '@smithy/credential-provider-imds': 4.2.13 - '@smithy/property-provider': 4.2.13 - '@smithy/shared-ini-file-loader': 4.4.8 - '@smithy/types': 4.14.0 + '@aws-sdk/credential-provider-ini@3.972.30': + dependencies: + '@aws-sdk/core': 3.974.0 + '@aws-sdk/credential-provider-env': 3.972.26 + '@aws-sdk/credential-provider-http': 3.972.28 + '@aws-sdk/credential-provider-login': 3.972.30 + '@aws-sdk/credential-provider-process': 3.972.26 + '@aws-sdk/credential-provider-sso': 3.972.30 + '@aws-sdk/credential-provider-web-identity': 3.972.30 + '@aws-sdk/nested-clients': 3.996.20 + '@aws-sdk/types': 3.973.8 + '@smithy/credential-provider-imds': 4.2.14 + '@smithy/property-provider': 4.2.14 + '@smithy/shared-ini-file-loader': 4.4.9 + '@smithy/types': 4.14.1 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-login@3.972.29': + '@aws-sdk/credential-provider-login@3.972.30': dependencies: - '@aws-sdk/core': 3.973.27 - '@aws-sdk/nested-clients': 3.996.19 - '@aws-sdk/types': 3.973.7 - '@smithy/property-provider': 4.2.13 - '@smithy/protocol-http': 5.3.13 - '@smithy/shared-ini-file-loader': 4.4.8 - '@smithy/types': 4.14.0 + '@aws-sdk/core': 3.974.0 + '@aws-sdk/nested-clients': 3.996.20 + '@aws-sdk/types': 3.973.8 + '@smithy/property-provider': 4.2.14 + '@smithy/protocol-http': 5.3.14 + '@smithy/shared-ini-file-loader': 4.4.9 + '@smithy/types': 4.14.1 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-node@3.972.30': - dependencies: - '@aws-sdk/credential-provider-env': 3.972.25 - '@aws-sdk/credential-provider-http': 3.972.27 - '@aws-sdk/credential-provider-ini': 3.972.29 - '@aws-sdk/credential-provider-process': 3.972.25 - '@aws-sdk/credential-provider-sso': 3.972.29 - '@aws-sdk/credential-provider-web-identity': 3.972.29 - '@aws-sdk/types': 3.973.7 - '@smithy/credential-provider-imds': 4.2.13 - '@smithy/property-provider': 4.2.13 - '@smithy/shared-ini-file-loader': 4.4.8 - '@smithy/types': 4.14.0 + '@aws-sdk/credential-provider-node@3.972.31': + dependencies: + '@aws-sdk/credential-provider-env': 3.972.26 + '@aws-sdk/credential-provider-http': 3.972.28 + '@aws-sdk/credential-provider-ini': 3.972.30 + '@aws-sdk/credential-provider-process': 3.972.26 + '@aws-sdk/credential-provider-sso': 3.972.30 + '@aws-sdk/credential-provider-web-identity': 3.972.30 + '@aws-sdk/types': 3.973.8 + '@smithy/credential-provider-imds': 4.2.14 + '@smithy/property-provider': 4.2.14 + '@smithy/shared-ini-file-loader': 4.4.9 + '@smithy/types': 4.14.1 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-process@3.972.25': + '@aws-sdk/credential-provider-process@3.972.26': dependencies: - '@aws-sdk/core': 3.973.27 - '@aws-sdk/types': 3.973.7 - '@smithy/property-provider': 4.2.13 - '@smithy/shared-ini-file-loader': 4.4.8 - '@smithy/types': 4.14.0 + '@aws-sdk/core': 3.974.0 + '@aws-sdk/types': 3.973.8 + '@smithy/property-provider': 4.2.14 + '@smithy/shared-ini-file-loader': 4.4.9 + '@smithy/types': 4.14.1 tslib: 2.8.1 - '@aws-sdk/credential-provider-sso@3.972.29': + '@aws-sdk/credential-provider-sso@3.972.30': dependencies: - '@aws-sdk/core': 3.973.27 - '@aws-sdk/nested-clients': 3.996.19 - '@aws-sdk/token-providers': 3.1026.0 - '@aws-sdk/types': 3.973.7 - '@smithy/property-provider': 4.2.13 - '@smithy/shared-ini-file-loader': 4.4.8 - '@smithy/types': 4.14.0 + '@aws-sdk/core': 3.974.0 + '@aws-sdk/nested-clients': 3.996.20 + '@aws-sdk/token-providers': 3.1031.0 + '@aws-sdk/types': 3.973.8 + '@smithy/property-provider': 4.2.14 + '@smithy/shared-ini-file-loader': 4.4.9 + '@smithy/types': 4.14.1 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-web-identity@3.972.29': + '@aws-sdk/credential-provider-web-identity@3.972.30': dependencies: - '@aws-sdk/core': 3.973.27 - '@aws-sdk/nested-clients': 3.996.19 - '@aws-sdk/types': 3.973.7 - '@smithy/property-provider': 4.2.13 - '@smithy/shared-ini-file-loader': 4.4.8 - '@smithy/types': 4.14.0 + '@aws-sdk/core': 3.974.0 + '@aws-sdk/nested-clients': 3.996.20 + '@aws-sdk/types': 3.973.8 + '@smithy/property-provider': 4.2.14 + '@smithy/shared-ini-file-loader': 4.4.9 + '@smithy/types': 4.14.1 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/middleware-bucket-endpoint@3.972.9': + '@aws-sdk/middleware-bucket-endpoint@3.972.10': dependencies: - '@aws-sdk/types': 3.973.7 + '@aws-sdk/types': 3.973.8 '@aws-sdk/util-arn-parser': 3.972.3 - '@smithy/node-config-provider': 4.3.13 - '@smithy/protocol-http': 5.3.13 - '@smithy/types': 4.14.0 + '@smithy/node-config-provider': 4.3.14 + '@smithy/protocol-http': 5.3.14 + '@smithy/types': 4.14.1 '@smithy/util-config-provider': 4.2.2 tslib: 2.8.1 - '@aws-sdk/middleware-expect-continue@3.972.9': + '@aws-sdk/middleware-expect-continue@3.972.10': dependencies: - '@aws-sdk/types': 3.973.7 - '@smithy/protocol-http': 5.3.13 - '@smithy/types': 4.14.0 + '@aws-sdk/types': 3.973.8 + '@smithy/protocol-http': 5.3.14 + '@smithy/types': 4.14.1 tslib: 2.8.1 - '@aws-sdk/middleware-flexible-checksums@3.974.7': + '@aws-sdk/middleware-flexible-checksums@3.974.8': dependencies: '@aws-crypto/crc32': 5.2.0 '@aws-crypto/crc32c': 5.2.0 '@aws-crypto/util': 5.2.0 - '@aws-sdk/core': 3.973.27 - '@aws-sdk/crc64-nvme': 3.972.6 - '@aws-sdk/types': 3.973.7 + '@aws-sdk/core': 3.974.0 + '@aws-sdk/crc64-nvme': 3.972.7 + '@aws-sdk/types': 3.973.8 '@smithy/is-array-buffer': 4.2.2 - '@smithy/node-config-provider': 4.3.13 - '@smithy/protocol-http': 5.3.13 - '@smithy/types': 4.14.0 - '@smithy/util-middleware': 4.2.13 - '@smithy/util-stream': 4.5.22 + '@smithy/node-config-provider': 4.3.14 + '@smithy/protocol-http': 5.3.14 + '@smithy/types': 4.14.1 + '@smithy/util-middleware': 4.2.14 + '@smithy/util-stream': 4.5.23 '@smithy/util-utf8': 4.2.2 tslib: 2.8.1 - '@aws-sdk/middleware-host-header@3.972.9': + '@aws-sdk/middleware-host-header@3.972.10': dependencies: - '@aws-sdk/types': 3.973.7 - '@smithy/protocol-http': 5.3.13 - '@smithy/types': 4.14.0 + '@aws-sdk/types': 3.973.8 + '@smithy/protocol-http': 5.3.14 + '@smithy/types': 4.14.1 tslib: 2.8.1 - '@aws-sdk/middleware-location-constraint@3.972.9': + '@aws-sdk/middleware-location-constraint@3.972.10': dependencies: - '@aws-sdk/types': 3.973.7 - '@smithy/types': 4.14.0 + '@aws-sdk/types': 3.973.8 + '@smithy/types': 4.14.1 tslib: 2.8.1 - '@aws-sdk/middleware-logger@3.972.9': + '@aws-sdk/middleware-logger@3.972.10': dependencies: - '@aws-sdk/types': 3.973.7 - '@smithy/types': 4.14.0 + '@aws-sdk/types': 3.973.8 + '@smithy/types': 4.14.1 tslib: 2.8.1 - '@aws-sdk/middleware-recursion-detection@3.972.10': + '@aws-sdk/middleware-recursion-detection@3.972.11': dependencies: - '@aws-sdk/types': 3.973.7 + '@aws-sdk/types': 3.973.8 '@aws/lambda-invoke-store': 0.2.4 - '@smithy/protocol-http': 5.3.13 - '@smithy/types': 4.14.0 + '@smithy/protocol-http': 5.3.14 + '@smithy/types': 4.14.1 tslib: 2.8.1 - '@aws-sdk/middleware-sdk-s3@3.972.28': + '@aws-sdk/middleware-sdk-s3@3.972.29': dependencies: - '@aws-sdk/core': 3.973.27 - '@aws-sdk/types': 3.973.7 + '@aws-sdk/core': 3.974.0 + '@aws-sdk/types': 3.973.8 '@aws-sdk/util-arn-parser': 3.972.3 - '@smithy/core': 3.23.14 - '@smithy/node-config-provider': 4.3.13 - '@smithy/protocol-http': 5.3.13 - '@smithy/signature-v4': 5.3.13 - '@smithy/smithy-client': 4.12.9 - '@smithy/types': 4.14.0 + '@smithy/core': 3.23.15 + '@smithy/node-config-provider': 4.3.14 + '@smithy/protocol-http': 5.3.14 + '@smithy/signature-v4': 5.3.14 + '@smithy/smithy-client': 4.12.11 + '@smithy/types': 4.14.1 '@smithy/util-config-provider': 4.2.2 - '@smithy/util-middleware': 4.2.13 - '@smithy/util-stream': 4.5.22 + '@smithy/util-middleware': 4.2.14 + '@smithy/util-stream': 4.5.23 '@smithy/util-utf8': 4.2.2 tslib: 2.8.1 - '@aws-sdk/middleware-ssec@3.972.9': + '@aws-sdk/middleware-ssec@3.972.10': dependencies: - '@aws-sdk/types': 3.973.7 - '@smithy/types': 4.14.0 + '@aws-sdk/types': 3.973.8 + '@smithy/types': 4.14.1 tslib: 2.8.1 - '@aws-sdk/middleware-user-agent@3.972.29': + '@aws-sdk/middleware-user-agent@3.972.30': dependencies: - '@aws-sdk/core': 3.973.27 - '@aws-sdk/types': 3.973.7 - '@aws-sdk/util-endpoints': 3.996.6 - '@smithy/core': 3.23.14 - '@smithy/protocol-http': 5.3.13 - '@smithy/types': 4.14.0 - '@smithy/util-retry': 4.3.1 + '@aws-sdk/core': 3.974.0 + '@aws-sdk/types': 3.973.8 + '@aws-sdk/util-endpoints': 3.996.7 + '@smithy/core': 3.23.15 + '@smithy/protocol-http': 5.3.14 + '@smithy/types': 4.14.1 + '@smithy/util-retry': 4.3.2 tslib: 2.8.1 - '@aws-sdk/nested-clients@3.996.19': + '@aws-sdk/nested-clients@3.996.20': dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.973.27 - '@aws-sdk/middleware-host-header': 3.972.9 - '@aws-sdk/middleware-logger': 3.972.9 - '@aws-sdk/middleware-recursion-detection': 3.972.10 - '@aws-sdk/middleware-user-agent': 3.972.29 - '@aws-sdk/region-config-resolver': 3.972.11 - '@aws-sdk/types': 3.973.7 - '@aws-sdk/util-endpoints': 3.996.6 - '@aws-sdk/util-user-agent-browser': 3.972.9 - '@aws-sdk/util-user-agent-node': 3.973.15 - '@smithy/config-resolver': 4.4.15 - '@smithy/core': 3.23.14 - '@smithy/fetch-http-handler': 5.3.16 - '@smithy/hash-node': 4.2.13 - '@smithy/invalid-dependency': 4.2.13 - '@smithy/middleware-content-length': 4.2.13 - '@smithy/middleware-endpoint': 4.4.29 - '@smithy/middleware-retry': 4.5.1 - '@smithy/middleware-serde': 4.2.17 - '@smithy/middleware-stack': 4.2.13 - '@smithy/node-config-provider': 4.3.13 - '@smithy/node-http-handler': 4.5.2 - '@smithy/protocol-http': 5.3.13 - '@smithy/smithy-client': 4.12.9 - '@smithy/types': 4.14.0 - '@smithy/url-parser': 4.2.13 + '@aws-sdk/core': 3.974.0 + '@aws-sdk/middleware-host-header': 3.972.10 + '@aws-sdk/middleware-logger': 3.972.10 + '@aws-sdk/middleware-recursion-detection': 3.972.11 + '@aws-sdk/middleware-user-agent': 3.972.30 + '@aws-sdk/region-config-resolver': 3.972.12 + '@aws-sdk/types': 3.973.8 + '@aws-sdk/util-endpoints': 3.996.7 + '@aws-sdk/util-user-agent-browser': 3.972.10 + '@aws-sdk/util-user-agent-node': 3.973.16 + '@smithy/config-resolver': 4.4.16 + '@smithy/core': 3.23.15 + '@smithy/fetch-http-handler': 5.3.17 + '@smithy/hash-node': 4.2.14 + '@smithy/invalid-dependency': 4.2.14 + '@smithy/middleware-content-length': 4.2.14 + '@smithy/middleware-endpoint': 4.4.30 + '@smithy/middleware-retry': 4.5.3 + '@smithy/middleware-serde': 4.2.18 + '@smithy/middleware-stack': 4.2.14 + '@smithy/node-config-provider': 4.3.14 + '@smithy/node-http-handler': 4.5.3 + '@smithy/protocol-http': 5.3.14 + '@smithy/smithy-client': 4.12.11 + '@smithy/types': 4.14.1 + '@smithy/url-parser': 4.2.14 '@smithy/util-base64': 4.3.2 '@smithy/util-body-length-browser': 4.2.2 '@smithy/util-body-length-node': 4.2.3 - '@smithy/util-defaults-mode-browser': 4.3.45 - '@smithy/util-defaults-mode-node': 4.2.50 - '@smithy/util-endpoints': 3.4.0 - '@smithy/util-middleware': 4.2.13 - '@smithy/util-retry': 4.3.1 + '@smithy/util-defaults-mode-browser': 4.3.47 + '@smithy/util-defaults-mode-node': 4.2.52 + '@smithy/util-endpoints': 3.4.1 + '@smithy/util-middleware': 4.2.14 + '@smithy/util-retry': 4.3.2 '@smithy/util-utf8': 4.2.2 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/region-config-resolver@3.972.11': + '@aws-sdk/region-config-resolver@3.972.12': dependencies: - '@aws-sdk/types': 3.973.7 - '@smithy/config-resolver': 4.4.15 - '@smithy/node-config-provider': 4.3.13 - '@smithy/types': 4.14.0 + '@aws-sdk/types': 3.973.8 + '@smithy/config-resolver': 4.4.16 + '@smithy/node-config-provider': 4.3.14 + '@smithy/types': 4.14.1 tslib: 2.8.1 - '@aws-sdk/signature-v4-multi-region@3.996.16': + '@aws-sdk/signature-v4-multi-region@3.996.17': dependencies: - '@aws-sdk/middleware-sdk-s3': 3.972.28 - '@aws-sdk/types': 3.973.7 - '@smithy/protocol-http': 5.3.13 - '@smithy/signature-v4': 5.3.13 - '@smithy/types': 4.14.0 + '@aws-sdk/middleware-sdk-s3': 3.972.29 + '@aws-sdk/types': 3.973.8 + '@smithy/protocol-http': 5.3.14 + '@smithy/signature-v4': 5.3.14 + '@smithy/types': 4.14.1 tslib: 2.8.1 - '@aws-sdk/token-providers@3.1026.0': + '@aws-sdk/token-providers@3.1031.0': dependencies: - '@aws-sdk/core': 3.973.27 - '@aws-sdk/nested-clients': 3.996.19 - '@aws-sdk/types': 3.973.7 - '@smithy/property-provider': 4.2.13 - '@smithy/shared-ini-file-loader': 4.4.8 - '@smithy/types': 4.14.0 + '@aws-sdk/core': 3.974.0 + '@aws-sdk/nested-clients': 3.996.20 + '@aws-sdk/types': 3.973.8 + '@smithy/property-provider': 4.2.14 + '@smithy/shared-ini-file-loader': 4.4.9 + '@smithy/types': 4.14.1 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/types@3.973.7': + '@aws-sdk/types@3.973.8': dependencies: - '@smithy/types': 4.14.0 + '@smithy/types': 4.14.1 tslib: 2.8.1 '@aws-sdk/util-arn-parser@3.972.3': dependencies: tslib: 2.8.1 - '@aws-sdk/util-endpoints@3.996.6': + '@aws-sdk/util-endpoints@3.996.7': dependencies: - '@aws-sdk/types': 3.973.7 - '@smithy/types': 4.14.0 - '@smithy/url-parser': 4.2.13 - '@smithy/util-endpoints': 3.4.0 + '@aws-sdk/types': 3.973.8 + '@smithy/types': 4.14.1 + '@smithy/url-parser': 4.2.14 + '@smithy/util-endpoints': 3.4.1 tslib: 2.8.1 '@aws-sdk/util-locate-window@3.965.5': dependencies: tslib: 2.8.1 - '@aws-sdk/util-user-agent-browser@3.972.9': + '@aws-sdk/util-user-agent-browser@3.972.10': dependencies: - '@aws-sdk/types': 3.973.7 - '@smithy/types': 4.14.0 + '@aws-sdk/types': 3.973.8 + '@smithy/types': 4.14.1 bowser: 2.14.1 tslib: 2.8.1 - '@aws-sdk/util-user-agent-node@3.973.15': + '@aws-sdk/util-user-agent-node@3.973.16': dependencies: - '@aws-sdk/middleware-user-agent': 3.972.29 - '@aws-sdk/types': 3.973.7 - '@smithy/node-config-provider': 4.3.13 - '@smithy/types': 4.14.0 + '@aws-sdk/middleware-user-agent': 3.972.30 + '@aws-sdk/types': 3.973.8 + '@smithy/node-config-provider': 4.3.14 + '@smithy/types': 4.14.1 '@smithy/util-config-provider': 4.2.2 tslib: 2.8.1 - '@aws-sdk/xml-builder@3.972.17': + '@aws-sdk/xml-builder@3.972.18': dependencies: - '@smithy/types': 4.14.0 + '@smithy/types': 4.14.1 fast-xml-parser: 5.5.8 tslib: 2.8.1 @@ -8704,97 +8704,97 @@ snapshots: dependencies: tslib: 2.8.1 - '@smithy/config-resolver@4.4.15': + '@smithy/config-resolver@4.4.16': dependencies: - '@smithy/node-config-provider': 4.3.13 - '@smithy/types': 4.14.0 + '@smithy/node-config-provider': 4.3.14 + '@smithy/types': 4.14.1 '@smithy/util-config-provider': 4.2.2 - '@smithy/util-endpoints': 3.4.0 - '@smithy/util-middleware': 4.2.13 + '@smithy/util-endpoints': 3.4.1 + '@smithy/util-middleware': 4.2.14 tslib: 2.8.1 - '@smithy/core@3.23.14': + '@smithy/core@3.23.15': dependencies: - '@smithy/protocol-http': 5.3.13 - '@smithy/types': 4.14.0 - '@smithy/url-parser': 4.2.13 + '@smithy/protocol-http': 5.3.14 + '@smithy/types': 4.14.1 + '@smithy/url-parser': 4.2.14 '@smithy/util-base64': 4.3.2 '@smithy/util-body-length-browser': 4.2.2 - '@smithy/util-middleware': 4.2.13 - '@smithy/util-stream': 4.5.22 + '@smithy/util-middleware': 4.2.14 + '@smithy/util-stream': 4.5.23 '@smithy/util-utf8': 4.2.2 '@smithy/uuid': 1.1.2 tslib: 2.8.1 - '@smithy/credential-provider-imds@4.2.13': + '@smithy/credential-provider-imds@4.2.14': dependencies: - '@smithy/node-config-provider': 4.3.13 - '@smithy/property-provider': 4.2.13 - '@smithy/types': 4.14.0 - '@smithy/url-parser': 4.2.13 + '@smithy/node-config-provider': 4.3.14 + '@smithy/property-provider': 4.2.14 + '@smithy/types': 4.14.1 + '@smithy/url-parser': 4.2.14 tslib: 2.8.1 - '@smithy/eventstream-codec@4.2.13': + '@smithy/eventstream-codec@4.2.14': dependencies: '@aws-crypto/crc32': 5.2.0 - '@smithy/types': 4.14.0 + '@smithy/types': 4.14.1 '@smithy/util-hex-encoding': 4.2.2 tslib: 2.8.1 - '@smithy/eventstream-serde-browser@4.2.13': + '@smithy/eventstream-serde-browser@4.2.14': dependencies: - '@smithy/eventstream-serde-universal': 4.2.13 - '@smithy/types': 4.14.0 + '@smithy/eventstream-serde-universal': 4.2.14 + '@smithy/types': 4.14.1 tslib: 2.8.1 - '@smithy/eventstream-serde-config-resolver@4.3.13': + '@smithy/eventstream-serde-config-resolver@4.3.14': dependencies: - '@smithy/types': 4.14.0 + '@smithy/types': 4.14.1 tslib: 2.8.1 - '@smithy/eventstream-serde-node@4.2.13': + '@smithy/eventstream-serde-node@4.2.14': dependencies: - '@smithy/eventstream-serde-universal': 4.2.13 - '@smithy/types': 4.14.0 + '@smithy/eventstream-serde-universal': 4.2.14 + '@smithy/types': 4.14.1 tslib: 2.8.1 - '@smithy/eventstream-serde-universal@4.2.13': + '@smithy/eventstream-serde-universal@4.2.14': dependencies: - '@smithy/eventstream-codec': 4.2.13 - '@smithy/types': 4.14.0 + '@smithy/eventstream-codec': 4.2.14 + '@smithy/types': 4.14.1 tslib: 2.8.1 - '@smithy/fetch-http-handler@5.3.16': + '@smithy/fetch-http-handler@5.3.17': dependencies: - '@smithy/protocol-http': 5.3.13 - '@smithy/querystring-builder': 4.2.13 - '@smithy/types': 4.14.0 + '@smithy/protocol-http': 5.3.14 + '@smithy/querystring-builder': 4.2.14 + '@smithy/types': 4.14.1 '@smithy/util-base64': 4.3.2 tslib: 2.8.1 - '@smithy/hash-blob-browser@4.2.14': + '@smithy/hash-blob-browser@4.2.15': dependencies: '@smithy/chunked-blob-reader': 5.2.2 '@smithy/chunked-blob-reader-native': 4.2.3 - '@smithy/types': 4.14.0 + '@smithy/types': 4.14.1 tslib: 2.8.1 - '@smithy/hash-node@4.2.13': + '@smithy/hash-node@4.2.14': dependencies: - '@smithy/types': 4.14.0 + '@smithy/types': 4.14.1 '@smithy/util-buffer-from': 4.2.2 '@smithy/util-utf8': 4.2.2 tslib: 2.8.1 - '@smithy/hash-stream-node@4.2.13': + '@smithy/hash-stream-node@4.2.14': dependencies: - '@smithy/types': 4.14.0 + '@smithy/types': 4.14.1 '@smithy/util-utf8': 4.2.2 tslib: 2.8.1 - '@smithy/invalid-dependency@4.2.13': + '@smithy/invalid-dependency@4.2.14': dependencies: - '@smithy/types': 4.14.0 + '@smithy/types': 4.14.1 tslib: 2.8.1 '@smithy/is-array-buffer@2.2.0': @@ -8805,127 +8805,127 @@ snapshots: dependencies: tslib: 2.8.1 - '@smithy/md5-js@4.2.13': + '@smithy/md5-js@4.2.14': dependencies: - '@smithy/types': 4.14.0 + '@smithy/types': 4.14.1 '@smithy/util-utf8': 4.2.2 tslib: 2.8.1 - '@smithy/middleware-content-length@4.2.13': + '@smithy/middleware-content-length@4.2.14': dependencies: - '@smithy/protocol-http': 5.3.13 - '@smithy/types': 4.14.0 + '@smithy/protocol-http': 5.3.14 + '@smithy/types': 4.14.1 tslib: 2.8.1 - '@smithy/middleware-endpoint@4.4.29': + '@smithy/middleware-endpoint@4.4.30': dependencies: - '@smithy/core': 3.23.14 - '@smithy/middleware-serde': 4.2.17 - '@smithy/node-config-provider': 4.3.13 - '@smithy/shared-ini-file-loader': 4.4.8 - '@smithy/types': 4.14.0 - '@smithy/url-parser': 4.2.13 - '@smithy/util-middleware': 4.2.13 + '@smithy/core': 3.23.15 + '@smithy/middleware-serde': 4.2.18 + '@smithy/node-config-provider': 4.3.14 + '@smithy/shared-ini-file-loader': 4.4.9 + '@smithy/types': 4.14.1 + '@smithy/url-parser': 4.2.14 + '@smithy/util-middleware': 4.2.14 tslib: 2.8.1 - '@smithy/middleware-retry@4.5.1': + '@smithy/middleware-retry@4.5.3': dependencies: - '@smithy/core': 3.23.14 - '@smithy/node-config-provider': 4.3.13 - '@smithy/protocol-http': 5.3.13 - '@smithy/service-error-classification': 4.2.13 - '@smithy/smithy-client': 4.12.9 - '@smithy/types': 4.14.0 - '@smithy/util-middleware': 4.2.13 - '@smithy/util-retry': 4.3.1 + '@smithy/core': 3.23.15 + '@smithy/node-config-provider': 4.3.14 + '@smithy/protocol-http': 5.3.14 + '@smithy/service-error-classification': 4.2.14 + '@smithy/smithy-client': 4.12.11 + '@smithy/types': 4.14.1 + '@smithy/util-middleware': 4.2.14 + '@smithy/util-retry': 4.3.2 '@smithy/uuid': 1.1.2 tslib: 2.8.1 - '@smithy/middleware-serde@4.2.17': + '@smithy/middleware-serde@4.2.18': dependencies: - '@smithy/core': 3.23.14 - '@smithy/protocol-http': 5.3.13 - '@smithy/types': 4.14.0 + '@smithy/core': 3.23.15 + '@smithy/protocol-http': 5.3.14 + '@smithy/types': 4.14.1 tslib: 2.8.1 - '@smithy/middleware-stack@4.2.13': + '@smithy/middleware-stack@4.2.14': dependencies: - '@smithy/types': 4.14.0 + '@smithy/types': 4.14.1 tslib: 2.8.1 - '@smithy/node-config-provider@4.3.13': + '@smithy/node-config-provider@4.3.14': dependencies: - '@smithy/property-provider': 4.2.13 - '@smithy/shared-ini-file-loader': 4.4.8 - '@smithy/types': 4.14.0 + '@smithy/property-provider': 4.2.14 + '@smithy/shared-ini-file-loader': 4.4.9 + '@smithy/types': 4.14.1 tslib: 2.8.1 - '@smithy/node-http-handler@4.5.2': + '@smithy/node-http-handler@4.5.3': dependencies: - '@smithy/protocol-http': 5.3.13 - '@smithy/querystring-builder': 4.2.13 - '@smithy/types': 4.14.0 + '@smithy/protocol-http': 5.3.14 + '@smithy/querystring-builder': 4.2.14 + '@smithy/types': 4.14.1 tslib: 2.8.1 - '@smithy/property-provider@4.2.13': + '@smithy/property-provider@4.2.14': dependencies: - '@smithy/types': 4.14.0 + '@smithy/types': 4.14.1 tslib: 2.8.1 - '@smithy/protocol-http@5.3.13': + '@smithy/protocol-http@5.3.14': dependencies: - '@smithy/types': 4.14.0 + '@smithy/types': 4.14.1 tslib: 2.8.1 - '@smithy/querystring-builder@4.2.13': + '@smithy/querystring-builder@4.2.14': dependencies: - '@smithy/types': 4.14.0 + '@smithy/types': 4.14.1 '@smithy/util-uri-escape': 4.2.2 tslib: 2.8.1 - '@smithy/querystring-parser@4.2.13': + '@smithy/querystring-parser@4.2.14': dependencies: - '@smithy/types': 4.14.0 + '@smithy/types': 4.14.1 tslib: 2.8.1 - '@smithy/service-error-classification@4.2.13': + '@smithy/service-error-classification@4.2.14': dependencies: - '@smithy/types': 4.14.0 + '@smithy/types': 4.14.1 - '@smithy/shared-ini-file-loader@4.4.8': + '@smithy/shared-ini-file-loader@4.4.9': dependencies: - '@smithy/types': 4.14.0 + '@smithy/types': 4.14.1 tslib: 2.8.1 - '@smithy/signature-v4@5.3.13': + '@smithy/signature-v4@5.3.14': dependencies: '@smithy/is-array-buffer': 4.2.2 - '@smithy/protocol-http': 5.3.13 - '@smithy/types': 4.14.0 + '@smithy/protocol-http': 5.3.14 + '@smithy/types': 4.14.1 '@smithy/util-hex-encoding': 4.2.2 - '@smithy/util-middleware': 4.2.13 + '@smithy/util-middleware': 4.2.14 '@smithy/util-uri-escape': 4.2.2 '@smithy/util-utf8': 4.2.2 tslib: 2.8.1 - '@smithy/smithy-client@4.12.9': + '@smithy/smithy-client@4.12.11': dependencies: - '@smithy/core': 3.23.14 - '@smithy/middleware-endpoint': 4.4.29 - '@smithy/middleware-stack': 4.2.13 - '@smithy/protocol-http': 5.3.13 - '@smithy/types': 4.14.0 - '@smithy/util-stream': 4.5.22 + '@smithy/core': 3.23.15 + '@smithy/middleware-endpoint': 4.4.30 + '@smithy/middleware-stack': 4.2.14 + '@smithy/protocol-http': 5.3.14 + '@smithy/types': 4.14.1 + '@smithy/util-stream': 4.5.23 tslib: 2.8.1 - '@smithy/types@4.14.0': + '@smithy/types@4.14.1': dependencies: tslib: 2.8.1 - '@smithy/url-parser@4.2.13': + '@smithy/url-parser@4.2.14': dependencies: - '@smithy/querystring-parser': 4.2.13 - '@smithy/types': 4.14.0 + '@smithy/querystring-parser': 4.2.14 + '@smithy/types': 4.14.1 tslib: 2.8.1 '@smithy/util-base64@4.3.2': @@ -8956,49 +8956,49 @@ snapshots: dependencies: tslib: 2.8.1 - '@smithy/util-defaults-mode-browser@4.3.45': + '@smithy/util-defaults-mode-browser@4.3.47': dependencies: - '@smithy/property-provider': 4.2.13 - '@smithy/smithy-client': 4.12.9 - '@smithy/types': 4.14.0 + '@smithy/property-provider': 4.2.14 + '@smithy/smithy-client': 4.12.11 + '@smithy/types': 4.14.1 tslib: 2.8.1 - '@smithy/util-defaults-mode-node@4.2.50': + '@smithy/util-defaults-mode-node@4.2.52': dependencies: - '@smithy/config-resolver': 4.4.15 - '@smithy/credential-provider-imds': 4.2.13 - '@smithy/node-config-provider': 4.3.13 - '@smithy/property-provider': 4.2.13 - '@smithy/smithy-client': 4.12.9 - '@smithy/types': 4.14.0 + '@smithy/config-resolver': 4.4.16 + '@smithy/credential-provider-imds': 4.2.14 + '@smithy/node-config-provider': 4.3.14 + '@smithy/property-provider': 4.2.14 + '@smithy/smithy-client': 4.12.11 + '@smithy/types': 4.14.1 tslib: 2.8.1 - '@smithy/util-endpoints@3.4.0': + '@smithy/util-endpoints@3.4.1': dependencies: - '@smithy/node-config-provider': 4.3.13 - '@smithy/types': 4.14.0 + '@smithy/node-config-provider': 4.3.14 + '@smithy/types': 4.14.1 tslib: 2.8.1 '@smithy/util-hex-encoding@4.2.2': dependencies: tslib: 2.8.1 - '@smithy/util-middleware@4.2.13': + '@smithy/util-middleware@4.2.14': dependencies: - '@smithy/types': 4.14.0 + '@smithy/types': 4.14.1 tslib: 2.8.1 - '@smithy/util-retry@4.3.1': + '@smithy/util-retry@4.3.2': dependencies: - '@smithy/service-error-classification': 4.2.13 - '@smithy/types': 4.14.0 + '@smithy/service-error-classification': 4.2.14 + '@smithy/types': 4.14.1 tslib: 2.8.1 - '@smithy/util-stream@4.5.22': + '@smithy/util-stream@4.5.23': dependencies: - '@smithy/fetch-http-handler': 5.3.16 - '@smithy/node-http-handler': 4.5.2 - '@smithy/types': 4.14.0 + '@smithy/fetch-http-handler': 5.3.17 + '@smithy/node-http-handler': 4.5.3 + '@smithy/types': 4.14.1 '@smithy/util-base64': 4.3.2 '@smithy/util-buffer-from': 4.2.2 '@smithy/util-hex-encoding': 4.2.2 @@ -9019,9 +9019,9 @@ snapshots: '@smithy/util-buffer-from': 4.2.2 tslib: 2.8.1 - '@smithy/util-waiter@4.2.15': + '@smithy/util-waiter@4.2.16': dependencies: - '@smithy/types': 4.14.0 + '@smithy/types': 4.14.1 tslib: 2.8.1 '@smithy/uuid@1.1.2': @@ -10036,7 +10036,7 @@ snapshots: dependencies: baseline-browser-mapping: 2.10.19 caniuse-lite: 1.0.30001788 - electron-to-chromium: 1.5.339 + electron-to-chromium: 1.5.340 node-releases: 2.0.37 update-browserslist-db: 1.2.3(browserslist@4.28.2) @@ -10593,7 +10593,7 @@ snapshots: dependencies: jake: 10.9.4 - electron-to-chromium@1.5.339: {} + electron-to-chromium@1.5.340: {} elegant-spinner@1.0.1: {} @@ -10754,7 +10754,7 @@ snapshots: '@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.9.3) eslint-config-xo-space: 0.35.0(eslint@8.57.1) eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) eslint-plugin-mocha: 10.5.0(eslint@8.57.1) eslint-plugin-n: 15.7.0(eslint@8.57.1) eslint-plugin-perfectionist: 2.11.0(eslint@8.57.1)(typescript@5.9.3) @@ -10816,7 +10816,7 @@ snapshots: eslint-config-xo: 0.49.0(eslint@8.57.1) eslint-config-xo-space: 0.35.0(eslint@8.57.1) eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.58.2(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.58.2(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) eslint-plugin-jsdoc: 50.8.0(eslint@8.57.1) eslint-plugin-mocha: 10.5.0(eslint@8.57.1) eslint-plugin-n: 17.24.0(eslint@8.57.1)(typescript@5.9.3) @@ -10868,7 +10868,7 @@ snapshots: tinyglobby: 0.2.16 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) transitivePeerDependencies: - supports-color @@ -10933,7 +10933,7 @@ snapshots: eslint-utils: 2.1.0 regexpp: 3.2.0 - eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -10991,7 +10991,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.58.2(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.58.2(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -11376,13 +11376,13 @@ snapshots: fast-uri@3.1.0: {} - fast-xml-builder@1.1.4: + fast-xml-builder@1.1.5: dependencies: path-expression-matcher: 1.5.0 fast-xml-parser@5.5.8: dependencies: - fast-xml-builder: 1.1.4 + fast-xml-builder: 1.1.5 path-expression-matcher: 1.5.0 strnum: 2.2.3