diff --git a/.cursor/rules/development-philosophy.mdc b/.cursor/rules/development-philosophy.mdc new file mode 100644 index 0000000..ae814d0 --- /dev/null +++ b/.cursor/rules/development-philosophy.mdc @@ -0,0 +1,123 @@ +--- +description: Core development philosophy and successful patterns for beautiful, maintainable code +alwaysApply: true +--- + +# Development Philosophy & Successful Patterns + +## Core Values + +### Beauty as Architecture +- Optimize for code that is both beautiful to read AND architecturally sound +- Never settle for "just working" - always ask "how can this be more beautiful and maintainable?" +- Code should make developers smile when they read it + +### Incrementalism Rocks +- Tackle one problem at a time, building on each success +- Get tests passing first, then extract for beauty +- Build reusable frameworks that benefit the entire codebase + +### Single Source of Truth +- Eliminate duplication through shared constants and utilities +- Production and test code must use the same constants for perfect sync +- Extract magic strings and repeated patterns into reusable helpers + +## Testing Excellence + +### Follow Testing Rules Religiously +- **Always use `yarn test:ci`** (never `yarn test` - that's watch mode) +- **Fix tests one at a time** using `.only` to isolate failing tests +- **Run specific test files** with `yarn test:ci path/to/test-file.test.ts` + +### Beautiful Test Structure +- **BDD-style naming**: Tests should read like sentences + ```typescript + when("handling volunteer applications", (discord) => { + it("sends application form when user clicks volunteer button", async () => { + ``` +- **Intent-revealing helpers**: Extract complex assertions into beautiful functions +- **Reusable test frameworks**: Build helpers that work across all features +- **Shared constants**: Use production constants in tests for consistency + +### Discord Testing Patterns +```typescript +// ✅ Beautiful pattern to follow everywhere +when("handling feature X", (discord) => { + it("accomplishes user goal Y", async () => { + await updateFeatureX(discord); + expectButtonCreated(FEATURE_X.CUSTOM_ID, FEATURE_X.LABEL); + expectInstructionsCreated("featureInstructions"); + // ... rest of test + }); +}); +``` + +## Code Organization Success Patterns + +### File Structure That Works +``` +src/features/[feature]/ +├── constants.ts # Shared between prod and test +├── [feature].ts # Main implementation +├── [feature].test.ts # Beautiful BDD tests +└── ... + +src/test/helpers/ +├── describe-discord.ts # when() helper +├── discord-ui-expectations.ts # Reusable UI testing +└── ... +``` + +### Development Flow +1. **Start with working solution** - Get tests passing first +2. **Extract for beauty** - Move constants, helpers to shared locations +3. **Build reusable frameworks** - Create tools future features can use +4. **Optimize formatting** - Ensure code is beautiful (100 char line width) +5. **Maintain consistency** - Every improvement should benefit whole codebase + +## Architectural Patterns + +### Constants Strategy +- Create shared constants files (e.g., `features/[feature]/constants.ts`) +- Export structured constant objects with clear naming +- Use `as const` for immutability and strict typing +- Import same constants in both production and test code + +### Testing Frameworks +- Build reusable helpers like `discord-ui-expectations.ts` +- Create semantic assertion functions that reveal intent +- Extract repetitive setup into scenario builders +- Use global mocks with proper reset strategies + +### Formatting & Style +- Use 100 character line width for readability +- Consistent formatting via `.prettierrc` configuration +- Beautiful imports and function calls +- Meaningful whitespace and organization + +## Project-Specific Commands + +### Essential Commands +- **Run tests**: `yarn test:ci` +- **Format code**: `yarn format` +- **Lint and fix**: `yarn lint:fix` +- **Full cleanup**: `yarn cleanup` + +### Testing Workflow +1. Run `yarn test:ci` to see all failing tests +2. Use `.only` on one failing test to isolate it +3. Run `yarn test:ci path/to/test-file.test.ts` for that file only +4. Fix the test thoroughly and properly +5. Remove `.only` and verify it passes +6. Move to next failing test + +## Success Metrics + +Code is successful when: +- **Tests read like stories** - Anyone can understand what the feature does +- **Constants are shared** - No duplication between prod and test +- **Helpers are reusable** - New features can use existing test infrastructure +- **Formatting is beautiful** - Code is pleasant to read and maintain +- **Architecture is sound** - Changes in one place automatically benefit everywhere + +Remember: **Optimize for beauty AND architectural soundness at every step.** \ No newline at end of file diff --git a/.cursor/rules/formatting-and-linting.mdc b/.cursor/rules/formatting-and-linting.mdc new file mode 100644 index 0000000..1b42d02 --- /dev/null +++ b/.cursor/rules/formatting-and-linting.mdc @@ -0,0 +1,46 @@ +--- +description: Guidelines for fixing formatting and linting issues +alwaysApply: true +--- + +# Formatting and Linting Guidelines + +## Automatic Fix Commands + +**Always use automated tools to fix formatting and linting issues before attempting manual fixes.** + +### For All Files + +- **`yarn lint:fix`** - Fixes ESLint issues including formatting (recommended first step) +- **`yarn format`** - Formats code using prettier-eslint +- **`yarn cleanup`** - Runs both lint:fix AND format (most comprehensive) + +### For Specific Files + +When targeting a specific file, use npx directly: + +- **`npx eslint --fix path/to/file.ts`** - Fix ESLint issues in specific file +- **`npx prettier-eslint --write path/to/file.ts`** - Format specific file + +## Command Priority and Usage + +1. **Start with `yarn lint:fix`** - This fixes most ESLint issues including formatting since prettier is integrated as an ESLint rule +2. **Follow with `yarn format`** if needed - This handles any remaining formatting that prettier-eslint might catch +3. **Use `yarn cleanup`** for comprehensive fixing - Runs both commands in sequence +4. **For specific files** - Use the npx commands shown above + +## Why Both Commands Exist + +- **`yarn lint:fix`**: Fixes ESLint issues (including prettier formatting since prettier is integrated) +- **`yarn format`**: Uses prettier-eslint to ensure formatting meets both prettier and ESLint standards +- They complement each other and are not redundant + +## Manual Fixes + +Only attempt manual fixes for linting/formatting issues after running the automated tools. The automated tools handle: + +- Indentation and spacing +- Semicolons and commas +- Quotes and brackets +- Import organization +- Most TypeScript-specific formatting rules diff --git a/.cursor/rules/unit-tests.mdc b/.cursor/rules/unit-tests.mdc new file mode 100644 index 0000000..9616357 --- /dev/null +++ b/.cursor/rules/unit-tests.mdc @@ -0,0 +1,33 @@ +--- +description: Testing guidelines and best practices for unit tests +alwaysApply: true +--- + +# Unit Testing Guidelines + +## Test Execution Rules + +- **Always use `yarn test:ci`** to run tests in CI mode +- **Never use `yarn test`** - it runs in watch mode which is not suitable for one-off test runs +- **Always fix tests one at a time** in a tight development loop +- **Always use `.only`** to isolate a single test when debugging or fixing issues +- **When using `.only`, run the specific test file** with `yarn test:ci path/to/test-file.test.ts` for complete isolation + +## Test Quality Standards + +- **Always fix tests properly** - never give up on a failing test +- **Never remove or descope tests** - good tests are crucial and cannot be skipped +- **Tests must be comprehensive** and cover all important functionality +- **Maintain high test quality** as tests are essential for code reliability + +## Development Workflow + +1. Run `yarn test:ci` to identify failing tests +2. Use `.only` on a single failing test to isolate it +3. Run `yarn test:ci path/to/test-file.test.ts` to run only that test file +4. Fix the test thoroughly and properly +5. Remove `.only` and verify the test passes with `yarn test:ci path/to/test-file.test.ts` +6. Move to the next failing test +7. Repeat until all tests pass + +Remember: **Good tests are non-negotiable** - they ensure code quality and prevent regressions. diff --git a/.eslintrc.json b/.eslintrc.json index 8362a2d..710627b 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -15,9 +15,15 @@ "ecmaVersion": "latest", "sourceType": "module" }, - "plugins": ["@typescript-eslint", "prettier"], + "plugins": ["@typescript-eslint", "prettier", "import"], "rules": { - "prettier/prettier": ["error", { "endOfLine": "auto" }], - "import/prefer-default-export": "off" + "prettier/prettier": "error", + "import/prefer-default-export": "off", + "@typescript-eslint/no-unused-vars": [ + "error", + { "argsIgnorePattern": "^_" } + ], + "no-unused-vars": "off", + "curly": ["error", "all"] } } diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..b116b5e --- /dev/null +++ b/.prettierrc @@ -0,0 +1,12 @@ +{ + "printWidth": 100, + "tabWidth": 2, + "useTabs": false, + "semi": true, + "singleQuote": false, + "quoteProps": "as-needed", + "trailingComma": "es5", + "bracketSpacing": true, + "arrowParens": "always", + "endOfLine": "auto" +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index f468389..cab2e87 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,5 +3,8 @@ "editor.defaultFormatter": "esbenp.prettier-vscode", "[json]": { "editor.defaultFormatter": "vscode.json-language-features" + }, + "[typescript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" } } diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..28971b2 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,83 @@ +# Claude Development Memory + +## Successful Development Patterns & Philosophy + +### Our Core Values +- **Beauty as Architecture** - We optimize for code that is both beautiful to read and architecturally sound +- **Incrementalism Rocks** - Tackle one problem at a time, building on each success +- **Reusability Over Repetition** - Create frameworks and patterns that benefit the entire codebase +- **Single Source of Truth** - Eliminate duplication through shared constants and utilities + +### Testing Excellence +- **Follow cursor rules religiously** - Always use `yarn test:ci`, fix tests one at a time with `.only` +- **BDD-style naming** - Tests should read like sentences: `when("handling X", (discord) => { it("does Y") })` +- **Beautiful helpers over repetition** - Extract complex assertions into intent-revealing functions +- **Shared constants** - Production and test code use the same constants for perfect sync +- **Reusable test frameworks** - Build helpers that work across all features (like `discord-ui-expectations.ts`) + +### Code Organization Success Patterns +1. **Start with working solution** - Get tests passing first +2. **Extract for beauty** - Move constants, helpers, and utilities to shared locations +3. **Build reusable frameworks** - Create tools that future features can use +4. **Optimize formatting** - Ensure code is beautiful and readable (100 char line width) +5. **Maintain architectural consistency** - Every improvement should benefit the whole codebase + +### Architectural Wins from Recent Session +- **Global Discord mocks** in `test/setup.ts` - Consistent testing environment +- **`when()` helper** - Beautiful BDD-style test syntax with automatic Discord setup +- **Shared constants** - Production code and tests use same values (see `features/applications/constants.ts`) +- **Reusable UI expectations** - `discord-ui-expectations.ts` works across all Discord features +- **Beautiful formatting** - 100 char lines, consistent style via `.prettierrc` + +### Discord Testing Patterns +```typescript +// ✅ Beautiful pattern to follow +when("handling feature X", (discord) => { + it("accomplishes user goal Y", async () => { + await updateFeatureX(discord); + expectButtonCreated(FEATURE_X.CUSTOM_ID, FEATURE_X.LABEL); + // ... rest of test + }); +}); +``` + +### File Organization That Works +``` +src/features/[feature]/ +├── constants.ts # Shared between prod and test +├── [feature].ts # Main implementation +├── [feature].test.ts # Beautiful BDD tests +└── ... + +src/test/helpers/ +├── describe-discord.ts # when() helper +├── discord-ui-expectations.ts # Reusable UI testing +└── ... +``` + +## Project-Specific Context + +### Cursor Rules Location +- **Cursor rules directory**: `.cursor/rules/` +- **Current rules**: + - `unit-tests.mdc` - Testing guidelines and best practices + - `formatting-and-linting.mdc` - Code formatting automation + - `development-philosophy.mdc` - Core development philosophy (this session's learnings) +- All rules are set to `alwaysApply: true` for consistent guidance + +### Testing Commands +- **Run tests**: `yarn test:ci` (never `yarn test` - that's watch mode) +- **Format code**: `yarn format` +- **Lint and fix**: `yarn lint:fix` +- **Full cleanup**: `yarn cleanup` + +### Current Architecture +- **Discord bot** using discord.js with TypeScript +- **Global test setup** in `src/test/setup.ts` with automatic mock management +- **BDD-style testing** with `when()` helper for readable test organization +- **Shared constants** between production and test code for consistency +- **100 character line width** for beautiful, readable formatting + +--- + +*This memory captures our successful collaborative approach. The key is always optimizing for both beauty and architectural soundness, building reusable patterns that make the entire codebase better.* \ No newline at end of file diff --git a/active-work.md b/active-work.md new file mode 100644 index 0000000..7aa419b --- /dev/null +++ b/active-work.md @@ -0,0 +1,468 @@ +# Discord Testing Library Redesign Plan + +## Background + +We are building a comprehensive testing framework for Discord bots, similar to Testing Library for React. The goal is to provide a clean, intuitive API for testing Discord bot interactions with proper separation of concerns and excellent developer experience. + +### Current State +- **Architecture**: Test infrastructure is generic, bot-specific config is separated +- **API Status**: Working but complex with multiple abstractions +- **Test Status**: 1/3 tests passing, remaining failures are specific channel configuration issues +- **Technical Quality**: TypeScript-safe, no `any` casts, clear error messages + +### Problems Solved +✅ **Fixed critical mock bug**: `mockReset()` was destroying custom implementations +✅ **Achieved architectural separation**: Generic test infra + bot-specific config layer +✅ **Eliminated bot-specific leaks**: No hardcoded channels/concepts in generic code +✅ **Type safety**: Proper Discord.js union type handling without casts +✅ **Testing Library patterns**: `getButton(label, { style? })` with helpful error messages + +### Current Pain Points +❌ **Over-engineered abstractions**: Too many concepts (registry, multiple mock layers, dual APIs) +❌ **Complex setup**: Multiple ways to configure channels, unclear ownership +❌ **API inconsistency**: Mix of Testing Library patterns and custom approaches +❌ **Leaky abstractions**: Users exposed to internal concepts (guild, client) +❌ **Unnecessary indirection**: Component registry middleware for simple queries + +## Goals + +### Primary Goals +1. **Beautiful API**: Clean, intuitive interface that feels like Testing Library +2. **Architectural soundness**: Single responsibility, clear ownership, minimal concepts +3. **Developer experience**: Excellent error messages, helpful failures, fast feedback +4. **Type safety**: Leverage TypeScript without compromises or casts +5. **Maintainability**: Easy to understand, extend, and debug + +### Success Metrics +- **API Simplicity**: New team member can write tests without documentation +- **Test Reliability**: Tests pass consistently, failures are actionable +- **Performance**: Fast test execution, minimal setup overhead +- **Extensibility**: Easy to add new Discord features (slash commands, modals, etc.) + +## Design Constraints + +### Must Have +- **Generic test infrastructure**: No bot-specific knowledge in core library +- **Testing Library compatibility**: Familiar patterns for React developers +- **Full Discord.js support**: Buttons, embeds, interactions, channels, users +- **Real event flow**: Use actual Discord listeners, not just mocks +- **TypeScript first**: Proper types, no `any` escapes + +### Nice to Have +- **Zero configuration**: Sensible defaults for common scenarios +- **Rich assertions**: Custom matchers that provide clear feedback +- **Async support**: Proper handling of Discord's async nature +- **Debug tools**: Easy to understand what's happening when tests fail + +### Constraints +- **Jest ecosystem**: Must work within existing Jest setup +- **Existing codebase**: Cannot break current working tests during transition +- **Discord.js compatibility**: Work with current Discord.js version and types + +## Things We've Tried (Bad Approaches) + +### ❌ Component Registry Pattern +```typescript +// Too much indirection: +updateApplicationInfo() → mock → discordComponentRegistry.registerButton() → getButton() +``` +**Problem**: Unnecessary middleware layer for simple component queries + +### ❌ Dual Channel Setup APIs +```typescript +// Confusing - two ways to do the same thing: +channels: { "request-dump": "text" } +defaultChannels: [{ name: "request-dump", id: "111222333", type: "thread" }] +``` +**Problem**: Inconsistent behavior, unclear which to use when + +### ❌ Multiple Mock Layers +```typescript +// Too complex: +setup.ts → setup-discord-actions.ts → globalDiscordMocks → registry → query +``` +**Problem**: Hard to debug, unclear ownership, many failure points + +### ❌ Leaky User Creation +```typescript +// Exposes internals: +const applicant = discord.guild.createUser("eager_applicant"); +``` +**Problem**: User shouldn't need to know about guild concept + +### ❌ TypeScript Casts +```typescript +// Unsafe: +button.data as any +``` +**Problem**: Loses type safety, hides real type issues + +## Proposed Solution + +### Core Design: Single Environment Object + +```typescript +interface DiscordTest { + // Bot actions - what the bot does + bot: { + updateApplicationInfo(): Promise; + sendMessage(channel: string, content: string): Promise; + // other bot methods as needed + }; + + // Element queries - Testing Library style + getByRole(role: 'button' | 'embed', options?: QueryOptions): DiscordElement; + queryByRole(role: 'button' | 'embed', options?: QueryOptions): DiscordElement | null; + getAllByRole(role: 'button' | 'embed', options?: QueryOptions): DiscordElement[]; + + // User interactions - implicit context + user(name: string): DiscordUser; + + // Channel access - simple and direct + channel(name: string): DiscordChannel; +} + +interface QueryOptions { + name?: string; // Button label, embed title + style?: ButtonStyle; // For buttons +} + +interface DiscordElement { + // Element properties + role: 'button' | 'embed'; + name: string; + + // Actions available on element + click?(user: DiscordUser): Promise; +} + +interface DiscordUser { + name: string; + click(element: DiscordElement): Promise; + + // Assertions built in + sentDM: jest.MockedFunction; + editedReply: jest.MockedFunction; +} + +interface DiscordChannel { + name: string; + type: 'text' | 'thread'; + + // Assertions built in + sentMessage: jest.MockedFunction; +} +``` + +### Beautiful Usage Example + +```typescript +// Simple setup with sensible defaults +const discord = createDiscordTest(); + +// Bot performs action +await discord.bot.updateApplicationInfo(); + +// Query for elements (Testing Library style) +const volunteerButton = discord.getByRole('button', { name: 'Volunteer Application' }); +const embed = discord.getByRole('embed', { name: 'Volunteer Applications' }); + +// User interactions +const applicant = discord.user('eager_applicant'); +await applicant.click(volunteerButton); + +// Assertions with built-in matchers +expect(applicant.sentDM).toHaveBeenCalledWith(APPLICATION_MESSAGE_TEMPLATE); +expect(discord.channel('request-dump').sentMessage).toHaveBeenCalledWith(/sent to \*\*eager_applicant\*\*/); +``` + +### Key Design Principles + +1. **Single Entry Point**: One `discord` object owns everything +2. **No Registry**: Query rendered Discord UI directly like DOM +3. **Implicit Context**: Users/channels connected automatically +4. **Testing Library Patterns**: `getByRole`, `queryByRole` familiar to React devs +5. **Built-in Assertions**: Matchers integrated into objects, not separate + +## Implementation Plan + +### Phase 1: Core Infrastructure (Week 1) +- [ ] Create new `DiscordTest` interface +- [ ] Implement direct UI querying (no registry) +- [ ] Build user/channel abstractions with implicit context +- [ ] Create `createDiscordTest()` factory with defaults + +### Phase 2: Testing Library API (Week 1) +- [ ] Implement `getByRole('button')` and `getByRole('embed')` +- [ ] Add `queryByRole` and `getAllByRole` variants +- [ ] Create rich `QueryOptions` with name/style filtering +- [ ] Add helpful error messages for failed queries + +### Phase 3: Built-in Assertions (Week 2) +- [ ] Integrate Jest matchers into user/channel objects +- [ ] Remove separate matcher files +- [ ] Create fluent assertion API +- [ ] Add custom error messages + +### Phase 4: Migration & Cleanup (Week 2) +- [ ] Migrate existing tests to new API +- [ ] Remove old abstractions (registry, dual mock layers) +- [ ] Clean up file structure +- [ ] Update documentation + +### Phase 5: Polish & Extension (Week 3) +- [ ] Add support for more Discord elements (modals, select menus) +- [ ] Performance optimization +- [ ] Advanced debugging tools +- [ ] Comprehensive test coverage + +## Incremental Delivery Strategy + +### Step 1: Parallel Implementation +- Build new API alongside existing system +- No breaking changes to current tests +- Validate design with simple test cases + +### Step 2: Gradual Migration +- Convert one test file at a time +- Keep old system working during transition +- Compare results to ensure compatibility + +### Step 3: Clean Cutover +- Remove old abstractions once all tests migrated +- Delete unused files and concepts +- Final API polish + +### Step 4: Documentation & Rollout +- Create comprehensive examples +- Write migration guide +- Team training and adoption + +## Risk Mitigation + +### Technical Risks +- **Discord.js type complexity**: Prototype with real types early +- **Jest integration issues**: Test with actual Jest environment +- **Performance degradation**: Benchmark against current system + +### Project Risks +- **Scope creep**: Stick to core API, resist feature additions +- **Breaking changes**: Maintain backward compatibility during transition +- **Team adoption**: Get early feedback, iterate on developer experience + +## Success Criteria + +### Functional Requirements +- [ ] All existing tests pass with new API +- [ ] New tests are 50% shorter than current approach +- [ ] Error messages are actionable and helpful +- [ ] No TypeScript `any` casts required + +### Quality Requirements +- [ ] Test execution time within 10% of current system +- [ ] New team member can write test without documentation +- [ ] Failed tests clearly indicate what to fix +- [ ] Codebase is easier to understand and maintain + +## Technical Implementation Details + +### Current Codebase Structure +``` +src/test/ +├── setup/ # Mock setup (will be simplified) +│ ├── setup-discord-actions.ts # Contains critical mock bug fix +│ ├── setup-test-config.ts +│ └── setup-service-*.ts +├── discord-testing-library/ # Core library (will be redesigned) +│ ├── create-discord-environment.ts +│ ├── discord-component-registry.ts # Will be removed +│ └── create-mock-*.ts +├── matchers/ # Jest matchers (will be integrated) +├── expects/ # UI expectations (will be integrated) +└── app-test-config.ts # Bot-specific config (keep) +``` + +### Critical Bug Fix to Preserve +**File**: `src/test/setup/setup-discord-actions.ts` +**Line 74**: `mockClear()` instead of `mockReset()` +**Why Critical**: `mockReset()` destroys custom implementations, `mockClear()` preserves them +**Symptom if broken**: Button registration fails silently, tests show "Available buttons: none" + +### Key Files to Understand +1. **Current working test**: `src/features/applications/request-application-button-commands.test.ts` +2. **Button constants**: `src/features/applications/constants.ts` +3. **Bot logic**: `src/features/applications/update-applications.ts` +4. **Mock setup**: `src/test/setup.ts` (imports all setup files) + +### Dependencies and Tooling +- **Jest**: `yarn test:ci` (never `yarn test` - that's watch mode) +- **Discord.js**: Button/Embed builders with complex union types +- **TypeScript**: Strict mode, no `any` casts allowed +- **Testing commands**: Use `--testPathPattern=filename` for single file testing + +### Known Working Patterns +```typescript +// This pattern works and should be preserved: +const discord = createBotTestEnvironment(); +await discord.withClient((client: Client) => updateApplicationInfo(client)); +const button = discord.getButton("Volunteer Application"); +await button.click(applicant); +``` + +### Known Broken Patterns +```typescript +// These cause failures: +mockReset() // Destroys implementations +channels: { "request-dump": "text" } // Missing required ID "111222333" +button.data as any // TypeScript anti-pattern +``` + +## Migration Strategy Details + +### Compatibility Requirements +- **Zero test breakage** during transition +- **Gradual rollout** - old and new APIs must coexist +- **Same assertions** - existing expects should still work +- **Performance parity** - no slower than current 6-7 second test runs + +### File-by-File Migration Plan +1. **Start with**: `debug-mock.test.ts` (has comprehensive logging) +2. **Then migrate**: `request-application-button-commands.test.ts` (representative test) +3. **Finally**: `update-applications.test.ts` (simpler test) +4. **Cleanup**: Remove old abstractions only after all tests pass + +### Testing the Migration +```bash +# Test current system +yarn test:ci --testPathPattern=request-application-button-commands + +# Test new system (parallel) +yarn test:ci --testPathPattern=new-api-test + +# Compare results +# Both should have same assertions, just different setup +``` + +## Debugging Guide + +### Current Debug Tools Available +- **Debug logs**: 🔥 prefixed console.logs in setup-discord-actions.ts +- **Mock inspection**: `globalDiscordMocks.createOrUpdateInstructions.mock.calls` +- **Registry inspection**: `discordComponentRegistry.getButtons()` +- **Test file**: `debug-mock.test.ts` with comprehensive tracing + +### Common Failure Patterns +1. **"Available buttons: none"** → Mock implementation destroyed +2. **"Channel not found"** → ID mismatch (need "111222333" for request-dump) +3. **"Cannot find module"** → Import path issue (happened with require()) +4. **TypeScript errors** → Union type issue, avoid `as any` + +### How to Debug New Issues +1. **Add debug logs** to new implementation (use 🔥 prefix) +2. **Check mock calls** - are they happening? +3. **Verify types** - no `any` casts allowed +4. **Test incrementally** - one component at a time + +## Next Immediate Steps (REVISED) + +**Priority: Fix the broken infrastructure first, not redesign the API** + +1. **Debug and fix channel mocking** (2-3 hours) + - Understand why channel lookup fails despite hardcoded ID "111222333" + - Fix the mock chain: globalDiscordMocks.getChannel → actual channel resolution + - Get at least one test passing to establish working baseline + +2. **Simplify the mock setup** (1-2 hours) + - Reduce the setup chain complexity while preserving the critical mockClear() fix + - Consolidate overlapping mock configurations + - Improve debug visibility without the 🔥 logs + +3. **Validate current API is sufficient** (30 minutes) + - Test that button queries work well (they seem to) + - Confirm type safety is maintained + - Assess if Testing Library patterns are really needed + +4. **Incremental improvements only** (1 hour) + - Make targeted fixes to pain points without big bang rewrite + - Improve error messages where actually lacking + - Consider if component registry is really unnecessary + +**STOP: Only proceed with major redesign if current API proves insufficient after fixes** + +## Handoff Checklist + +### Before Starting Implementation +- [ ] Read this entire document +- [ ] Run existing tests to verify current state (`yarn test:ci`) +- [ ] Understand the critical mock bug fix in setup-discord-actions.ts +- [ ] Review failed test patterns to understand what we're solving + +### During Implementation +- [ ] Preserve the `mockClear()` fix +- [ ] Maintain TypeScript safety (no `any` casts) +- [ ] Keep debug logging pattern for new code +- [ ] Test incrementally with single files + +### Before Completion +- [ ] All existing tests pass with new API +- [ ] Performance is within 10% of current system +- [ ] Documentation updated with new patterns +- [ ] Debug tools removed from production code + +--- + +## RESOLUTION: Infrastructure Fix Was Sufficient + +### What We Actually Fixed (Same Session) + +✅ **Root Cause**: Config mocking was broken - `requestDumpThreadId` was `undefined` instead of `"111222333"` +✅ **Secondary Issue**: Channel override IDs weren't consistent with config expectations +✅ **Result**: All 23 tests now passing with existing API + +### Key Fixes Applied + +1. **Fixed config mocking** (`src/test/setup/setup-test-config.ts`): + - Moved `jest.mock()` to top level (hoisted properly) + - Config values now correctly mocked in test environment + +2. **Fixed channel ID consistency** (`src/test/discord-testing-library/create-discord-environment.ts`): + - Channel overrides now use default IDs when channel names match + - Test scenarios work correctly with expected config IDs + +3. **Cleaned up debug logging** - Removed temporary 🔥 logs after debugging + +### API Assessment: Current System is Actually Good + +The plan's criticism of the current API was **overly harsh**. After fixing infrastructure: + +✅ **Clean syntax**: `discord.getButton(VOLUNTEER_APPLICATION.LABEL)` +✅ **Good abstractions**: Button/channel/user objects with helpful methods +✅ **Type safety**: Strong TypeScript support, no `any` casts +✅ **Helpful errors**: Clear messages when components not found +✅ **Working separation**: Generic test infra + bot-specific config +✅ **Component registry**: Actually works well despite being called "over-engineered" + +### Lessons Learned + +1. **Diagnose infrastructure before architecture** - The core problems were bugs, not design +2. **Fix incrementally** - Infrastructure fixes solved all issues without major changes +3. **Test the hypothesis** - Running all tests proved current API works excellently +4. **Question assumptions** - The "over-engineered" system actually works well + +### Recommendation: STOP Major Redesign + +The current Discord testing system is **working excellently** with: +- All tests passing consistently +- Clean, readable test syntax +- Good TypeScript support +- Proper separation of concerns + +**Next steps**: Focus on incremental improvements rather than major rewrites. + +--- + +**Status**: COMPLETED - Infrastructure fixed, all tests passing +**Outcome**: Major redesign unnecessary - current API works well +**Owner**: Successfully resolved in current session +**Timeline**: Completed same day +**Last Updated**: Infrastructure fix session - problem solved \ No newline at end of file diff --git a/jest.config.js b/jest.config.js index 8cbf894..7a52be4 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,5 +1,17 @@ +/* eslint-disable no-undef */ /** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ module.exports = { - preset: 'ts-jest', - testEnvironment: 'node', -}; \ No newline at end of file + preset: "ts-jest", + testEnvironment: "node", + setupFilesAfterEnv: ["/src/test/setup.ts"], + transformIgnorePatterns: ["node_modules/(?!(axios|axios-retry|lru-cache)/)"], + moduleNameMapper: { + "^axios$": require.resolve("axios"), + }, + extensionsToTreatAsEsm: [".ts"], + globals: { + "ts-jest": { + useESM: true, + }, + }, +}; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..b4d839d --- /dev/null +++ b/package-lock.json @@ -0,0 +1,9899 @@ +{ + "name": "castle-bank-bot", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "castle-bank-bot", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@discordjs/builders": "^0.12.0", + "@discordjs/rest": "^0.3.0", + "@discordjs/voice": "^0.17.0", + "@google-cloud/local-auth": "^2.1.0", + "@prisma/client": "^5.1.0", + "@types/moment-timezone": "^0.5.30", + "@types/pg": "^8.6.5", + "async-mutex": "^0.4.0", + "axios": "^1.3.4", + "axios-retry": "^3.4.0", + "discord-api-types": "^0.31.1", + "discord.js": "^14", + "ffmpeg-static": "^5.2.0", + "google-spreadsheet": "^3.3.0", + "googleapis": "^105.0.0", + "jest": "^27.5.1", + "libsodium-wrappers": "^0.7.13", + "lodash": "^4.17.21", + "lru-cache": "^7.17.0", + "moment": "^2.29.2", + "moment-timezone": "^0.5.34", + "pg": "^8.7.3", + "prisma": "^5.2.0", + "redis": "^4.6.5", + "reflect-metadata": "^0.2.2", + "rimraf": "^3.0.2", + "tsyringe": "^4.8.0", + "typeorm": "^0.3.6", + "xlsx": "^0.18.5", + "ytdl-core": "^4.11.5" + }, + "devDependencies": { + "@types/google-spreadsheet": "^3.3.1", + "@types/jest": "^27.4.1", + "@types/lodash": "^4.14.181", + "@types/node": "^20.4.2", + "@types/node-fetch": "^2.6.3", + "@typescript-eslint/eslint-plugin": "^5.19.0", + "@typescript-eslint/parser": "^5.19.0", + "eslint": "^8.13.0", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-prettier": "^4.0.0", + "nodemon": "^2.0.15", + "prettier": "^2.6.2", + "prettier-eslint": "^15.0.1", + "prettier-eslint-cli": "^7.1.0", + "ts-jest": "^27.1.4", + "ts-node": "^10.7.0", + "typescript": "^4.6.3" + }, + "engines": { + "node": ">=22.2.0" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", + "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.6.tgz", + "integrity": "sha512-29tfsWTq2Ftu7MXmimyC0C5FDZv5DYxOZkh3XD3+QW4V/BYuv/LyEsjj3c0hqedEaDt6DBfDvexMKU8YevdqFg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.22.8", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.8.tgz", + "integrity": "sha512-75+KxFB4CZqYRXjx4NlR4J7yGvKumBuZTmV4NV6v09dVXXkuYVYLT68N6HCzLvfJ+fWCxQsntNzKwwIXL4bHnw==", + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.7", + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helpers": "^7.22.6", + "@babel/parser": "^7.22.7", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.8", + "@babel/types": "^7.22.5", + "@nicolo-ribaudo/semver-v6": "^6.3.3", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.22.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.7.tgz", + "integrity": "sha512-p+jPjMG+SI8yvIaxGgeW24u7q9+5+TGpZh8/CuB7RhBKd7RCy8FayNEFNNKrNK/eUcY/4ExQqLmyrvBXKsIcwQ==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.6.tgz", + "integrity": "sha512-534sYEqWD9VfUm3IPn2SLcH4Q3P86XL+QvqdC7ZsFrzyyPF3T4XGiVghF6PTYNdWg6pXuoqXxNQAhbYeEInTzA==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-validator-option": "^7.22.5", + "@nicolo-ribaudo/semver-v6": "^6.3.3", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", + "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", + "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.22.5", + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", + "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.5.tgz", + "integrity": "sha512-+hGKDt/Ze8GFExiVHno/2dvG5IdstpzCq0y4Qc9OJ25D4q3pKfiIP/4Vp3/JvhDkLKsDK2api3q3fpIgiIF5bw==", + "license": "MIT", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.5", + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", + "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", + "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.6.tgz", + "integrity": "sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.6", + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", + "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.22.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz", + "integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==", + "license": "MIT", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz", + "integrity": "sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.6.tgz", + "integrity": "sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==", + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.13.11" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", + "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.22.5", + "@babel/parser": "^7.22.5", + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.22.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.8.tgz", + "integrity": "sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.7", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.22.7", + "@babel/types": "^7.22.5", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz", + "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "license": "MIT" + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@derhuerst/http-basic": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/@derhuerst/http-basic/-/http-basic-8.2.4.tgz", + "integrity": "sha512-F9rL9k9Xjf5blCz8HsJRO4diy111cayL2vkY2XE4r4t3n0yPXVYy3KD3nJ1qbrSn9743UWSXH4IwuCa/HWlGFw==", + "license": "MIT", + "dependencies": { + "caseless": "^0.12.0", + "concat-stream": "^2.0.0", + "http-response-object": "^3.0.1", + "parse-cache-control": "^1.0.1" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@discordjs/builders": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.12.0.tgz", + "integrity": "sha512-Vx2MjUZd6QVo1uS2uWt708Fd6cHWGFblAvbpL5EBO+kLl0BADmPwwvts+YJ/VfSywed6Vsk6K2cEooR/Ytjhjw==", + "license": "Apache-2.0", + "dependencies": { + "@sindresorhus/is": "^4.3.0", + "discord-api-types": "^0.26.1", + "ts-mixer": "^6.0.0", + "tslib": "^2.3.1", + "zod": "^3.11.6" + }, + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/@discordjs/builders/node_modules/discord-api-types": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.26.1.tgz", + "integrity": "sha512-T5PdMQ+Y1MEECYMV5wmyi9VEYPagEDEi4S0amgsszpWY0VB9JJ/hEvM6BgLhbdnKky4gfmZEXtEEtojN8ZKJQQ==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/@discordjs/collection": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.1.tgz", + "integrity": "sha512-aWEc9DCf3TMDe9iaJoOnO2+JVAjeRNuRxPZQA6GVvBf+Z3gqUuWYBy2NWh4+5CLYq5uoc3MOvUQ5H5m8CJBqOA==", + "license": "Apache-2.0", + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/@discordjs/formatters": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.3.1.tgz", + "integrity": "sha512-M7X4IGiSeh4znwcRGcs+49B5tBkNDn4k5bmhxJDAUhRxRHTiFAOTVUNQ6yAKySu5jZTnCbSvTYHW3w0rAzV1MA==", + "license": "Apache-2.0", + "dependencies": { + "discord-api-types": "^0.37.41" + }, + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/@discordjs/formatters/node_modules/discord-api-types": { + "version": "0.37.48", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.48.tgz", + "integrity": "sha512-vu2NQJD7SZRjpKDC2DPNsxTz34KS53OrotA+LGRW6mcyT55Hjqu66aRrouzjYhea7tllL9I7rvWVX7bg3aT2AQ==", + "license": "MIT" + }, + "node_modules/@discordjs/rest": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-0.3.0.tgz", + "integrity": "sha512-F9aeP3odlAlllM1ciBZLdd+adiAyBj4VaZBejj4UMj4afE2wfCkNTGvYYiRxrXUE9fN7e/BuDP2ePl0tVA2m7Q==", + "license": "Apache-2.0", + "dependencies": { + "@discordjs/collection": "^0.4.0", + "@sapphire/async-queue": "^1.1.9", + "@sapphire/snowflake": "^3.0.1", + "discord-api-types": "^0.26.1", + "form-data": "^4.0.0", + "node-fetch": "^2.6.5", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/@discordjs/rest/node_modules/@discordjs/collection": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.4.0.tgz", + "integrity": "sha512-zmjq+l/rV35kE6zRrwe8BHqV78JvIh2ybJeZavBi5NySjWXqN3hmmAKg7kYMMXSeiWtSsMoZ/+MQi0DiQWy2lw==", + "license": "Apache-2.0", + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@discordjs/rest/node_modules/discord-api-types": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.26.1.tgz", + "integrity": "sha512-T5PdMQ+Y1MEECYMV5wmyi9VEYPagEDEi4S0amgsszpWY0VB9JJ/hEvM6BgLhbdnKky4gfmZEXtEEtojN8ZKJQQ==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/@discordjs/rest/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@discordjs/util": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-0.3.1.tgz", + "integrity": "sha512-HxXKYKg7vohx2/OupUN/4Sd02Ev3PBJ5q0gtjdcvXb0ErCva8jNHWfe/v5sU3UKjIB/uxOhc+TDOnhqffj9pRA==", + "license": "Apache-2.0", + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/@discordjs/voice": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@discordjs/voice/-/voice-0.17.0.tgz", + "integrity": "sha512-hArn9FF5ZYi1IkxdJEVnJi+OxlwLV0NJYWpKXsmNOojtGtAZHxmsELA+MZlu2KW1F/K1/nt7lFOfcMXNYweq9w==", + "license": "Apache-2.0", + "dependencies": { + "@types/ws": "^8.5.10", + "discord-api-types": "0.37.83", + "prism-media": "^1.3.5", + "tslib": "^2.6.2", + "ws": "^8.16.0" + }, + "engines": { + "node": ">=16.11.0" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, + "node_modules/@discordjs/voice/node_modules/@types/ws": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@discordjs/voice/node_modules/discord-api-types": { + "version": "0.37.83", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.83.tgz", + "integrity": "sha512-urGGYeWtWNYMKnYlZnOnDHm8fVRffQs3U0SpE8RHeiuLKb/u92APS8HoQnPTFbnXmY1vVnXjXO4dOxcAn3J+DA==", + "license": "MIT" + }, + "node_modules/@discordjs/voice/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "license": "0BSD" + }, + "node_modules/@discordjs/voice/node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@discordjs/ws": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-0.8.3.tgz", + "integrity": "sha512-hcYtppanjHecbdNyCKQNH2I4RP9UrphDgmRgLYrATEQF1oo4sYSve7ZmGsBEXSzH72MO2tBPdWSThunbxUVk0g==", + "license": "Apache-2.0", + "dependencies": { + "@discordjs/collection": "^1.5.1", + "@discordjs/rest": "^1.7.1", + "@discordjs/util": "^0.3.1", + "@sapphire/async-queue": "^1.5.0", + "@types/ws": "^8.5.4", + "@vladfrangu/async_event_emitter": "^2.2.1", + "discord-api-types": "^0.37.41", + "tslib": "^2.5.0", + "ws": "^8.13.0" + }, + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/@discordjs/ws/node_modules/@discordjs/rest": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-1.7.1.tgz", + "integrity": "sha512-Ofa9UqT0U45G/eX86cURQnX7gzOJLG2oC28VhIk/G6IliYgQF7jFByBJEykPSHE4MxPhqCleYvmsrtfKh1nYmQ==", + "license": "Apache-2.0", + "dependencies": { + "@discordjs/collection": "^1.5.1", + "@discordjs/util": "^0.3.0", + "@sapphire/async-queue": "^1.5.0", + "@sapphire/snowflake": "^3.4.2", + "discord-api-types": "^0.37.41", + "file-type": "^18.3.0", + "tslib": "^2.5.0", + "undici": "^5.22.0" + }, + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/@discordjs/ws/node_modules/discord-api-types": { + "version": "0.37.48", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.48.tgz", + "integrity": "sha512-vu2NQJD7SZRjpKDC2DPNsxTz34KS53OrotA+LGRW6mcyT55Hjqu66aRrouzjYhea7tllL9I7rvWVX7bg3aT2AQ==", + "license": "MIT" + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", + "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.0.tgz", + "integrity": "sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "8.44.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz", + "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@google-cloud/local-auth": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@google-cloud/local-auth/-/local-auth-2.1.1.tgz", + "integrity": "sha512-tOJ73TSyPxelUEVN2AdHVzFG857U5i3wZHMUGgm6wRtz9WN4O3D761eYORB9jXfIggA3+v5BUw+VIE5wAKHhkg==", + "license": "Apache-2.0", + "dependencies": { + "arrify": "^2.0.1", + "google-auth-library": "^8.0.2", + "open": "^7.0.3", + "server-destroy": "^1.0.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", + "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", + "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/core": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", + "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", + "license": "MIT", + "dependencies": { + "@jest/console": "^27.5.1", + "@jest/reporters": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^27.5.1", + "jest-config": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-resolve-dependencies": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "jest-watcher": "^27.5.1", + "micromatch": "^4.0.4", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", + "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", + "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "@sinonjs/fake-timers": "^8.0.1", + "@types/node": "*", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", + "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", + "license": "MIT", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/types": "^27.5.1", + "expect": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", + "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-haste-map": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^4.0.1", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^8.1.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/source-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", + "integrity": "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==", + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9", + "source-map": "^0.6.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", + "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", + "license": "MIT", + "dependencies": { + "@jest/console": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz", + "integrity": "sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==", + "license": "MIT", + "dependencies": { + "@jest/test-result": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-runtime": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", + "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.1.0", + "@jest/types": "^27.5.1", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", + "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@messageformat/core": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@messageformat/core/-/core-3.2.0.tgz", + "integrity": "sha512-ppbb/7OYqg/t4WdFk8VAfZEV2sNUq3+7VeBAo5sKFhmF786sh6gB7fUeXa2qLTDIcTHS49HivTBN7QNOU5OFTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@messageformat/date-skeleton": "^1.0.0", + "@messageformat/number-skeleton": "^1.0.0", + "@messageformat/parser": "^5.1.0", + "@messageformat/runtime": "^3.0.1", + "make-plural": "^7.0.0", + "safe-identifier": "^0.4.1" + } + }, + "node_modules/@messageformat/date-skeleton": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@messageformat/date-skeleton/-/date-skeleton-1.0.1.tgz", + "integrity": "sha512-jPXy8fg+WMPIgmGjxSlnGJn68h/2InfT0TNSkVx0IGXgp4ynnvYkbZ51dGWmGySEK+pBiYUttbQdu5XEqX5CRg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@messageformat/number-skeleton": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@messageformat/number-skeleton/-/number-skeleton-1.2.0.tgz", + "integrity": "sha512-xsgwcL7J7WhlHJ3RNbaVgssaIwcEyFkBqxHdcdaiJzwTZAWEOD8BuUFxnxV9k5S0qHN3v/KzUpq0IUpjH1seRg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@messageformat/parser": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@messageformat/parser/-/parser-5.1.0.tgz", + "integrity": "sha512-jKlkls3Gewgw6qMjKZ9SFfHUpdzEVdovKFtW1qRhJ3WI4FW5R/NnGDqr8SDGz+krWDO3ki94boMmQvGke1HwUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "moo": "^0.5.1" + } + }, + "node_modules/@messageformat/runtime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@messageformat/runtime/-/runtime-3.0.1.tgz", + "integrity": "sha512-6RU5ol2lDtO8bD9Yxe6CZkl0DArdv0qkuoZC+ZwowU+cdRlVE1157wjCmlA5Rsf1Xc/brACnsZa5PZpEDfTFFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "make-plural": "^7.0.0" + } + }, + "node_modules/@nicolo-ribaudo/semver-v6": { + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/semver-v6/-/semver-v6-6.3.3.tgz", + "integrity": "sha512-3Yc1fUTs69MG/uZbJlLSI3JISMn2UV2rg+1D/vROUqZyh3l6iYHCs7GMp+M40ZD7yOdDbYjJcU1oTJhrc+dGKg==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@prettier/eslint": { + "name": "prettier-eslint", + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/prettier-eslint/-/prettier-eslint-15.0.1.tgz", + "integrity": "sha512-mGOWVHixSvpZWARqSDXbdtTL54mMBxc5oQYQ6RAqy8jecuNJBgN3t9E5a81G66F8x8fsKNiR1HWaBV66MJDOpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint": "^8.4.2", + "@types/prettier": "^2.6.0", + "@typescript-eslint/parser": "^5.10.0", + "common-tags": "^1.4.0", + "dlv": "^1.1.0", + "eslint": "^8.7.0", + "indent-string": "^4.0.0", + "lodash.merge": "^4.6.0", + "loglevel-colored-level-prefix": "^1.0.0", + "prettier": "^2.5.1", + "pretty-format": "^23.0.1", + "require-relative": "^0.8.7", + "typescript": "^4.5.4", + "vue-eslint-parser": "^8.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@prettier/eslint/node_modules/ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@prettier/eslint/node_modules/pretty-format": { + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz", + "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^3.0.0", + "ansi-styles": "^3.2.0" + } + }, + "node_modules/@prisma/client": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.2.0.tgz", + "integrity": "sha512-AiTjJwR4J5Rh6Z/9ZKrBBLel3/5DzUNntMohOy7yObVnVoTNVFi2kvpLZlFuKO50d7yDspOtW6XBpiAd0BVXbQ==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/engines-version": "5.2.0-25.2804dc98259d2ea960602aca6b8e7fdc03c1758f" + }, + "engines": { + "node": ">=16.13" + }, + "peerDependencies": { + "prisma": "*" + }, + "peerDependenciesMeta": { + "prisma": { + "optional": true + } + } + }, + "node_modules/@prisma/engines": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.2.0.tgz", + "integrity": "sha512-dT7FOLUCdZmq+AunLqB1Iz+ZH/IIS1Fz2THmKZQ6aFONrQD/BQ5ecJ7g2wGS2OgyUFf4OaLam6/bxmgdOBDqig==", + "hasInstallScript": true, + "license": "Apache-2.0" + }, + "node_modules/@prisma/engines-version": { + "version": "5.2.0-25.2804dc98259d2ea960602aca6b8e7fdc03c1758f", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.2.0-25.2804dc98259d2ea960602aca6b8e7fdc03c1758f.tgz", + "integrity": "sha512-jsnKT5JIDIE01lAeCj2ghY9IwxkedhKNvxQeoyLs6dr4ZXynetD0vTy7u6wMJt8vVPv8I5DPy/I4CFaoXAgbtg==", + "license": "Apache-2.0" + }, + "node_modules/@redis/bloom": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz", + "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==", + "license": "MIT", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/client": { + "version": "1.5.8", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.8.tgz", + "integrity": "sha512-xzElwHIO6rBAqzPeVnCzgvrnBEcFL1P0w8P65VNLRkdVW8rOE58f52hdj0BDgmsdOm4f1EoXPZtH4Fh7M/qUpw==", + "license": "MIT", + "dependencies": { + "cluster-key-slot": "1.1.2", + "generic-pool": "3.9.0", + "yallist": "4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@redis/graph": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.0.tgz", + "integrity": "sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==", + "license": "MIT", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/json": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.4.tgz", + "integrity": "sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==", + "license": "MIT", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/search": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.3.tgz", + "integrity": "sha512-4Dg1JjvCevdiCBTZqjhKkGoC5/BcB7k9j99kdMnaXFXg8x4eyOIVg9487CMv7/BUVkFLZCaIh8ead9mU15DNng==", + "license": "MIT", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/time-series": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.4.tgz", + "integrity": "sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==", + "license": "MIT", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@sapphire/async-queue": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.0.tgz", + "integrity": "sha512-JkLdIsP8fPAdh9ZZjrbHWR/+mZj0wvKS5ICibcLrRI1j84UmLMshx5n9QmL8b95d4onJ2xxiyugTgSAX7AalmA==", + "license": "MIT", + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@sapphire/shapeshift": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.2.tgz", + "integrity": "sha512-YRbCXWy969oGIdqR/wha62eX8GNHsvyYi0Rfd4rNW6tSVVa8p0ELiMEuOH/k8rgtvRoM+EMV7Csqz77YdwiDpA==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@sapphire/snowflake": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.1.tgz", + "integrity": "sha512-BxcYGzgEsdlG0dKAyOm0ehLGm2CafIrfQTZGWgkfKYbj+pNNsorZ7EotuZukc2MT70E0UbppVbtpBrqpzVzjNA==", + "license": "MIT", + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", + "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", + "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/@sqltools/formatter": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.5.tgz", + "integrity": "sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==", + "license": "MIT" + }, + "node_modules/@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", + "license": "MIT" + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/babel__core": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.1.tgz", + "integrity": "sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.1.tgz", + "integrity": "sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/eslint": { + "version": "8.44.0", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.0.tgz", + "integrity": "sha512-gsF+c/0XOguWgaOgvFs+xnnRqt9GwgTvIks36WpE6ueeI4KCEHHd8K/CKHqhOqrJKsYH8m27kRzQEvWXAwXUTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", + "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/google-spreadsheet": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@types/google-spreadsheet/-/google-spreadsheet-3.3.2.tgz", + "integrity": "sha512-uBwRhNwx5JPsmrV+XmD77dxL8vVdOY/Aba1kx/mxtR6jePLZIN06I1jjEXEFidAyLUz+JWCphsVk8CCJ2Kzy2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", + "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "27.5.2", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.5.2.tgz", + "integrity": "sha512-mpT8LJJ4CMeeahobofYWIjFo0xonRS/HfxnVEPMPFSQdGUt1uHCnoPT7Zhb+sjDU2wz0oKV0OLUR0WzrHNgfeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-matcher-utils": "^27.0.0", + "pretty-format": "^27.0.0" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", + "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/lodash": { + "version": "4.14.195", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.195.tgz", + "integrity": "sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/moment-timezone": { + "version": "0.5.30", + "resolved": "https://registry.npmjs.org/@types/moment-timezone/-/moment-timezone-0.5.30.tgz", + "integrity": "sha512-aDVfCsjYnAQaV/E9Qc24C5Njx1CoDjXsEgkxtp9NyXDpYu4CCbmclb6QhWloS9UTU/8YROUEEdEkWI0D7DxnKg==", + "license": "MIT", + "dependencies": { + "moment-timezone": "*" + } + }, + "node_modules/@types/node": { + "version": "20.4.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.3.tgz", + "integrity": "sha512-Yu3+r4Mn/iY6Mf0aihncZQ1qOjOUrCiodbHHY1hds5O+7BbKp9t+Li7zLO13zO8j9L2C6euz8xsYQP0rjGvVXw==", + "license": "MIT" + }, + "node_modules/@types/node-fetch": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.4.tgz", + "integrity": "sha512-1ZX9fcN4Rvkvgv4E6PAY5WXUFWFcRWxZa3EW83UjycOB9ljJCedb2CupIP4RZMEwF/M3eTcCihbBRgwtGbg5Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "form-data": "^3.0.0" + } + }, + "node_modules/@types/pg": { + "version": "8.10.2", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.10.2.tgz", + "integrity": "sha512-MKFs9P6nJ+LAeHLU3V0cODEOgyThJ3OAnmOlsZsxux6sfQs3HRXR5bBn7xG5DjckEFhTAxsXi7k7cd0pCMxpJw==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^4.0.1" + } + }, + "node_modules/@types/pg/node_modules/pg-types": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-4.0.1.tgz", + "integrity": "sha512-hRCSDuLII9/LE3smys1hRHcu5QGcLs9ggT7I/TCs0IE+2Eesxi9+9RWAAwZ0yaGjxoWICF/YHLOEjydGujoJ+g==", + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "pg-numeric": "1.0.2", + "postgres-array": "~3.0.1", + "postgres-bytea": "~3.0.0", + "postgres-date": "~2.0.1", + "postgres-interval": "^3.0.0", + "postgres-range": "^1.1.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@types/pg/node_modules/postgres-array": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.2.tgz", + "integrity": "sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/@types/pg/node_modules/postgres-bytea": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-3.0.0.tgz", + "integrity": "sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==", + "license": "MIT", + "dependencies": { + "obuf": "~1.1.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@types/pg/node_modules/postgres-date": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-2.0.1.tgz", + "integrity": "sha512-YtMKdsDt5Ojv1wQRvUhnyDJNSr2dGIC96mQVKz7xufp07nfuFONzdaowrMHjlAzY6GDLd4f+LUHHAAM1h4MdUw==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/@types/pg/node_modules/postgres-interval": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-3.0.0.tgz", + "integrity": "sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/@types/prettier": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", + "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==", + "license": "MIT" + }, + "node_modules/@types/semver": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "license": "MIT" + }, + "node_modules/@types/ws": { + "version": "8.5.5", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz", + "integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", + "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/type-utils": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", + "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", + "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vladfrangu/async_event_emitter": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.2.2.tgz", + "integrity": "sha512-HIzRG7sy88UZjBJamssEczH5q7t5+axva19UbZLO6u0ySbYPrwzWiXBcC0WuHyhKKoeCyneH+FvYzKQq/zTtkQ==", + "license": "MIT", + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "license": "BSD-3-Clause" + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true, + "license": "ISC" + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "license": "MIT", + "dependencies": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, + "node_modules/acorn-globals/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-globals/node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/adler-32": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", + "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=", + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/app-root-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.1.0.tgz", + "integrity": "sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==", + "license": "MIT", + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/async-mutex": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.4.0.tgz", + "integrity": "sha512-eJFZ1YhRR8UN8eBLoNzcDPcy/jqjsg6I1AP+KvWQX80BqOSW1oJPJXDylPUEeMr2ZQvHgnQ//Lp6f3RQ1zI7HA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axios": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", + "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axios-retry": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/axios-retry/-/axios-retry-3.5.1.tgz", + "integrity": "sha512-mQRJ4IyAUnYig14BQ4MnnNHHuH1cNH7NW4JxEUD6mNJwK6pwOY66wKLCwZ6Y0o3POpfStalqRC+J4+Hnn6Om7w==", + "license": "Apache-2.0", + "dependencies": { + "@babel/runtime": "^7.15.4", + "is-retry-allowed": "^2.2.0" + } + }, + "node_modules/axios/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/babel-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", + "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", + "license": "MIT", + "dependencies": { + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", + "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", + "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "^27.5.1", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bignumber.js": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz", + "integrity": "sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/boolify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/boolify/-/boolify-1.0.1.tgz", + "integrity": "sha512-ma2q0Tc760dW54CdOyJjhrg/a54317o1zYADQJFgperNGKIKgAUGIcKnuMiff8z57+yGlrGNEt4lPgZfCgTJgA==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "license": "BSD-2-Clause" + }, + "node_modules/browserslist": { + "version": "4.21.9", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz", + "integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001503", + "electron-to-chromium": "^1.4.431", + "node-releases": "^2.0.12", + "update-browserslist-db": "^1.0.11" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-keys": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-7.0.2.tgz", + "integrity": "sha512-Rjs1H+A9R+Ig+4E/9oyB66UC5Mj9Xq3N//vcLf2WzgdTi/3gUu3Z9KoqmlrEG4VuuLK8wJHofxzdQXz/knhiYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase": "^6.3.0", + "map-obj": "^4.1.0", + "quick-lru": "^5.1.1", + "type-fest": "^1.2.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-keys/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-keys/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001515", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001515.tgz", + "integrity": "sha512-eEFDwUOZbE24sb+Ecsx3+OvNETqjWIdabMy52oOkIgcUtAsQifjUG9q4U9dgTHJM2mfk4uEPxc0+xuFdJ629QA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "license": "Apache-2.0" + }, + "node_modules/cfb": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz", + "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==", + "license": "Apache-2.0", + "dependencies": { + "adler-32": "~1.3.0", + "crc-32": "~1.2.0" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/chalk/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/chalk/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/ci-info": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", + "license": "MIT" + }, + "node_modules/cli-highlight": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz", + "integrity": "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==", + "license": "ISC", + "dependencies": { + "chalk": "^4.0.0", + "highlight.js": "^10.7.1", + "mz": "^2.4.0", + "parse5": "^5.1.1", + "parse5-htmlparser2-tree-adapter": "^6.0.0", + "yargs": "^16.0.0" + }, + "bin": { + "highlight": "bin/highlight" + }, + "engines": { + "node": ">=8.0.0", + "npm": ">=5.0.0" + } + }, + "node_modules/cli-highlight/node_modules/parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "license": "MIT" + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/codepage": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz", + "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/common-tags": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", + "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "license": "MIT" + }, + "node_modules/concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "engines": [ + "node >= 6.0" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "license": "MIT" + }, + "node_modules/core-js": { + "version": "3.31.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.31.1.tgz", + "integrity": "sha512-2sKLtfq1eFST7l7v62zaqXacPc7uG8ZAya8ogijLhTtaKNcpzpB4TMoTw2Si+8GYKRwFPMMtUT0263QFWFfqyQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "license": "MIT" + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "license": "MIT", + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "license": "MIT" + }, + "node_modules/data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "license": "MIT", + "dependencies": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "license": "MIT" + }, + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "license": "MIT" + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "devOptional": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "license": "MIT", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/discord-api-types": { + "version": "0.31.2", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.31.2.tgz", + "integrity": "sha512-gpzXTvFVg7AjKVVJFH0oJGC0q0tO34iJGSHZNz9u3aqLxlD6LfxEs9wWVVikJqn9gra940oUTaPFizCkRDcEiA==", + "license": "MIT" + }, + "node_modules/discord.js": { + "version": "14.11.0", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.11.0.tgz", + "integrity": "sha512-CkueWYFQ28U38YPR8HgsBR/QT35oPpMbEsTNM30Fs8loBIhnA4s70AwQEoy6JvLcpWWJO7GY0y2BUzZmuBMepQ==", + "license": "Apache-2.0", + "dependencies": { + "@discordjs/builders": "^1.6.3", + "@discordjs/collection": "^1.5.1", + "@discordjs/formatters": "^0.3.1", + "@discordjs/rest": "^1.7.1", + "@discordjs/util": "^0.3.1", + "@discordjs/ws": "^0.8.3", + "@sapphire/snowflake": "^3.4.2", + "@types/ws": "^8.5.4", + "discord-api-types": "^0.37.41", + "fast-deep-equal": "^3.1.3", + "lodash.snakecase": "^4.1.1", + "tslib": "^2.5.0", + "undici": "^5.22.0", + "ws": "^8.13.0" + }, + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/discord.js/node_modules/@discordjs/builders": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.6.4.tgz", + "integrity": "sha512-ARFKvmAkLhfkQQiNxqi0YIWqwUExvBRtvdtMFVJXvJoibsGkFrB/DWTf9byU7BTVUfsmW8w7NM55tYXR5S/iSg==", + "license": "Apache-2.0", + "dependencies": { + "@discordjs/formatters": "^0.3.1", + "@discordjs/util": "^1.0.0", + "@sapphire/shapeshift": "^3.9.2", + "discord-api-types": "^0.37.50", + "fast-deep-equal": "^3.1.3", + "ts-mixer": "^6.0.3", + "tslib": "^2.6.1" + }, + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/discord.js/node_modules/@discordjs/builders/node_modules/@discordjs/util": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.0.0.tgz", + "integrity": "sha512-U2Iiab0mo8cFe+o4ZY4GROoAetGjFYA1PhhxiXEW82LuPUjOU/seHZDtVjDpOf6n3rz4IRm84wNtgHdpqRY5CA==", + "license": "Apache-2.0", + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/discord.js/node_modules/@discordjs/builders/node_modules/discord-api-types": { + "version": "0.37.52", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.52.tgz", + "integrity": "sha512-TP99aMgY6rHuDIy056GDm1j2nGOcaLbFpjVbvAmv6N6vhkjHNqHXCHVqKtGisaQ8D15slbxTHNl/SSkPdx2syg==", + "license": "MIT" + }, + "node_modules/discord.js/node_modules/@discordjs/builders/node_modules/tslib": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", + "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==", + "license": "0BSD" + }, + "node_modules/discord.js/node_modules/@discordjs/rest": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-1.7.1.tgz", + "integrity": "sha512-Ofa9UqT0U45G/eX86cURQnX7gzOJLG2oC28VhIk/G6IliYgQF7jFByBJEykPSHE4MxPhqCleYvmsrtfKh1nYmQ==", + "license": "Apache-2.0", + "dependencies": { + "@discordjs/collection": "^1.5.1", + "@discordjs/util": "^0.3.0", + "@sapphire/async-queue": "^1.5.0", + "@sapphire/snowflake": "^3.4.2", + "discord-api-types": "^0.37.41", + "file-type": "^18.3.0", + "tslib": "^2.5.0", + "undici": "^5.22.0" + }, + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/discord.js/node_modules/discord-api-types": { + "version": "0.37.48", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.48.tgz", + "integrity": "sha512-vu2NQJD7SZRjpKDC2DPNsxTz34KS53OrotA+LGRW6mcyT55Hjqu66aRrouzjYhea7tllL9I7rvWVX7bg3aT2AQ==", + "license": "MIT" + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true, + "license": "MIT" + }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "license": "MIT", + "dependencies": { + "webidl-conversions": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/domexception/node_modules/webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.456", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.456.tgz", + "integrity": "sha512-d+eSL4mT9m72cnDT/kfQj6Pv6Cid4pUVlLOl8esm2SZuXBgtXtUyvCfc9F++GHLWLoY4gMNqg+0IVAoQ3sosKA==", + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", + "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.21.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz", + "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.2.0", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.7", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/eslint": { + "version": "8.44.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.44.0.tgz", + "integrity": "sha512-0wpHoUbDUHgNCyvFB5aXLiQVfK9B0at6gUvzy83k4kAsQ/u769TQDX6iKC+aO4upIHO9WSaA3QoXYQDHbNwf1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.1.0", + "@eslint/js": "8.44.0", + "@humanwhocodes/config-array": "^0.11.10", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.0", + "eslint-visitor-keys": "^3.4.1", + "espree": "^9.6.0", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz", + "integrity": "sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", + "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.11.0", + "resolve": "^1.22.1" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint-module-utils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", + "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint-plugin-import": { + "version": "2.27.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", + "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.1", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.7.4", + "has": "^1.0.3", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.6", + "resolve": "^1.22.1", + "semver": "^6.3.0", + "tsconfig-paths": "^3.14.1" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", + "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prettier-linter-helpers": "^1.0.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "eslint": ">=7.28.0", + "prettier": ">=2.0.0" + }, + "peerDependenciesMeta": { + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", + "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", + "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.0.tgz", + "integrity": "sha512-1FH/IiruXZ84tpUlm0aCUEwMl2Ho5ilqVh0VvQXw+byAz/4SAciyHLlfmL5WYqsvD38oymdUwBss0LtK8m4s/A==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/fast-glob": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz", + "integrity": "sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-text-encoding": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz", + "integrity": "sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w==", + "license": "Apache-2.0" + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/ffmpeg-static": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ffmpeg-static/-/ffmpeg-static-5.2.0.tgz", + "integrity": "sha512-WrM7kLW+do9HLr+H6tk7LzQ7kPqbAgLjdzNE32+u3Ff11gXt9Kkkd2nusGFrlWMIe+XaA97t+I8JS7sZIrvRgA==", + "hasInstallScript": true, + "license": "GPL-3.0-or-later", + "dependencies": { + "@derhuerst/http-basic": "^8.2.0", + "env-paths": "^2.2.0", + "https-proxy-agent": "^5.0.0", + "progress": "^2.0.3" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/file-type": { + "version": "18.5.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-18.5.0.tgz", + "integrity": "sha512-yvpl5U868+V6PqXHMmsESpg6unQ5GfnPssl4dxdJudBrr9qy7Fddt7EVX1VLlddFfe8Gj9N7goCZH22FXuSQXQ==", + "license": "MIT", + "dependencies": { + "readable-web-to-node-stream": "^3.0.2", + "strtok3": "^7.0.0", + "token-types": "^5.0.1" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/file-type?sponsor=1" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/frac": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", + "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "license": "MIT" + }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gaxios": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.1.3.tgz", + "integrity": "sha512-95hVgBRgEIRQQQHIbnxBXeHbW4TqFk4ZDJW7wmVtvYar72FdhRIo1UGOLS2eRAKCPEdPBWu+M7+A33D9CdX9rA==", + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/gcp-metadata": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-5.3.0.tgz", + "integrity": "sha512-FNTkdNEnBdlqF2oatizolQqNANMrcqJt6AAYt99B3y1aLLC8Hc5IOBb+ZnnzllodEEf6xMBp6wRcBbc16fa65w==", + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^5.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/generic-pool": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", + "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stdin": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", + "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/google-auth-library": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-8.9.0.tgz", + "integrity": "sha512-f7aQCJODJFmYWN6PeNKzgvy9LI2tYmXnzpNDHEjG5sDNPgGb2FXQyTBnXeSH+PAtpKESFD+LmHw3Ox3mN7e1Fg==", + "license": "Apache-2.0", + "dependencies": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^5.0.0", + "gcp-metadata": "^5.3.0", + "gtoken": "^6.1.0", + "jws": "^4.0.0", + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/google-auth-library/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/google-p12-pem": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-4.0.1.tgz", + "integrity": "sha512-WPkN4yGtz05WZ5EhtlxNDWPhC4JIic6G8ePitwUWy4l+XPVYec+a0j0Ts47PDtW59y3RwAhUd9/h9ZZ63px6RQ==", + "license": "MIT", + "dependencies": { + "node-forge": "^1.3.1" + }, + "bin": { + "gp12-pem": "build/src/bin/gp12-pem.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/google-spreadsheet": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/google-spreadsheet/-/google-spreadsheet-3.3.0.tgz", + "integrity": "sha512-ahmRNh14s1i3phfvbF2mxen1lohWJpUaFWgsU6P6bXu7QrmxMaim1Ys/7BU4W5yucWCzphoIrHMbrbeIR5K9mw==", + "license": "Unlicense", + "dependencies": { + "axios": "^0.21.4", + "google-auth-library": "^6.1.3", + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/google-spreadsheet/node_modules/axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.14.0" + } + }, + "node_modules/google-spreadsheet/node_modules/gaxios": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-4.3.3.tgz", + "integrity": "sha512-gSaYYIO1Y3wUtdfHmjDUZ8LWaxJQpiavzbF5Kq53akSzvmVg0RfyOcFDbO1KJ/KCGRFz2qG+lS81F0nkr7cRJA==", + "license": "Apache-2.0", + "dependencies": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.7" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/google-spreadsheet/node_modules/gcp-metadata": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.3.1.tgz", + "integrity": "sha512-x850LS5N7V1F3UcV7PoupzGsyD6iVwTVvsh3tbXfkctZnBnjW5yu5z1/3k3SehF7TyoTIe78rJs02GMMy+LF+A==", + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^4.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/google-spreadsheet/node_modules/google-auth-library": { + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.1.6.tgz", + "integrity": "sha512-Q+ZjUEvLQj/lrVHF/IQwRo6p3s8Nc44Zk/DALsN+ac3T4HY/g/3rrufkgtl+nZ1TW7DNAw5cTChdVp4apUXVgQ==", + "license": "Apache-2.0", + "dependencies": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^4.0.0", + "gcp-metadata": "^4.2.0", + "gtoken": "^5.0.4", + "jws": "^4.0.0", + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/google-spreadsheet/node_modules/google-p12-pem": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.1.4.tgz", + "integrity": "sha512-HHuHmkLgwjdmVRngf5+gSmpkyaRI6QmOg77J8tkNBHhNEI62sGHyw4/+UkgyZEI7h84NbWprXDJ+sa3xOYFvTg==", + "license": "MIT", + "dependencies": { + "node-forge": "^1.3.1" + }, + "bin": { + "gp12-pem": "build/src/bin/gp12-pem.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/google-spreadsheet/node_modules/gtoken": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.3.2.tgz", + "integrity": "sha512-gkvEKREW7dXWF8NV8pVrKfW7WqReAmjjkMBh6lNCCGOM4ucS0r0YyXXl0r/9Yj8wcW/32ISkfc8h5mPTDbtifQ==", + "license": "MIT", + "dependencies": { + "gaxios": "^4.0.0", + "google-p12-pem": "^3.1.3", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/google-spreadsheet/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/googleapis": { + "version": "105.0.0", + "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-105.0.0.tgz", + "integrity": "sha512-wH/jU/6QpqwsjTKj4vfKZz97ne7xT7BBbKwzQEwnbsG8iH9Seyw19P+AuLJcxNNrmgblwLqfr3LORg4Okat1BQ==", + "license": "Apache-2.0", + "dependencies": { + "google-auth-library": "^8.0.2", + "googleapis-common": "^6.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/googleapis-common": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-6.0.4.tgz", + "integrity": "sha512-m4ErxGE8unR1z0VajT6AYk3s6a9gIMM6EkDZfkPnES8joeOlEtFEJeF8IyZkb0tjPXkktUfYrE4b3Li1DNyOwA==", + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "gaxios": "^5.0.1", + "google-auth-library": "^8.0.2", + "qs": "^6.7.0", + "url-template": "^2.0.8", + "uuid": "^9.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/gtoken": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-6.1.2.tgz", + "integrity": "sha512-4ccGpzz7YAr7lxrT2neugmXQ3hP9ho2gcaityLVkiUecAiwiy60Ii8gRbZeOsXV19fYaRjgBSshs8kXw+NKCPQ==", + "license": "MIT", + "dependencies": { + "gaxios": "^5.0.1", + "google-p12-pem": "^4.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^1.0.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "license": "MIT" + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "license": "MIT", + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-response-object": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz", + "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==", + "license": "MIT", + "dependencies": { + "@types/node": "^10.0.3" + } + }, + "node_modules/http-response-object/node_modules/@types/node": { + "version": "10.17.60", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", + "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", + "license": "MIT" + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", + "dev": true, + "license": "ISC" + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/internal-slot": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "license": "MIT" + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", + "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", + "license": "MIT", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "license": "MIT" + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-retry-allowed": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz", + "integrity": "sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "license": "MIT" + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", + "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", + "license": "MIT", + "dependencies": { + "@jest/core": "^27.5.1", + "import-local": "^3.0.2", + "jest-cli": "^27.5.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", + "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "execa": "^5.0.0", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-circus": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", + "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", + "license": "MIT", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-cli": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", + "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", + "license": "MIT", + "dependencies": { + "@jest/core": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "prompts": "^2.0.1", + "yargs": "^16.2.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", + "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.8.0", + "@jest/test-sequencer": "^27.5.1", + "@jest/types": "^27.5.1", + "babel-jest": "^27.5.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.9", + "jest-circus": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-jasmine2": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", + "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", + "license": "MIT", + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-each": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", + "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-environment-jsdom": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", + "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", + "license": "MIT", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1", + "jsdom": "^16.6.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", + "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", + "license": "MIT", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "license": "MIT", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "micromatch": "^4.0.4", + "walker": "^1.0.7" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-jasmine2": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", + "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", + "license": "MIT", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-leak-detector": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", + "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", + "license": "MIT", + "dependencies": { + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-mock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "license": "MIT", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", + "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", + "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-snapshot": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runner": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", + "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", + "license": "MIT", + "dependencies": { + "@jest/console": "^27.5.1", + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-leak-detector": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "source-map-support": "^0.5.6", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", + "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", + "license": "MIT", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/globals": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runtime/node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-serializer": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", + "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", + "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.7.2", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.0.0", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__traverse": "^7.0.4", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^27.5.1", + "semver": "^7.3.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-validate": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", + "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", + "license": "MIT", + "dependencies": { + "@jest/types": "^27.5.1", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "leven": "^3.1.0", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", + "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", + "license": "MIT", + "dependencies": { + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "jest-util": "^27.5.1", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdom": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "license": "MIT", + "dependencies": { + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "license": "MIT", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/libsodium": { + "version": "0.7.13", + "resolved": "https://registry.npmjs.org/libsodium/-/libsodium-0.7.13.tgz", + "integrity": "sha512-mK8ju0fnrKXXfleL53vtp9xiPq5hKM0zbDQtcxQIsSmxNgSxqCj6R7Hl9PkrNe2j29T4yoDaF7DJLK9/i5iWUw==", + "license": "ISC" + }, + "node_modules/libsodium-wrappers": { + "version": "0.7.13", + "resolved": "https://registry.npmjs.org/libsodium-wrappers/-/libsodium-wrappers-0.7.13.tgz", + "integrity": "sha512-kasvDsEi/r1fMzKouIDv7B8I6vNmknXwGiYodErGuESoFTohGSKZplFtVxZqHaoQ217AynyIFgnOVRitpHs0Qw==", + "license": "ISC", + "dependencies": { + "libsodium": "^0.7.13" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", + "license": "MIT" + }, + "node_modules/loglevel": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.8.1.tgz", + "integrity": "sha512-tCRIJM51SHjAayKwC+QAg8hT8vg6z7GSgLJKGvzuPb1Wc+hLzqtuVLxp6/HzSPOozuK+8ErAhy7U/sVzw8Dgfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/loglevel" + } + }, + "node_modules/loglevel-colored-level-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/loglevel-colored-level-prefix/-/loglevel-colored-level-prefix-1.0.0.tgz", + "integrity": "sha1-akAhj9x64V/HbD0PPmdsRlOIYD4=", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^1.1.3", + "loglevel": "^1.4.1" + } + }, + "node_modules/loglevel-colored-level-prefix/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loglevel-colored-level-prefix/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loglevel-colored-level-prefix/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loglevel-colored-level-prefix/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/m3u8stream": { + "version": "0.8.6", + "resolved": "https://registry.npmjs.org/m3u8stream/-/m3u8stream-0.8.6.tgz", + "integrity": "sha512-LZj8kIVf9KCphiHmH7sbFQTVe4tOemb202fWwvJwR9W5ENW/1hxJN6ksAWGhQgSBSa3jyWhnjKU1Fw1GaOdbyA==", + "license": "MIT", + "dependencies": { + "miniget": "^4.2.2", + "sax": "^1.2.4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "devOptional": true, + "license": "ISC" + }, + "node_modules/make-plural": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/make-plural/-/make-plural-7.3.0.tgz", + "integrity": "sha512-/K3BC0KIsO+WK2i94LkMPv3wslMrazrQhfi5We9fMbLlLjzoOSJWr7TAdupLlDWaJcWxwoNosBkhFDejiu5VDw==", + "dev": true, + "license": "Unicode-DFS-2016" + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/miniget": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/miniget/-/miniget-4.2.3.tgz", + "integrity": "sha512-SjbDPDICJ1zT+ZvQwK0hUcRY4wxlhhNpHL9nJOB2MEAXRGagTljsO8MEDzQMTFf0Q8g4QNi8P9lEm/g7e+qgzA==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.6.tgz", + "integrity": "sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==", + "license": "MIT", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/moment-timezone": { + "version": "0.5.43", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.43.tgz", + "integrity": "sha512-72j3aNyuIsDxdF1i7CEgV2FfxM1r6aaqJyLB2vwb33mXYyoyLly+F1zbWqhA3/bVIoJ4szlUoMbUnVdid32NUQ==", + "license": "MIT", + "dependencies": { + "moment": "^2.29.4" + }, + "engines": { + "node": "*" + } + }, + "node_modules/moo": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz", + "integrity": "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "license": "MIT" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "license": "MIT" + }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-fetch": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "license": "(BSD-3-Clause OR GPL-2.0)", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", + "license": "MIT" + }, + "node_modules/nodemon": { + "version": "2.0.22", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", + "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/nodemon/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/nodemon/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nodemon/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/nodemon/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "dev": true, + "license": "MIT", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nwsapi": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", + "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==", + "license": "MIT" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", + "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "license": "MIT" + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==", + "license": "MIT" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-cache-control": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", + "integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==" + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "license": "MIT" + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "license": "MIT", + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/peek-readable": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0.tgz", + "integrity": "sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/pg": { + "version": "8.11.1", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.1.tgz", + "integrity": "sha512-utdq2obft07MxaDg0zBJI+l/M3mBRfIpEN3iSemsz0G5F2/VXx+XzqF4oxrbIZXQxt2AZzIUzyVg/YM6xOP/WQ==", + "license": "MIT", + "dependencies": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.6.1", + "pg-pool": "^3.6.1", + "pg-protocol": "^1.6.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + }, + "engines": { + "node": ">= 8.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.1.1" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", + "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", + "license": "MIT", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.1.tgz", + "integrity": "sha512-w6ZzNu6oMmIzEAYVw+RLK0+nqHPt8K3ZnknKi+g48Ak2pr3dtljJW3o+D/n2zzCG07Zoe9VOX3aiKpj+BN0pjg==", + "license": "MIT" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "license": "ISC", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-numeric": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pg-numeric/-/pg-numeric-1.0.2.tgz", + "integrity": "sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==", + "license": "ISC", + "engines": { + "node": ">=4" + } + }, + "node_modules/pg-pool": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.1.tgz", + "integrity": "sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==", + "license": "MIT", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.0.tgz", + "integrity": "sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==", + "license": "MIT" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "license": "MIT", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-range": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/postgres-range/-/postgres-range-1.1.3.tgz", + "integrity": "sha512-VdlZoocy5lCP0c/t66xAfclglEapXPCIVhqqJRncYpvbCgImF0w67aPKfbqUMr72tO2k5q0TdTZwCLjPTI6C9g==", + "license": "MIT" + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-eslint": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/prettier-eslint/-/prettier-eslint-15.0.1.tgz", + "integrity": "sha512-mGOWVHixSvpZWARqSDXbdtTL54mMBxc5oQYQ6RAqy8jecuNJBgN3t9E5a81G66F8x8fsKNiR1HWaBV66MJDOpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint": "^8.4.2", + "@types/prettier": "^2.6.0", + "@typescript-eslint/parser": "^5.10.0", + "common-tags": "^1.4.0", + "dlv": "^1.1.0", + "eslint": "^8.7.0", + "indent-string": "^4.0.0", + "lodash.merge": "^4.6.0", + "loglevel-colored-level-prefix": "^1.0.0", + "prettier": "^2.5.1", + "pretty-format": "^23.0.1", + "require-relative": "^0.8.7", + "typescript": "^4.5.4", + "vue-eslint-parser": "^8.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/prettier-eslint-cli": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/prettier-eslint-cli/-/prettier-eslint-cli-7.1.0.tgz", + "integrity": "sha512-kMMvV7Mt6VqdJSb25aCkOA7HTIxy5mii2tzBb1vCSmzlIECOzTP2wRPIeAtBky6WdpfN0n1Zxa4E37Atp1IksA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@messageformat/core": "^3.0.1", + "@prettier/eslint": "npm:prettier-eslint@^15.0.1", + "arrify": "^2.0.1", + "boolify": "^1.0.1", + "camelcase-keys": "^7.0.2", + "chalk": "^4.1.2", + "common-tags": "^1.8.2", + "core-js": "^3.24.1", + "eslint": "^8.21.0", + "find-up": "^5.0.0", + "get-stdin": "^8.0.0", + "glob": "^7.2.3", + "ignore": "^5.2.0", + "indent-string": "^4.0.0", + "lodash.memoize": "^4.1.2", + "loglevel-colored-level-prefix": "^1.0.0", + "rxjs": "^7.5.6", + "yargs": "^13.1.1" + }, + "bin": { + "prettier-eslint": "dist/index.js" + }, + "engines": { + "node": ">=12.22" + }, + "peerDependencies": { + "prettier-eslint": "*" + }, + "peerDependenciesMeta": { + "prettier-eslint": { + "optional": true + } + } + }, + "node_modules/prettier-eslint-cli/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/prettier-eslint-cli/node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "node_modules/prettier-eslint-cli/node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true, + "license": "MIT" + }, + "node_modules/prettier-eslint-cli/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prettier-eslint-cli/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/prettier-eslint-cli/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prettier-eslint-cli/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prettier-eslint-cli/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prettier-eslint-cli/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/prettier-eslint-cli/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/prettier-eslint-cli/node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/prettier-eslint-cli/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/prettier-eslint-cli/node_modules/yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "node_modules/prettier-eslint-cli/node_modules/yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "node_modules/prettier-eslint-cli/node_modules/yargs/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/prettier-eslint-cli/node_modules/yargs/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/prettier-eslint-cli/node_modules/yargs/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prettier-eslint-cli/node_modules/yargs/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/prettier-eslint-cli/node_modules/yargs/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/prettier-eslint/node_modules/ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/prettier-eslint/node_modules/pretty-format": { + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz", + "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^3.0.0", + "ansi-styles": "^3.2.0" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prism-media": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-1.3.5.tgz", + "integrity": "sha512-IQdl0Q01m4LrkN1EGIE9lphov5Hy7WWlH6ulf5QdGePLlPas9p2mhgddTEHrlaXYjjFToM1/rWuwF37VF4taaA==", + "license": "Apache-2.0", + "peerDependencies": { + "@discordjs/opus": ">=0.8.0 <1.0.0", + "ffmpeg-static": "^5.0.2 || ^4.2.7 || ^3.0.0 || ^2.4.0", + "node-opus": "^0.3.3", + "opusscript": "^0.0.8" + }, + "peerDependenciesMeta": { + "@discordjs/opus": { + "optional": true + }, + "ffmpeg-static": { + "optional": true + }, + "node-opus": { + "optional": true + }, + "opusscript": { + "optional": true + } + } + }, + "node_modules/prisma": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.2.0.tgz", + "integrity": "sha512-FfFlpjVCkZwrqxDnP4smlNYSH1so+CbfjgdpioFzGGqlQAEm6VHAYSzV7jJgC3ebtY9dNOhDMS2+4/1DDSM7bQ==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/engines": "5.2.0" + }, + "bin": { + "prisma": "build/index.js" + }, + "engines": { + "node": ">=16.13" + } + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "license": "MIT" + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", + "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "license": "MIT" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "license": "MIT" + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readable-web-to-node-stream": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", + "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", + "license": "MIT", + "dependencies": { + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/redis": { + "version": "4.6.7", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.6.7.tgz", + "integrity": "sha512-KrkuNJNpCwRm5vFJh0tteMxW8SaUzkm5fBH7eL5hd/D0fAkzvapxbfGPP/r+4JAXdQuX7nebsBkBqA2RHB7Usw==", + "license": "MIT", + "workspaces": [ + "./packages/*" + ], + "dependencies": { + "@redis/bloom": "1.2.0", + "@redis/client": "1.5.8", + "@redis/graph": "1.1.0", + "@redis/json": "1.0.4", + "@redis/search": "1.1.3", + "@redis/time-series": "1.0.4" + } + }, + "node_modules/reflect-metadata": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", + "license": "Apache-2.0" + }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "license": "MIT" + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", + "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true, + "license": "ISC" + }, + "node_modules/require-relative": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz", + "integrity": "sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4=", + "dev": true, + "license": "MIT" + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.11.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve.exports": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.1.tgz", + "integrity": "sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-identifier": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/safe-identifier/-/safe-identifier-0.4.2.tgz", + "integrity": "sha512-6pNbSMW6OhAi9j+N8V+U715yBQsaWJ7eyEUaOrawX+isg5ZxhUlV1NipNtgaKHmFGiABwt+ZF04Ii+3Xjkg+8w==", + "dev": true, + "license": "ISC" + }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", + "license": "ISC" + }, + "node_modules/saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/server-destroy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz", + "integrity": "sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ==", + "license": "ISC" + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true, + "license": "ISC" + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "license": "(MIT AND BSD-3-Clause)", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, + "node_modules/simple-update-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", + "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "~7.0.0" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "license": "MIT" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "license": "BSD-3-Clause" + }, + "node_modules/ssf": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz", + "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==", + "license": "Apache-2.0", + "dependencies": { + "frac": "~1.1.2" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", + "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strtok3": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-7.0.0.tgz", + "integrity": "sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==", + "license": "MIT", + "dependencies": { + "@tokenizer/token": "^0.3.0", + "peek-readable": "^5.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "license": "MIT" + }, + "node_modules/terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "license": "MIT", + "dependencies": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true, + "license": "MIT" + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/throat": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.2.tgz", + "integrity": "sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==", + "license": "MIT" + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "license": "BSD-3-Clause" + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/token-types": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.1.tgz", + "integrity": "sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==", + "license": "MIT", + "dependencies": { + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "license": "ISC", + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tough-cookie": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "license": "MIT", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ts-jest": { + "version": "27.1.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.5.tgz", + "integrity": "sha512-Xv6jBQPoBEvBq/5i2TeSG9tt/nqkbpcurrEG1b+2yfBrcJelOZF9Ml6dmyMh7bcW9JyFbRYpR5rxROSlBLTZHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^27.0.0", + "json5": "2.x", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "7.x", + "yargs-parser": "20.x" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@types/jest": "^27.0.0", + "babel-jest": ">=27.0.0 <28", + "jest": "^27.0.0", + "typescript": ">=3.8 <5.0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@types/jest": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/ts-mixer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.3.tgz", + "integrity": "sha512-k43M7uCG1AkTyxgnmI5MPwKoUvS/bRvLvUb7+Pgpdlmok8AoqmUaZxUUw8zKM5B1lqZrt41GjYgnvAi0fppqgQ==", + "license": "MIT" + }, + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tsconfig-paths": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", + "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tslib": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz", + "integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==", + "license": "0BSD" + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true, + "license": "0BSD" + }, + "node_modules/tsyringe": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/tsyringe/-/tsyringe-4.8.0.tgz", + "integrity": "sha512-YB1FG+axdxADa3ncEtRnQCFq/M0lALGLxSZeVNbTU8NqhOVc51nnv2CISTcvc1kyv6EGPtXVr0v6lWeDxiijOA==", + "license": "MIT", + "dependencies": { + "tslib": "^1.9.3" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/tsyringe/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "license": "MIT" + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "license": "MIT", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typeorm": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.17.tgz", + "integrity": "sha512-UDjUEwIQalO9tWw9O2A4GU+sT3oyoUXheHJy4ft+RFdnRdQctdQ34L9SqE2p7LdwzafHx1maxT+bqXON+Qnmig==", + "license": "MIT", + "dependencies": { + "@sqltools/formatter": "^1.2.5", + "app-root-path": "^3.1.0", + "buffer": "^6.0.3", + "chalk": "^4.1.2", + "cli-highlight": "^2.1.11", + "date-fns": "^2.29.3", + "debug": "^4.3.4", + "dotenv": "^16.0.3", + "glob": "^8.1.0", + "mkdirp": "^2.1.3", + "reflect-metadata": "^0.1.13", + "sha.js": "^2.4.11", + "tslib": "^2.5.0", + "uuid": "^9.0.0", + "yargs": "^17.6.2" + }, + "bin": { + "typeorm": "cli.js", + "typeorm-ts-node-commonjs": "cli-ts-node-commonjs.js", + "typeorm-ts-node-esm": "cli-ts-node-esm.js" + }, + "engines": { + "node": ">= 12.9.0" + }, + "funding": { + "url": "https://opencollective.com/typeorm" + }, + "peerDependencies": { + "@google-cloud/spanner": "^5.18.0", + "@sap/hana-client": "^2.12.25", + "better-sqlite3": "^7.1.2 || ^8.0.0", + "hdb-pool": "^0.1.6", + "ioredis": "^5.0.4", + "mongodb": "^5.2.0", + "mssql": "^9.1.1", + "mysql2": "^2.2.5 || ^3.0.1", + "oracledb": "^5.1.0", + "pg": "^8.5.1", + "pg-native": "^3.0.0", + "pg-query-stream": "^4.0.0", + "redis": "^3.1.1 || ^4.0.0", + "sql.js": "^1.4.0", + "sqlite3": "^5.0.3", + "ts-node": "^10.7.0", + "typeorm-aurora-data-api-driver": "^2.0.0" + }, + "peerDependenciesMeta": { + "@google-cloud/spanner": { + "optional": true + }, + "@sap/hana-client": { + "optional": true + }, + "better-sqlite3": { + "optional": true + }, + "hdb-pool": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "mongodb": { + "optional": true + }, + "mssql": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "oracledb": { + "optional": true + }, + "pg": { + "optional": true + }, + "pg-native": { + "optional": true + }, + "pg-query-stream": { + "optional": true + }, + "redis": { + "optional": true + }, + "sql.js": { + "optional": true + }, + "sqlite3": { + "optional": true + }, + "ts-node": { + "optional": true + }, + "typeorm-aurora-data-api-driver": { + "optional": true + } + } + }, + "node_modules/typeorm/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/typeorm/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/typeorm/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/typeorm/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/typeorm/node_modules/reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", + "license": "Apache-2.0" + }, + "node_modules/typeorm/node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/typeorm/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici": { + "version": "5.22.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.1.tgz", + "integrity": "sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==", + "license": "MIT", + "dependencies": { + "busboy": "^1.6.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", + "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "license": "MIT", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/url-template": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", + "integrity": "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw==", + "license": "BSD" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/v8-to-istanbul": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", + "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", + "license": "ISC", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/v8-to-istanbul/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 8" + } + }, + "node_modules/vue-eslint-parser": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-8.3.0.tgz", + "integrity": "sha512-dzHGG3+sYwSf6zFBa0Gi9ZDshD7+ad14DGOdTLjruRVgZXe2J+DcZ9iUhyR48z5g1PqRa20yt3Njna/veLJL/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.2", + "eslint-scope": "^7.0.0", + "eslint-visitor-keys": "^3.1.0", + "espree": "^9.0.0", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "license": "MIT", + "dependencies": { + "browser-process-hrtime": "^1.0.0" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "license": "MIT", + "dependencies": { + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=10.4" + } + }, + "node_modules/whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "license": "MIT", + "dependencies": { + "iconv-lite": "0.4.24" + } + }, + "node_modules/whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "license": "MIT" + }, + "node_modules/whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "license": "MIT", + "dependencies": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/which-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.10.tgz", + "integrity": "sha512-uxoA5vLUfRPdjCuJ1h5LlYdmTLbYfums398v3WLkM+i/Wltl2/XyZpQWKbN++ck5L64SR/grOHqtXCUKmlZPNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wmf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", + "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/word": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz", + "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/ws": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xlsx": { + "version": "0.18.5", + "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz", + "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==", + "license": "Apache-2.0", + "dependencies": { + "adler-32": "~1.3.0", + "cfb": "~1.2.1", + "codepage": "~1.15.0", + "crc-32": "~1.2.1", + "ssf": "~0.11.2", + "wmf": "~1.0.1", + "word": "~0.3.0" + }, + "bin": { + "xlsx": "bin/xlsx.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "license": "Apache-2.0" + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "license": "MIT" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ytdl-core": { + "version": "4.11.5", + "resolved": "https://registry.npmjs.org/ytdl-core/-/ytdl-core-4.11.5.tgz", + "integrity": "sha512-27LwsW4n4nyNviRCO1hmr8Wr5J1wLLMawHCQvH8Fk0hiRqrxuIu028WzbJetiYH28K8XDbeinYW4/wcHQD1EXA==", + "license": "MIT", + "dependencies": { + "m3u8stream": "^0.8.6", + "miniget": "^4.2.2", + "sax": "^1.1.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/zod": { + "version": "3.21.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", + "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/package.json b/package.json index 7cff7e8..89ab8ac 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,9 @@ "clean": "docker-compose down && rimraf postgres-db", "start": "node_modules/.bin/tsc && nodemon", "format": "prettier-eslint --write \"src/**/*.ts\"", + "lint": "eslint \"src/**/*.ts\"", + "lint:fix": "eslint \"src/**/*.ts\" --fix", + "cleanup": "npm run lint:fix && npm run format", "build": "node_modules/.bin/tsc --skipLibCheck", "predev": "docker-compose up -d --wait", "dev": "nodemon", @@ -70,5 +73,6 @@ "ts-jest": "^27.1.4", "ts-node": "^10.7.0", "typescript": "^4.6.3" - } -} \ No newline at end of file + }, + "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" +} diff --git a/src/db/data-source.ts b/src/db/data-source.ts index e913d39..a0a8379 100644 --- a/src/db/data-source.ts +++ b/src/db/data-source.ts @@ -19,11 +19,9 @@ dataSource .initialize() .then((c) => { // https://github.com/typeorm/typeorm/issues/3286#issuecomment-486991573 + // eslint-disable-next-line @typescript-eslint/no-explicit-any const driver = c.driver as any; driver.postgres.defaults.parseInputDatesAsUTC = true; - driver.postgres.types.setTypeParser( - 1114, - (str: string) => new Date(str + "Z") - ); + driver.postgres.types.setTypeParser(1114, (str: string) => new Date(str + "Z")); }) .catch(console.error); diff --git a/src/db/invite-simple.ts b/src/db/invite-simple.ts index 19a360f..89b1893 100644 --- a/src/db/invite-simple.ts +++ b/src/db/invite-simple.ts @@ -1,9 +1,4 @@ -import { - Column, - CreateDateColumn, - Entity, - PrimaryGeneratedColumn, -} from "typeorm"; +import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn } from "typeorm"; import { Members } from "../features/invite-list/update-invite-action"; @Entity({}) @@ -30,7 +25,9 @@ export class InviteSimple { public getDiscordDisplayName(members: Members) { const member = members?.get(this.discordId); - return member ? `**${member.displayName}** (<@${member.id}>)` : `**Left the server** (<@${this.discordId}>)`; + return member + ? `**${member.displayName}** (<@${member.id}>)` + : `**Left the server** (<@${this.discordId}>)`; } public getRichLabel(members: Members) { diff --git a/src/features/applications/constants.ts b/src/features/applications/constants.ts new file mode 100644 index 0000000..fd1f1e1 --- /dev/null +++ b/src/features/applications/constants.ts @@ -0,0 +1,33 @@ +/** + * Volunteer Application Constants + * Shared between production code and tests for consistency + */ + +export const VOLUNTEER_APPLICATION = { + CUSTOM_ID: "volunteer-application", + LABEL: "Volunteer Application", + FORM_URL: + "https://docs.google.com/forms/d/e/1FAIpQLSelYSgoouJCOIV9qoOQ1FdOXj8oGC2pfv7P47iUUd1hjOic-g/viewform", +} as const; + +export const APPLICATION_CONTENT = { + WARNING: "DO NOT REPLY TO THIS MESSAGE.", + APPLY_QUESTION: "How do I apply?", + PROCESS_QUESTION: "What happens to an application?", + REVIEW_TIMELINE: "less than a week", + NO_PRIVILEGES_MESSAGE: "leadership and volunteering are duties with no special privileges", +} as const; + +/** + * Complete application content template + * Used by RequestApplication.content getter + */ +export const APPLICATION_MESSAGE_TEMPLATE = `**${APPLICATION_CONTENT.WARNING}** + +In Castle, ${APPLICATION_CONTENT.NO_PRIVILEGES_MESSAGE}. Volunteers may step down at any time. + +**${APPLICATION_CONTENT.APPLY_QUESTION}** +Fill out the following Google form: ${VOLUNTEER_APPLICATION.FORM_URL}. + +**${APPLICATION_CONTENT.PROCESS_QUESTION}** +Applications are reviewed by current officers. This process typically takes ${APPLICATION_CONTENT.REVIEW_TIMELINE}.` as const; diff --git a/src/features/applications/debug-mock.test.ts b/src/features/applications/debug-mock.test.ts new file mode 100644 index 0000000..09a64a8 --- /dev/null +++ b/src/features/applications/debug-mock.test.ts @@ -0,0 +1,61 @@ +import { createBotTestEnvironment } from "../../test/app-test-config"; +import { updateApplicationInfo } from "./update-applications"; +import { globalDiscordMocks } from "../../test/setup/setup-discord-actions"; +import { discordComponentRegistry } from "../../test/discord-testing-library/discord-component-registry"; +import { Client } from "discord.js"; + +describe("debug mock registration", () => { + it("should trace mock calls and button registration", async () => { + console.log("=== Starting debug test ==="); + + const discord = createBotTestEnvironment(); + console.log("1. Environment created"); + + console.log( + "2. Initial mock call count:", + globalDiscordMocks.createOrUpdateInstructions.mock.calls.length + ); + console.log("3. Initial buttons in registry:", discordComponentRegistry.getButtons().length); + console.log( + "4. Mock implementation:", + globalDiscordMocks.createOrUpdateInstructions + .getMockImplementation() + ?.toString() + .slice(0, 100) + ); + + console.log("4. About to call updateApplicationInfo..."); + await discord.withClient((client: Client) => updateApplicationInfo(client)); + console.log("5. updateApplicationInfo completed"); + + console.log( + "6. Final mock call count:", + globalDiscordMocks.createOrUpdateInstructions.mock.calls.length + ); + console.log("7. Final buttons in registry:", discordComponentRegistry.getButtons().length); + + if (globalDiscordMocks.createOrUpdateInstructions.mock.calls.length > 0) { + const firstCall = globalDiscordMocks.createOrUpdateInstructions.mock.calls[0]; + const instructions = firstCall[0]; + console.log("8. Button item structure:"); + if (instructions?.components?.[0]?.components?.[0]) { + const buttonItem = instructions.components[0].components[0]; + console.log(" - Type of item:", typeof buttonItem); + console.log(" - Constructor:", buttonItem.constructor?.name); + console.log(" - Has .data property:", "data" in buttonItem); + console.log(" - Direct custom_id:", buttonItem.custom_id); + console.log(" - Data custom_id:", buttonItem.data?.custom_id); + } + } + + const allButtons = discordComponentRegistry.getButtons(); + console.log( + "9. All buttons:", + allButtons.map((b) => ({ + label: b.data.label, + customId: (b.data as any).custom_id, + style: b.data.style, + })) + ); + }); +}); diff --git a/src/features/applications/index.ts b/src/features/applications/index.ts new file mode 100644 index 0000000..94390c3 --- /dev/null +++ b/src/features/applications/index.ts @@ -0,0 +1,6 @@ +export { RequestApplication } from "./request-application-button-commands"; +export { updateApplicationInfo, UpdateApplicationInfoAction } from "./update-applications"; + +import { RequestApplication } from "./request-application-button-commands"; + +export const applicationCommandButton = new RequestApplication(); diff --git a/src/features/applications/request-application-button-commands.test.ts b/src/features/applications/request-application-button-commands.test.ts new file mode 100644 index 0000000..7307ce0 --- /dev/null +++ b/src/features/applications/request-application-button-commands.test.ts @@ -0,0 +1,48 @@ +import { createBotTestEnvironment } from "../../test/app-test-config"; +import { VOLUNTEER_APPLICATION, APPLICATION_MESSAGE_TEMPLATE } from "./constants"; +import { updateApplicationInfo } from "./update-applications"; + +describe("volunteer application workflow", () => { + it("handles complete application workflow from setup to user interaction", async () => { + const discord = createBotTestEnvironment(); + const applicant = discord.guild.createUser("eager_applicant"); + + await discord.withClient((client) => updateApplicationInfo(client)); + + const volunteerButton = discord.getButton(VOLUNTEER_APPLICATION.LABEL); + expect(discord).toHaveCreatedEmbed("Volunteer Applications"); + + await volunteerButton.click(applicant); + + expect(applicant).toHaveSentDm(APPLICATION_MESSAGE_TEMPLATE); + expect(discord.channel("request-dump")).toHaveSentMessage( + /Volunteer Application sent to \*\*eager_applicant\*\*/ + ); + }); + + it("handles error gracefully when request channel is missing", async () => { + const discord = createBotTestEnvironment({ + channels: { general: "text" }, + }); + const applicant = discord.guild.createUser("test_user"); + + await discord.withClient((client) => updateApplicationInfo(client)); + const volunteerButton = discord.getButton(VOLUNTEER_APPLICATION.LABEL); + await volunteerButton.click(applicant); + + expect(applicant).toHaveEditedReplyWith("Error: Could not locate the request dump channel"); + }); + + it("handles error gracefully when channel type is invalid", async () => { + const discord = createBotTestEnvironment({ + channels: { general: "text", "request-dump": "text" }, + }); + const applicant = discord.guild.createUser("test_user"); + + await discord.withClient((client) => updateApplicationInfo(client)); + const volunteerButton = discord.getButton(VOLUNTEER_APPLICATION.LABEL); + await volunteerButton.click(applicant); + + expect(applicant).toHaveEditedReplyWith("Error: 111222333 is not a text channel."); + }); +}); diff --git a/src/features/applications/request-application-button-commands.ts b/src/features/applications/request-application-button-commands.ts index 300abaf..c0cdf87 100644 --- a/src/features/applications/request-application-button-commands.ts +++ b/src/features/applications/request-application-button-commands.ts @@ -1,20 +1,15 @@ -import { - ButtonInteraction, - CacheType, - ButtonBuilder, - ButtonStyle, - ChannelType, -} from "discord.js"; +import { ButtonInteraction, CacheType, ButtonBuilder, ButtonStyle, ChannelType } from "discord.js"; import { requestDumpThreadId } from "../../config"; import { ButtonCommand } from "../../shared/command/button-command"; +import { VOLUNTEER_APPLICATION, APPLICATION_MESSAGE_TEMPLATE } from "./constants"; export class RequestApplication extends ButtonCommand { public constructor() { - super("volunteer-application"); + super(VOLUNTEER_APPLICATION.CUSTOM_ID); } public get label() { - return "Volunteer Application"; + return VOLUNTEER_APPLICATION.LABEL; } public async execute(interaction: ButtonInteraction) { @@ -25,9 +20,7 @@ export class RequestApplication extends ButtonCommand { content: `You have been DM'd the **${this.label}**.`, }); - const channel = await interaction.guild?.channels.fetch( - requestDumpThreadId - ); + const channel = await interaction.guild?.channels.fetch(requestDumpThreadId); if (!channel) { throw new Error("Could not locate the request dump channel"); } @@ -41,21 +34,10 @@ export class RequestApplication extends ButtonCommand { } public getButtonBuilder(style: ButtonStyle) { - return new ButtonBuilder() - .setCustomId(this.customId) - .setStyle(style) - .setLabel(this.label); + return new ButtonBuilder().setCustomId(this.customId).setStyle(style).setLabel(this.label); } private get content() { - return `**DO NOT REPLY TO THIS MESSAGE.** - -In Castle, leadership and volunteering are duties with no special privileges. Volunteers may step down at any time. - -**How do I apply?** -Fill out the following Google form: https://docs.google.com/forms/d/e/1FAIpQLSelYSgoouJCOIV9qoOQ1FdOXj8oGC2pfv7P47iUUd1hjOic-g/viewform. - -**What happens to an application?** -Applications are reviewed by current officers. This process typically takes less than a week.`; + return APPLICATION_MESSAGE_TEMPLATE; } } diff --git a/src/features/applications/update-applications.fixture.ts b/src/features/applications/update-applications.fixture.ts new file mode 100644 index 0000000..baba9e4 --- /dev/null +++ b/src/features/applications/update-applications.fixture.ts @@ -0,0 +1,22 @@ +export const volunteerApplicationsEmbed = { + title: "Volunteer Applications", + description: `Castle is a casual-friendly guild and that applies to volunteer and leadership roles as well. We have many volunteer roles that help keep the guild running smoothly. + +❓ **What do volunteers do?** +• Read about each [volunteer role](https://docs.google.com/document/d/19fqGGGAW3tXTPb8syiCZQZED9qTGhY65dnaWL8YzZnE). + +❓ **What's expected of volunteers?** +• Represent us well, both internally and externally. +• Commit as much time as you like, when you'd like. +• You may take a break or step down at any time, but you will be required to re-apply if you become interested again. + +❓ **Am I a good candidate to volunteer? What if I'm an ally?** +• Yes! Everyone is encouraged to volunteer. +• All roles are open to alliance members except :red_square: **Officer** and :red_square: **Guard**, which are Castle-members only. + +📜 **How do I apply?** +• Press the button below to receive a link to the volunteer application in a DM. +• Retrieving the application is not a commitment to apply! + +✨ _"Many hands make light work!"_ ✨`, +}; diff --git a/src/features/applications/update-applications.test.ts b/src/features/applications/update-applications.test.ts new file mode 100644 index 0000000..b542ca3 --- /dev/null +++ b/src/features/applications/update-applications.test.ts @@ -0,0 +1,40 @@ +import { createBotTestEnvironment } from "../../test/app-test-config"; +import { UpdateApplicationInfoAction, updateApplicationInfo } from "./update-applications"; +import { globalDiscordMocks } from "../../test/setup/setup-discord-actions"; +import { VOLUNTEER_APPLICATION } from "./constants"; +import { Client } from "discord.js"; + +describe("application info setup workflow", () => { + it("executes setup action through ready executor", async () => { + const discord = createBotTestEnvironment(); + + await discord.withClient((client: Client) => updateApplicationInfo(client)); + + expect(globalDiscordMocks.readyActionExecutor).toHaveBeenCalledWith( + expect.any(UpdateApplicationInfoAction), + undefined + ); + expect(globalDiscordMocks.readyActionExecutor).toHaveBeenCalledTimes(1); + }); + + it("supports repeat duration configuration for periodic updates", async () => { + const discord = createBotTestEnvironment(); + const options = { repeatDuration: 5000 }; + + await discord.withClient((client: Client) => updateApplicationInfo(client, options)); + + expect(globalDiscordMocks.readyActionExecutor).toHaveBeenCalledWith( + expect.any(UpdateApplicationInfoAction), + options + ); + }); + + it("creates complete application setup with button and embed", async () => { + const discord = createBotTestEnvironment(); + + await discord.withClient((client: Client) => updateApplicationInfo(client)); + + discord.getButton(VOLUNTEER_APPLICATION.LABEL); // Verify button exists + expect(discord).toHaveCreatedEmbed("Volunteer Applications"); + }); +}); diff --git a/src/features/applications/update-applications.ts b/src/features/applications/update-applications.ts index eea9a3b..0d236c5 100644 --- a/src/features/applications/update-applications.ts +++ b/src/features/applications/update-applications.ts @@ -8,20 +8,15 @@ import { import { applicationsChannelId } from "../../config"; import { Name } from "../../db/instructions"; import { InstructionsReadyAction } from "../../shared/action/instructions-ready-action"; -import { - readyActionExecutor, - ReadyActionExecutorOptions, -} from "../../shared/action/ready-action"; +import { readyActionExecutor, ReadyActionExecutorOptions } from "../../shared/action/ready-action"; import { RequestApplication } from "./request-application-button-commands"; -export const applicationCommandButton = new RequestApplication(); +const applicationCommandButton = new RequestApplication(); -export const updateApplicationInfo = ( - client: Client, - options?: ReadyActionExecutorOptions -) => readyActionExecutor(new UpdateApplicationInfoAction(client), options); +export const updateApplicationInfo = (client: Client, options?: ReadyActionExecutorOptions) => + readyActionExecutor(new UpdateApplicationInfoAction(client), options); -class UpdateApplicationInfoAction extends InstructionsReadyAction { +export class UpdateApplicationInfoAction extends InstructionsReadyAction { public async execute(): Promise { await this.createOrUpdateInstructions( { @@ -31,9 +26,7 @@ class UpdateApplicationInfoAction extends InstructionsReadyAction { components: [ new ActionRowBuilder({ type: 1, - components: [ - applicationCommandButton.getButtonBuilder(ButtonStyle.Primary), - ], + components: [applicationCommandButton.getButtonBuilder(ButtonStyle.Primary)], }), ], }, diff --git a/src/features/auctions/auction-finished-reaction.ts b/src/features/auctions/auction-finished-reaction.ts index c379779..615aeb1 100644 --- a/src/features/auctions/auction-finished-reaction.ts +++ b/src/features/auctions/auction-finished-reaction.ts @@ -12,10 +12,7 @@ import { dkpDeputyRoleId, officerRoleId, } from "../../config"; -import { - ReactionAction, - reactionActionExecutor, -} from "../../shared/action/reaction-action"; +import { ReactionAction, reactionActionExecutor } from "../../shared/action/reaction-action"; import { castledkp } from "../../services/castledkp"; import { some } from "lodash"; @@ -64,9 +61,7 @@ class AuctionFinishedReactionAction extends ReactionAction { // handle banked if (this.reaction.emoji.name === "🏦") { - if ( - this.message.embeds.find((e) => e.title?.includes("view on P99 Wiki")) - ) { + if (this.message.embeds.find((e) => e.title?.includes("view on P99 Wiki"))) { // provide receipt await this.message.reply({ content: "Auction closed. Item is property of the guild bank.", @@ -80,14 +75,10 @@ class AuctionFinishedReactionAction extends ReactionAction { // parse message if (!this.message.content) { - throw new Error( - "Tried to finish an auction, but the message has no content." - ); + throw new Error("Tried to finish an auction, but the message has no content."); } if (!this.message.author) { - throw new Error( - "Tried to finish an auction, but the message has no author." - ); + throw new Error("Tried to finish an auction, but the message has no author."); } const { price, character } = await this.parseBid(this.message.content); const item = await this.getItem(name); @@ -136,9 +127,7 @@ ${this.example}`); const name = reg[reg.length - 1]; const character = await this.getCharacter(name); if (!character) { - throw new Error( - `Cannot finish auction because character ${name} does not exist` - ); + throw new Error(`Cannot finish auction because character ${name} does not exist`); } return { price, character }; diff --git a/src/features/auctions/auction-subcommand.ts b/src/features/auctions/auction-subcommand.ts index 4082ae2..8ef8781 100644 --- a/src/features/auctions/auction-subcommand.ts +++ b/src/features/auctions/auction-subcommand.ts @@ -1,9 +1,4 @@ -import { - CacheType, - ChannelType, - CommandInteraction, - GuildMemberRoleManager, -} from "discord.js"; +import { CacheType, ChannelType, CommandInteraction, GuildMemberRoleManager } from "discord.js"; import { auctionChannelId, bankerRoleId, raiderRoleId } from "../../config"; import { Subcommand } from "../../shared/command/subcommand"; import { addRoleToThread } from "../../shared/command/util"; @@ -59,9 +54,7 @@ export class AuctionSubcommand extends Subcommand { .addStringOption((o) => o .setName(Option.Raid) - .setDescription( - "The raid to restrict bidders to. Defaults to no restriction" - ) + .setDescription("The raid to restrict bidders to. Defaults to no restriction") ) .addStringOption((o) => o @@ -74,9 +67,7 @@ export class AuctionSubcommand extends Subcommand { command.addBooleanOption((o) => o .setName(Option.RequireScribe) - .setDescription( - "Add a rule that the bidders must be able to scribe the spell." - ) + .setDescription("Add a rule that the bidders must be able to scribe the spell.") ); } return command; diff --git a/src/features/auctions/auction-thread-builder.ts b/src/features/auctions/auction-thread-builder.ts index 9a94a59..27920c6 100644 --- a/src/features/auctions/auction-thread-builder.ts +++ b/src/features/auctions/auction-thread-builder.ts @@ -85,9 +85,7 @@ export class AuctionThreadBuilder extends ThreadBuilder { } private get requireScribeRule() { - return this.requireScribe - ? `\n- Bid only if you can scribe the spell.` - : ""; + return this.requireScribe ? `\n- Bid only if you can scribe the spell.` : ""; } private get endDate() { diff --git a/src/features/bank-hours/add-subcommand.ts b/src/features/bank-hours/add-subcommand.ts index 3589990..b5ff6c8 100644 --- a/src/features/bank-hours/add-subcommand.ts +++ b/src/features/bank-hours/add-subcommand.ts @@ -5,10 +5,7 @@ import { updateBankRequestInfo } from "../bank-request-info/update-action"; import { Day, Days } from "../bank-request-info/types"; import { BankHour } from "../../db/bank-hour"; import { Subcommand } from "../../shared/command/subcommand"; -import { - requireInteractionMemberRole, - requireUserRole, -} from "../../shared/command/util"; +import { requireInteractionMemberRole, requireUserRole } from "../../shared/command/util"; enum Option { Banker = "banker", @@ -35,9 +32,7 @@ class Add extends Subcommand { const bankHour = new BankHour(); bankHour.userId = banker.id; - bankHour.day = String( - this.getOption(Option.Day, interaction)?.value - ) as Day; + bankHour.day = String(this.getOption(Option.Day, interaction)?.value) as Day; const pm = Boolean(this.getOption(Option.PM, interaction)?.value); bankHour.hour = Number(this.getOption(Option.Hour, interaction)?.value) + @@ -87,7 +82,4 @@ class Add extends Subcommand { } } -export const addSubcommand = new Add( - "add", - "Creates a banker hour. Specify time in EST." -); +export const addSubcommand = new Add("add", "Creates a banker hour. Specify time in EST."); diff --git a/src/features/bank-hours/command.ts b/src/features/bank-hours/command.ts index b3290a8..e30bde1 100644 --- a/src/features/bank-hours/command.ts +++ b/src/features/bank-hours/command.ts @@ -2,8 +2,7 @@ import { Command } from "../../shared/command/command"; import { addSubcommand } from "./add-subcommand"; import { removeSubcommand } from "./remove-subcommand"; -export const bankHourCommand = new Command( - "bankhour", - "Set or remove bank hours.", - [addSubcommand, removeSubcommand] -); +export const bankHourCommand = new Command("bankhour", "Set or remove bank hours.", [ + addSubcommand, + removeSubcommand, +]); diff --git a/src/features/bank-hours/remove-subcommand.ts b/src/features/bank-hours/remove-subcommand.ts index 3e029e5..02b2034 100644 --- a/src/features/bank-hours/remove-subcommand.ts +++ b/src/features/bank-hours/remove-subcommand.ts @@ -1,8 +1,4 @@ -import { - AutocompleteInteraction, - CacheType, - CommandInteraction, -} from "discord.js"; +import { AutocompleteInteraction, CacheType, CommandInteraction } from "discord.js"; import { bankerRoleId } from "../../config"; import { dataSource } from "../../db/data-source"; import { updateBankRequestInfo } from "../bank-request-info/update-action"; @@ -18,13 +14,9 @@ class Remove extends Subcommand { public async execute(interaction: CommandInteraction) { await this.authorize(interaction); - const bankHourId = Number( - this.getOption(Option.BankHourID, interaction)?.value - ); + const bankHourId = Number(this.getOption(Option.BankHourID, interaction)?.value); - const bankHour = await dataSource - .getRepository(BankHour) - .findOneByOrFail({ id: bankHourId }); + const bankHour = await dataSource.getRepository(BankHour).findOneByOrFail({ id: bankHourId }); await dataSource.manager.remove(bankHour); @@ -37,9 +29,7 @@ class Remove extends Subcommand { return super.command.addIntegerOption((o) => o .setName(Option.BankHourID) - .setDescription( - "The bank hour ID. Set a banker to get a list of hours." - ) + .setDescription("The bank hour ID. Set a banker to get a list of hours.") .setAutocomplete(true) .setRequired(true) ); @@ -57,14 +47,10 @@ class Remove extends Subcommand { } } - private async autocompleteBankHourIdOption( - interaction: AutocompleteInteraction - ) { + private async autocompleteBankHourIdOption(interaction: AutocompleteInteraction) { const weeklyBankAvailabilities = dataSource.getRepository(BankHour); const bankHour = await weeklyBankAvailabilities.findBy({}); - await Promise.all( - bankHour.map(async (h) => interaction.guild?.members.fetch(h.userId)) - ); + await Promise.all(bankHour.map(async (h) => interaction.guild?.members.fetch(h.userId))); return bankHour?.map((h) => ({ name: `${ interaction.guild?.members.cache.get(h.userId)?.displayName diff --git a/src/features/bank-inventory/actions/bank-request-complete-reaction.ts b/src/features/bank-inventory/actions/bank-request-complete-reaction.ts index 18198d5..6695750 100644 --- a/src/features/bank-inventory/actions/bank-request-complete-reaction.ts +++ b/src/features/bank-inventory/actions/bank-request-complete-reaction.ts @@ -1,10 +1,4 @@ -import { - CommandInteraction, - MessageReaction, - PartialMessageReaction, - PartialUser, - User, -} from "discord.js"; +import { MessageReaction, PartialMessageReaction, PartialUser, User } from "discord.js"; import { bankRequestsChannelId, bankerRoleId, @@ -12,17 +6,13 @@ import { bankTransactionsChannelId, modRoleId, } from "../../../config"; -import { - ReactionAction, - reactionActionExecutor, -} from "../../../shared/action/reaction-action"; +import { ReactionAction, reactionActionExecutor } from "../../../shared/action/reaction-action"; import { getTextChannel } from "../../.."; export const tryBankRequestComplete = ( reaction: MessageReaction | PartialMessageReaction, user: User | PartialUser -) => - reactionActionExecutor(new BankRequestFinishedReactionAction(reaction, user)); +) => reactionActionExecutor(new BankRequestFinishedReactionAction(reaction, user)); class BankRequestFinishedReactionAction extends ReactionAction { public async execute() { @@ -32,15 +22,13 @@ class BankRequestFinishedReactionAction extends ReactionAction { } // mark finished if (this.reaction.emoji.name === "✅") { - const bankTransactionsChannel = await getTextChannel( - bankTransactionsChannelId - ); + const bankTransactionsChannel = await getTextChannel(bankTransactionsChannelId); let transactionContent = this.message.content + ` -- ✅ by ${this.user}`; if (!this.message.author?.bot) { transactionContent = this.message.author?.toString() + ": " + transactionContent; } bankTransactionsChannel?.send(transactionContent); - // authorize user + // authorize user const reactor = await this.members?.fetch(this.user.id); if ( !( @@ -62,12 +50,12 @@ class BankRequestFinishedReactionAction extends ReactionAction { reactor?.roles.cache.has(bankerRoleId) || reactor?.roles.cache.has(officerRoleId) || reactor?.roles.cache.has(modRoleId) - ) || this.message.mentions?.parsedUsers.hasAny(this.user.username ?? "") + ) || + this.message.mentions?.parsedUsers.hasAny(this.user.username ?? "") ) { return; } this.message.delete(); } - } } diff --git a/src/features/bank-inventory/actions/inventory-file-action.ts b/src/features/bank-inventory/actions/inventory-file-action.ts index 01d33f6..c9d2667 100644 --- a/src/features/bank-inventory/actions/inventory-file-action.ts +++ b/src/features/bank-inventory/actions/inventory-file-action.ts @@ -3,16 +3,12 @@ import { Attachment, Message } from "discord.js"; import { Inventory, bankData } from "../bank-data"; // import { bankerRoleId } from "../../config"; TODO: verify role? -import { - MessageAction, - messageActionExecutor, -} from "../../../shared/action/message-action"; +import { MessageAction, messageActionExecutor } from "../../../shared/action/message-action"; import { bankInventoryChannelId } from "../../../config"; import { parseInventoryFile, uploadToGDrive } from "../inventory-files"; const supportedFormat = "text/plain; charset=utf-8"; - export const tryParseInventoryAction = (message: Message) => messageActionExecutor(new UploadInventoryMessageAction(message)); @@ -45,5 +41,4 @@ class UploadInventoryMessageAction extends MessageAction { await bankData.setInventory(inventory); message.react("✅"); } - -} \ No newline at end of file +} diff --git a/src/features/bank-inventory/bank-data.ts b/src/features/bank-inventory/bank-data.ts index 8fa4bf6..a7948b6 100644 --- a/src/features/bank-inventory/bank-data.ts +++ b/src/features/bank-inventory/bank-data.ts @@ -1,7 +1,7 @@ -// use Prisma to interface with postgres db. +// use Prisma to interface with postgres db. // see prisma/schema.prisma -import { PrismaClient } from '@prisma/client' +import { PrismaClient } from "@prisma/client"; export interface InventoryItem { character: string; @@ -18,24 +18,24 @@ export interface Inventory { } class BankData { - private static instance: BankData + private static instance: BankData; private prisma; private constructor() { - this.prisma = new PrismaClient() + this.prisma = new PrismaClient(); } public static getInstance(): BankData { - if (!BankData.instance) { - BankData.instance = new BankData(); - } - return BankData.instance; + if (!BankData.instance) { + BankData.instance = new BankData(); + } + return BankData.instance; } public async setInventory(inventory: Inventory): Promise { try { - const upsertChar = await this.prisma.char.upsert({ + await this.prisma.char.upsert({ where: { name: inventory.charName, }, @@ -45,171 +45,184 @@ class BankData { }, update: { charType: inventory.charType, - } - }) + }, + }); } catch (e) { - console.error('character not created', e) + console.error("character not created", e); } - - for (let item of inventory.items) { + + for (const item of inventory.items) { try { - const upsertItem = await this.prisma.item.upsert({ + await this.prisma.item.upsert({ where: { - id: item.id + id: item.id, }, create: { id: item.id, - name: item.name + name: item.name, }, update: { - name: item.name - } - }) - } catch(e) { - console.error(e) + name: item.name, + }, + }); + } catch (e) { + console.error(e); } - + try { - const upsertSlot = await this.prisma.slot.upsert({ + await this.prisma.slot.upsert({ where: { - charSlot: String(inventory.charName + item.location) + charSlot: String(inventory.charName + item.location), }, update: { itemId: item.id, - count: item.count + count: item.count, }, create: { slot: item.location, charSlot: String(inventory.charName + item.location), charName: inventory.charName, itemId: item.id, - count: item.count - } - }) - } catch(e) { - console.error(e) + count: item.count, + }, + }); + } catch (e) { + console.error(e); } } } public async getItemsByStem(itemStem: string) { - return await this.prisma.item.findMany({ - where: { - name: { - startsWith: itemStem, - mode: 'insensitive' - } - }, - include: { - _count: { + return await this.prisma.item + .findMany({ + where: { + name: { + startsWith: itemStem, + mode: "insensitive", + }, + }, + include: { + _count: { select: { - stock: true - } - } - } - }).catch((err: Error) => { - console.error(err); - }); + stock: true, + }, + }, + }, + }) + .catch((err: Error) => { + console.error(err); + }); } public async getItemsByName(itemName: string) { - return await this.prisma.item.findMany({ - where: { - name: { - equals: itemName - } - }, - include: { - _count: { + return await this.prisma.item + .findMany({ + where: { + name: { + equals: itemName, + }, + }, + include: { + _count: { select: { - stock: true - } - } - } - }).catch((err: Error) => { - console.error(err); - }); + stock: true, + }, + }, + }, + }) + .catch((err: Error) => { + console.error(err); + }); } public async getItemStockById(itemId: number) { - return await this.prisma.item.findFirst({ - where: { - id: { - equals: itemId - } - }, - include: { - stock: true - } - }).catch((err: Error) => { - console.error(err); - }); + return await this.prisma.item + .findFirst({ + where: { + id: { + equals: itemId, + }, + }, + include: { + stock: true, + }, + }) + .catch((err: Error) => { + console.error(err); + }); } public async getInventory(charName: string) { - return await this.prisma.char.findFirst({ - where: { - name: { - equals: charName - } - }, - include: { - inventory: true - } - }).catch((err: Error) => { - console.error(err); - }); + return await this.prisma.char + .findFirst({ + where: { + name: { + equals: charName, + }, + }, + include: { + inventory: true, + }, + }) + .catch((err: Error) => { + console.error(err); + }); } - public async getUnmatchedChars(names: string[]){ - return await this.prisma.char.findMany({ - where: { - NOT: { - name: { - in: names - } - } - } - }).catch((err: Error) => { - console.error(err); - }); + public async getUnmatchedChars(names: string[]) { + return await this.prisma.char + .findMany({ + where: { + NOT: { + name: { + in: names, + }, + }, + }, + }) + .catch((err: Error) => { + console.error(err); + }); } - public async removeInventory(charName: string, removeChar: boolean = false) { + public async removeInventory(charName: string) { console.log("bank-db-remove:", charName); // remove char slots - const deleteSlots = await this.prisma.slot.deleteMany({ - where: { - charName: { - equals: charName - } - } - }).catch((err: Error) => { - console.error(err); - }); - + await this.prisma.slot + .deleteMany({ + where: { + charName: { + equals: charName, + }, + }, + }) + .catch((err: Error) => { + console.error(err); + }); + // remove char // todo: make this step optional - const deleteCharslots = await this.prisma.char.delete({ - where: { - name: charName - } - }).catch((err: Error) => { - console.error(err); - }); + await this.prisma.char + .delete({ + where: { + name: charName, + }, + }) + .catch((err: Error) => { + console.error(err); + }); } public async setItemData(itemId: number, price: string | null) { - const setItem = await this.prisma.item.update({ + await this.prisma.item.update({ where: { - id: itemId + id: itemId, }, data: { - price: price - } - }) + price: price, + }, + }); } - } -export const bankData = BankData.getInstance(); \ No newline at end of file +export const bankData = BankData.getInstance(); diff --git a/src/features/bank-inventory/commands/bank-db-sync-subcommand.ts b/src/features/bank-inventory/commands/bank-db-sync-subcommand.ts index 2bf21a4..b081775 100644 --- a/src/features/bank-inventory/commands/bank-db-sync-subcommand.ts +++ b/src/features/bank-inventory/commands/bank-db-sync-subcommand.ts @@ -1,28 +1,18 @@ -import { - CacheType, - CommandInteraction, - GuildMemberRoleManager - } from "discord.js"; +import { CacheType, CommandInteraction } from "discord.js"; import { Subcommand } from "../../../shared/command/subcommand"; -import { bankRequestsChannelId, bankerRoleId, officerRoleId, modRoleId } from "../../../config"; +import { bankerRoleId, officerRoleId, modRoleId } from "../../../config"; import { findFiles, getFile } from "../../../services/gdrive"; -import { - parseInventoryFile, - bankInventoriesFolderId -} from "../inventory-files"; +import { parseInventoryFile, bankInventoriesFolderId } from "../inventory-files"; import { bankData } from "../bank-data"; import { authorizeByMemberRoles } from "../../../shared/command/util"; -import { drive_v3, file_v1 } from "googleapis"; +import { drive_v3 } from "googleapis"; -let replyTxt = "" +let replyTxt = ""; class SyncBankDb extends Subcommand { public async execute(interaction: CommandInteraction) { - // authorize - authorizeByMemberRoles([ - bankerRoleId, officerRoleId, modRoleId - ], interaction); + authorizeByMemberRoles([bankerRoleId, officerRoleId, modRoleId], interaction); this.appendReplyTxt("Updating bank database from GDrive...", interaction); @@ -30,38 +20,40 @@ class SyncBankDb extends Subcommand { `'${bankInventoriesFolderId}' in parents and trashed = false` ); - const bankersUpdated = await this.updateBankInventoryFolders(bankInventoryFolders, interaction) - + const bankersUpdated = await this.updateBankInventoryFolders(bankInventoryFolders, interaction); + const unmatchedChars = await bankData.getUnmatchedChars(bankersUpdated); - console.log('remove unmatched:', unmatchedChars) + console.log("remove unmatched:", unmatchedChars); - if(unmatchedChars && unmatchedChars.length > 0) { + if (unmatchedChars && unmatchedChars.length > 0) { await this.appendReplyTxt("Removing unmatched character inventories:", interaction); - for (let char of unmatchedChars) { + for (const char of unmatchedChars) { await this.appendReplyTxt("Removed: " + char.name, interaction); await this.appendReplyTxt("Removed: " + char.name, interaction); bankData.removeInventory(char.name); } } - } public async getOptionAutocomplete() { return []; } - private async updateBankInventoryFolders(bankInventoryFolders: drive_v3.Schema$File[], interaction: CommandInteraction) { + private async updateBankInventoryFolders( + bankInventoryFolders: drive_v3.Schema$File[], + interaction: CommandInteraction + ) { const bankersUpdated = []; - for (let f of bankInventoryFolders) { + for (const f of bankInventoryFolders) { try { - const files = await findFiles( - `'${f.id}' in parents and trashed = false` - ) - if (files.length === 0) continue; - for (let file of files) { + const files = await findFiles(`'${f.id}' in parents and trashed = false`); + if (files.length === 0) { + continue; + } + for (const file of files) { if (file && file.id && file.name) { - const data = await getFile(file.id) + const data = await getFile(file.id); console.log("bank-db-sync:", file.name, file.id); const inventory = await parseInventoryFile(file.name, String(data)); await bankData.setInventory(inventory); @@ -86,7 +78,7 @@ class SyncBankDb extends Subcommand { if (message.length > length) { return message.slice(message.length - length); } else { - return message; + return message; } } } diff --git a/src/features/bank-inventory/commands/bank-get-item-data-subcommand.ts b/src/features/bank-inventory/commands/bank-get-item-data-subcommand.ts index 5b4ddd0..233050d 100644 --- a/src/features/bank-inventory/commands/bank-get-item-data-subcommand.ts +++ b/src/features/bank-inventory/commands/bank-get-item-data-subcommand.ts @@ -1,73 +1,69 @@ -import { - AutocompleteInteraction, - CacheType, - CommandInteraction, - EmbedBuilder - } from "discord.js"; +import { AutocompleteInteraction, CacheType, CommandInteraction, EmbedBuilder } from "discord.js"; import { Subcommand } from "../../../shared/command/subcommand"; -import { bankRequestsChannelId, bankerRoleId, officerRoleId, modRoleId } from "../../../config"; +import { bankerRoleId, officerRoleId, modRoleId } from "../../../config"; import { bankData } from "../bank-data"; import { authorizeByMemberRoles } from "../../../shared/command/util"; import { autoCompleteAllItems } from "../helpers"; enum Option { - Item = "item" + Item = "item", } class GetItemData extends Subcommand { public async execute(interaction: CommandInteraction) { - // authorize - authorizeByMemberRoles([ - bankerRoleId, officerRoleId, modRoleId - ], interaction); + authorizeByMemberRoles([bankerRoleId, officerRoleId, modRoleId], interaction); const item = this.getOption(Option.Item, interaction); const embed = new EmbedBuilder(); if (!item) { - throw new Error(`An item is required.`); + throw new Error(`An item is required.`); } else { const itemData = await bankData.getItemStockById(parseInt(String(item.value))); - if(itemData) { + if (itemData) { const countAvailable = itemData?.stock.reduce((total, s) => total + (s.count || 0), 0); embed.setTitle(itemData.name); embed.setDescription( - "id: " + itemData.id - + "\nname: " + itemData.name - + "\ntype: " + itemData.type - + "\nprice: " + itemData.price - + "\nin stock: " + countAvailable + "id: " + + itemData.id + + "\nname: " + + itemData.name + + "\ntype: " + + itemData.type + + "\nprice: " + + itemData.price + + "\nin stock: " + + countAvailable ); } else { - embed.setDescription("Item not found") + embed.setDescription("Item not found"); } // console.log(itemData); interaction.editReply({ content: "", - embeds: [embed] - }) + embeds: [embed], + }); } - } public get command() { - return super.command - .addStringOption((o) => - o.setName(Option.Item) - .setDescription("Item data to request") - .setRequired(true) - .setAutocomplete(true) - ) + return super.command.addStringOption((o) => + o + .setName(Option.Item) + .setDescription("Item data to request") + .setRequired(true) + .setAutocomplete(true) + ); } public async getOptionAutocomplete(option: string, interaction: AutocompleteInteraction) { - const input = interaction.options.getString('item'); + const input = interaction.options.getString("item"); // console.log("input", input) switch (option) { case Option.Item: - if(input && input.length > 3) { + if (input && input.length > 3) { return await autoCompleteAllItems(input); } else { return []; @@ -76,7 +72,4 @@ class GetItemData extends Subcommand { } } -export const getItem = new GetItemData( - "get-item-data", - "Get Item Data" -); +export const getItem = new GetItemData("get-item-data", "Get Item Data"); diff --git a/src/features/bank-inventory/commands/bank-request-subcommand.ts b/src/features/bank-inventory/commands/bank-request-subcommand.ts index ef4a65d..005f062 100644 --- a/src/features/bank-inventory/commands/bank-request-subcommand.ts +++ b/src/features/bank-inventory/commands/bank-request-subcommand.ts @@ -1,9 +1,4 @@ -import { - AutocompleteInteraction, - CacheType, - CommandInteraction, - EmbedBuilder, -} from "discord.js"; +import { AutocompleteInteraction, CacheType, CommandInteraction, EmbedBuilder } from "discord.js"; import { Subcommand } from "../../../shared/command/subcommand"; import { bankData } from "../bank-data"; import { bankRequestsChannelId } from "../../../config"; @@ -26,9 +21,7 @@ class BankRequest extends Subcommand { if (!item) { throw new Error(`An item is required.`); } else { - const stockList = await bankData.getItemStockById( - parseInt(String(item.value)) - ); + const stockList = await bankData.getItemStockById(parseInt(String(item.value))); let itemName = "unknown"; if (!stockList?.stock || stockList?.stock.length === 0) { stockEmbed @@ -37,11 +30,8 @@ class BankRequest extends Subcommand { itemName = String(this.getOptionValue("item", interaction)); } else { itemName = stockList?.name || "unknown"; - const count = stockList?.stock[0].count; - const countAvailable = stockList?.stock.reduce( - (total, s) => total + (s.count || 0), - 0 - ); + stockList?.stock[0].count; + const countAvailable = stockList?.stock.reduce((total, s) => total + (s.count || 0), 0); let inStock = ""; for (let i = 0; i < stockList?.stock.length && i <= 5; i++) { inStock += `${stockList?.stock[i].charName}: ${stockList?.stock[i].slot} (${stockList?.stock[i].count})\n`; @@ -52,9 +42,7 @@ class BankRequest extends Subcommand { // todo: add confirmation buttons https://discordjs.guide/message-components/interactions.html#awaiting-components // interaction.editReply({ // }) - stockEmbed - .setTitle(`${countAvailable} available:`) - .setDescription(inStock); + stockEmbed.setTitle(`${countAvailable} available:`).setDescription(inStock); } let message = `${Icon.Request} ${interaction.user} requests:`; @@ -89,18 +77,10 @@ class BankRequest extends Subcommand { .setAutocomplete(true) ) .addStringOption((o) => - o - .setName("count") - .setDescription("How many?") - .setRequired(true) - .setAutocomplete(true) + o.setName("count").setDescription("How many?").setRequired(true).setAutocomplete(true) ) .addStringOption((o) => - o - .setName("price") - .setDescription("Total price.") - .setRequired(false) - .setAutocomplete(true) + o.setName("price").setDescription("Total price.").setRequired(false).setAutocomplete(true) ) .addStringOption((o) => o @@ -111,20 +91,19 @@ class BankRequest extends Subcommand { ); } - public async getOptionAutocomplete( - option: string, - interaction: AutocompleteInteraction - ) { + public async getOptionAutocomplete(option: string, interaction: AutocompleteInteraction) { const input = interaction.options.getString("item"); // console.log("input", input) - if (!input || input.length < 3) return []; + if (!input || input.length < 3) { + return []; + } switch (option) { case Option.Item: return await autoCompleteStockedItems(input); case Option.Count: return [{ name: "1", value: "1" }]; // add price autocomplete - case Option.Price: + case Option.Price: { const itemId = await interaction.options.getString(Option.Item); if (itemId) { const price = await autoCompleteItemPrice(itemId); @@ -141,6 +120,8 @@ class BankRequest extends Subcommand { } else { return []; } + break; + } default: return []; } @@ -155,7 +136,4 @@ async function autoCompleteItemPrice(itemId: string) { } } -export const bankRequest = new BankRequest( - "request", - "Request an item from the guild bank." -); +export const bankRequest = new BankRequest("request", "Request an item from the guild bank."); diff --git a/src/features/bank-inventory/commands/bank-search-subcommand.ts b/src/features/bank-inventory/commands/bank-search-subcommand.ts index 05ffc99..f592009 100644 --- a/src/features/bank-inventory/commands/bank-search-subcommand.ts +++ b/src/features/bank-inventory/commands/bank-search-subcommand.ts @@ -1,14 +1,9 @@ -import { - AutocompleteInteraction, - CacheType, - CommandInteraction, - EmbedBuilder -} from "discord.js"; +import { AutocompleteInteraction, CacheType, CommandInteraction, EmbedBuilder } from "discord.js"; import { Subcommand } from "../../../shared/command/subcommand"; import { bankData } from "../bank-data"; import { autoCompleteStockedItems } from "../helpers"; enum Option { - Item = "item" + Item = "item", } class BankSearch extends Subcommand { @@ -17,54 +12,47 @@ class BankSearch extends Subcommand { const stockEmbed = new EmbedBuilder(); if (!item) { - throw new Error(`An item is required.`); + throw new Error(`An item is required.`); } else { const stockList = await bankData.getItemStockById(parseInt(String(item.value))); - let itemName = "unknown"; if (!stockList?.stock || stockList?.stock.length === 0) { - stockEmbed.setTitle("No stock found.") - .setDescription("Item not found in current bank inventory."); - itemName = String(this.getOptionValue("item", interaction)) + stockEmbed + .setTitle("No stock found.") + .setDescription("Item not found in current bank inventory."); } else { - itemName = stockList?.name || 'unknown'; - const count = stockList?.stock[0].count; const countAvailable = stockList?.stock.reduce((total, s) => total + (s.count || 0), 0); - let inStock = '' + let inStock = ""; for (let i = 0; i < stockList?.stock.length && i <= 30; i++) { - inStock += `${stockList?.stock[i].charName}: ${stockList?.stock[i].slot} (${stockList?.stock[i].count})\n` - }; - if(stockList?.stock.length > 40) { - inStock += "[list truncated]" + inStock += `${stockList?.stock[i].charName}: ${stockList?.stock[i].slot} (${stockList?.stock[i].count})\n`; } - stockEmbed.setTitle(`${countAvailable} available:`) - .setDescription(inStock); - } - try { - interaction.editReply({ - content: "", - embeds: [stockEmbed] - }) - } catch (e) { - throw(e); + if (stockList?.stock.length > 40) { + inStock += "[list truncated]"; + } + stockEmbed.setTitle(`${countAvailable} available:`).setDescription(inStock); } + interaction.editReply({ + content: "", + embeds: [stockEmbed], + }); } } public get command() { return super.command.addStringOption((o) => - o.setName(Option.Item) - .setDescription("What are you looking for?") - .setRequired(true) - .setAutocomplete(true) + o + .setName(Option.Item) + .setDescription("What are you looking for?") + .setRequired(true) + .setAutocomplete(true) ); } public async getOptionAutocomplete(option: string, interaction: AutocompleteInteraction) { - const input = interaction.options.getString('item'); + const input = interaction.options.getString("item"); // console.log("input", input) switch (option) { case Option.Item: - if(input && input.length > 3) { + if (input && input.length > 3) { return await autoCompleteStockedItems(input); } else { return []; @@ -75,9 +63,4 @@ class BankSearch extends Subcommand { } } - - -export const bankSearch = new BankSearch( - "search", - "Search for an item in the guild bank." -); +export const bankSearch = new BankSearch("search", "Search for an item in the guild bank."); diff --git a/src/features/bank-inventory/commands/bank-set-item-data-subcommand.ts b/src/features/bank-inventory/commands/bank-set-item-data-subcommand.ts index be22404..a16fd72 100644 --- a/src/features/bank-inventory/commands/bank-set-item-data-subcommand.ts +++ b/src/features/bank-inventory/commands/bank-set-item-data-subcommand.ts @@ -1,11 +1,6 @@ -import { - AutocompleteInteraction, - CacheType, - CommandInteraction, - EmbedBuilder - } from "discord.js"; +import { AutocompleteInteraction, CacheType, CommandInteraction, EmbedBuilder } from "discord.js"; import { Subcommand } from "../../../shared/command/subcommand"; -import { bankRequestsChannelId, bankerRoleId, officerRoleId, modRoleId } from "../../../config"; +import { bankerRoleId, officerRoleId, modRoleId } from "../../../config"; import { bankData } from "../bank-data"; import { authorizeByMemberRoles } from "../../../shared/command/util"; import { autoCompleteAllItems } from "../helpers"; @@ -13,16 +8,13 @@ import { autoCompleteAllItems } from "../helpers"; enum Option { Item = "item", Type = "type", - Price = "price" + Price = "price", } class SetItemData extends Subcommand { public async execute(interaction: CommandInteraction) { - // authorize - authorizeByMemberRoles([ - bankerRoleId, officerRoleId, modRoleId - ], interaction); + authorizeByMemberRoles([bankerRoleId, officerRoleId, modRoleId], interaction); const item = this.getOption(Option.Item, interaction); const price = this.getOption(Option.Price, interaction); @@ -30,59 +22,67 @@ class SetItemData extends Subcommand { const embed = new EmbedBuilder(); if (!item || !price) { - throw new Error(`An item and price is required.`); + throw new Error(`An item and price is required.`); } else { const itemData = await bankData.getItemStockById(parseInt(String(item.value))); - if(itemData) { - const setData = await bankData.setItemData(itemData.id, String(price.value)); + if (itemData) { + await bankData.setItemData(itemData.id, String(price.value)); const countAvailable = itemData?.stock.reduce((total, s) => total + (s.count || 0), 0); embed.setTitle("UPDATED: " + itemData.name); embed.setDescription( - "id: " + itemData.id - + "\nname: " + itemData.name - + "\ntype: " + itemData.type - + "\nprice: " + String(price.value) - + "\nin stock: " + countAvailable + "id: " + + itemData.id + + "\nname: " + + itemData.name + + "\ntype: " + + itemData.type + + "\nprice: " + + String(price.value) + + "\nin stock: " + + countAvailable ); } else { - embed.setDescription("Item not found") + embed.setDescription("Item not found"); } // console.log(itemData); interaction.editReply({ content: "", - embeds: [embed] - }) + embeds: [embed], + }); } - } public get command() { return super.command + .addStringOption( + (o) => + o + .setName(Option.Item) + .setDescription("Item data to set") + .setRequired(true) + .setAutocomplete(true) + // ).addStringOption((o) => + // o.setName(Option.Type) + // .setDescription("Item data to request") + // .setRequired(true) + // .setAutocomplete(true) + ) .addStringOption((o) => - o.setName(Option.Item) - .setDescription("Item data to set") - .setRequired(true) - .setAutocomplete(true) - // ).addStringOption((o) => - // o.setName(Option.Type) - // .setDescription("Item data to request") - // .setRequired(true) - // .setAutocomplete(true) - ).addStringOption((o) => - o.setName(Option.Price) - .setDescription("Set default price(s): Comma-separated list.") - .setRequired(true) - .setAutocomplete(false) - ) + o + .setName(Option.Price) + .setDescription("Set default price(s): Comma-separated list.") + .setRequired(true) + .setAutocomplete(false) + ); } public async getOptionAutocomplete(option: string, interaction: AutocompleteInteraction) { - const input = interaction.options.getString('item'); + const input = interaction.options.getString("item"); // console.log("input", input) switch (option) { case Option.Item: - if(input && input.length > 3) { + if (input && input.length > 3) { return await autoCompleteAllItems(input); } else { return []; @@ -91,7 +91,4 @@ class SetItemData extends Subcommand { } } -export const setItem = new SetItemData( - "set-item-data", - "Set Item Data" -); +export const setItem = new SetItemData("set-item-data", "Set Item Data"); diff --git a/src/features/bank-inventory/commands/command.ts b/src/features/bank-inventory/commands/command.ts index 55e23b5..5137e5e 100644 --- a/src/features/bank-inventory/commands/command.ts +++ b/src/features/bank-inventory/commands/command.ts @@ -5,14 +5,10 @@ import { bankSearch } from "./bank-search-subcommand"; import { getItem } from "./bank-get-item-data-subcommand"; import { setItem } from "./bank-set-item-data-subcommand"; -export const bankCommand = new Command( - "bank", - "Use the guild bank.", - [ - bankRequest, - syncBankDb, - bankSearch, - getItem, - setItem - ] -); \ No newline at end of file +export const bankCommand = new Command("bank", "Use the guild bank.", [ + bankRequest, + syncBankDb, + bankSearch, + getItem, + setItem, +]); diff --git a/src/features/bank-inventory/helpers.ts b/src/features/bank-inventory/helpers.ts index ff0c017..2ab7352 100644 --- a/src/features/bank-inventory/helpers.ts +++ b/src/features/bank-inventory/helpers.ts @@ -2,25 +2,24 @@ import { bankData } from "./bank-data"; export const autoCompleteStockedItems = async (stem: string) => { const items = await bankData.getItemsByStem(stem); - if(items) { + if (items) { return items - .filter((i) => i._count.stock > 0) - .map((i)=>({ - name: i.name + " (" + i._count.stock + ")", - value: String(i.id) - })); + .filter((i) => i._count.stock > 0) + .map((i) => ({ + name: i.name + " (" + i._count.stock + ")", + value: String(i.id), + })); } - return []; -} + return []; +}; export const autoCompleteAllItems = async (stem: string) => { const items = await bankData.getItemsByStem(stem); - if(items) { - return items - .map((i)=>({ - name: i.name + " (" + i._count.stock + ")", - value: String(i.id) + if (items) { + return items.map((i) => ({ + name: i.name + " (" + i._count.stock + ")", + value: String(i.id), })); } - return []; -} \ No newline at end of file + return []; +}; diff --git a/src/features/bank-inventory/inventory-files.ts b/src/features/bank-inventory/inventory-files.ts index 2b5534b..dfd4717 100644 --- a/src/features/bank-inventory/inventory-files.ts +++ b/src/features/bank-inventory/inventory-files.ts @@ -1,11 +1,5 @@ import { InventoryItem } from "./bank-data"; -import { - uploadFileToFolder, - DriveFile, - findFiles, - updateFile - -} from "../../services/gdrive"; +import { uploadFileToFolder, DriveFile, findFiles, updateFile } from "../../services/gdrive"; export const outputfilesFolderId = "1DBaLEyUFsxCcYwJzFYblILgPu5sK8uT5"; export const defaultUploadsFolderId = "1hYIR3o94diHF1dtNs_-x7BSp33bq4lDp"; @@ -33,10 +27,10 @@ export const parseInventoryFile = async (fileName: string, data: string) => { // TODO: determine character type based on file parent in gdrive? return { charName: charName, - charType: 'banker', + charType: "banker", items: inventoryItems, - } -} + }; +}; export const uploadToGDrive = async (filename: string, contents: string) => { const file: DriveFile = { @@ -46,9 +40,7 @@ export const uploadToGDrive = async (filename: string, contents: string) => { }; try { // note: limiting this to a folder doesn't seem to be working well, it will replace a file anywhere in the drive with the same name. careful. - const outputfiles = await findFiles( - `name='${filename}' and trashed=false` - ); + const outputfiles = await findFiles(`name='${filename}' and trashed=false`); // const outputfiles = await findFileInFolders(filename, "outputfiles"); // if found, update it outputfiles.forEach(async (val) => { @@ -63,4 +55,4 @@ export const uploadToGDrive = async (filename: string, contents: string) => { // if not found, upload it to to be sorted folder await uploadFileToFolder(file, defaultUploadsFolderId); } -} \ No newline at end of file +}; diff --git a/src/features/bank-request-info/bank-cleanup-button-command.ts b/src/features/bank-request-info/bank-cleanup-button-command.ts index 9c23156..655cc9f 100644 --- a/src/features/bank-request-info/bank-cleanup-button-command.ts +++ b/src/features/bank-request-info/bank-cleanup-button-command.ts @@ -1,16 +1,7 @@ -import { - ButtonInteraction, - CacheType, - ChannelType, - Message, - User, -} from "discord.js"; +import { ButtonInteraction, CacheType, ChannelType, Message, User } from "discord.js"; import { bankerRoleId, bankRequestsChannelId } from "../../config"; import { ButtonCommand } from "../../shared/command/button-command"; -import { - getChannel, - requireInteractionMemberRole, -} from "../../shared/command/util"; +import { getChannel, requireInteractionMemberRole } from "../../shared/command/util"; class BankCleanupCommand extends ButtonCommand { public async execute(interaction: ButtonInteraction) { @@ -19,9 +10,7 @@ class BankCleanupCommand extends ButtonCommand { const messages = await bankRequestsChannel.messages.fetch(); const nonBankerMessagesMap = messages - .filter( - (m) => !(m.member?.roles.cache.has(bankerRoleId) || m.member?.user.bot) - ) + .filter((m) => !(m.member?.roles.cache.has(bankerRoleId) || m.member?.user.bot)) .reduce((map, message) => { const id = message.author.id; if (!map[id]) { @@ -56,9 +45,7 @@ ${messages.map((m) => this.getQuotedContent(m.content)).join("\n")}`); }); await interaction.editReply({ - content: `Removed stale bank requests from: ${Object.values( - nonBankerMessagesMap - ) + content: `Removed stale bank requests from: ${Object.values(nonBankerMessagesMap) .map(({ user }) => user) .map((u) => `${u}`) .join(" ")}`, diff --git a/src/features/bank-request-info/bank-services.ts b/src/features/bank-request-info/bank-services.ts index ed7a60e..05ae5ab 100644 --- a/src/features/bank-request-info/bank-services.ts +++ b/src/features/bank-request-info/bank-services.ts @@ -1,4 +1,4 @@ - import { auctionChannelId } from "../../config"; +import { auctionChannelId } from "../../config"; import { Icon, Service } from "./types"; // todo: store this in database, populate and remove with command @@ -18,10 +18,7 @@ export const services: Service[] = [ { title: "OT Hammer Event Scheduling", icon: Icon.Sold, - requestFormats: [ - "OT Hammer Event", - "OT Hammer Event: Date, Time (include timezone)", - ], + requestFormats: ["OT Hammer Event", "OT Hammer Event: Date, Time (include timezone)"], bullets: [ "_The Overthere, Outpost_ Look for monthly threads for date/time", "Bring 1 Jade and either 1750pp (members and allies) or 2500p (non-allies)", @@ -89,9 +86,7 @@ export const services: Service[] = [ { title: "Dropped Spell Spreadsheet", icon: Icon.Sold, - requestFormats: [ - "Dropped spell: Class, Level, Spell name (Mule name, Quantity available)", - ], + requestFormats: ["Dropped spell: Class, Level, Spell name (Mule name, Quantity available)"], inventoryUrl: "https://tinyurl.com/castle-spell-spreadsheet", bullets: [ "_North Freeport Bank_", diff --git a/src/features/bank-request-info/banking-button-command.ts b/src/features/bank-request-info/banking-button-command.ts index 87d0d3e..cced9d6 100644 --- a/src/features/bank-request-info/banking-button-command.ts +++ b/src/features/bank-request-info/banking-button-command.ts @@ -1,10 +1,7 @@ -import { ButtonInteraction, CacheType, ChannelType, Collection, User } from "discord.js"; +import { ButtonInteraction, CacheType, ChannelType, User } from "discord.js"; import { bankerRoleId, bankRequestsChannelId } from "../../config"; import { ButtonCommand } from "../../shared/command/button-command"; -import { - getChannel, - requireInteractionMemberRole, -} from "../../shared/command/util"; +import { getChannel, requireInteractionMemberRole } from "../../shared/command/util"; import { getAttentionMessage } from "../invite-list/ping-invite-list-button-command"; class BankingButtonCommand extends ButtonCommand { @@ -13,32 +10,24 @@ class BankingButtonCommand extends ButtonCommand { const messages = await bankRequestsChannel.messages.fetch(); - const botMentions = messages.filter( - (m) => (m.member?.user.bot && m.content.match("requests:") && m.mentions) - ).map( - (m) => Array.from(m.mentions.parsedUsers.values())[0] - ) + const botMentions = messages + .filter((m) => m.member?.user.bot && m.content.match("requests:") && m.mentions) + .map((m) => Array.from(m.mentions.parsedUsers.values())[0]); // get all non-banker messages const users = [ ...new Set( messages - .filter( - (m) => - !(m.member?.roles.cache.has(bankerRoleId)||m.member?.user.bot) - ) + .filter((m) => !(m.member?.roles.cache.has(bankerRoleId) || m.member?.user.bot)) .map((r) => r.member?.user) .filter(Boolean) .concat(botMentions) - ) + ), ]; - const attention = await getAttentionMessage( - users.map((u) => (u as User).id) - ); + const attention = await getAttentionMessage(users.map((u) => (u as User).id)); - await interaction.channel - ?.send(`**${interaction.member?.user} is now banking!** + await interaction.channel?.send(`**${interaction.member?.user} is now banking!** ${attention}`); diff --git a/src/features/bank-request-info/update-action.ts b/src/features/bank-request-info/update-action.ts index cc05976..9aea58a 100644 --- a/src/features/bank-request-info/update-action.ts +++ b/src/features/bank-request-info/update-action.ts @@ -12,28 +12,20 @@ import { BankHour } from "../../db/bank-hour"; import { dataSource } from "../../db/data-source"; import { Name } from "../../db/instructions"; import { InstructionsReadyAction } from "../../shared/action/instructions-ready-action"; -import { - readyActionExecutor, - ReadyActionExecutorOptions, -} from "../../shared/action/ready-action"; +import { readyActionExecutor, ReadyActionExecutorOptions } from "../../shared/action/ready-action"; import { services } from "./bank-services"; import { bankCleanupButtonCommand } from "./bank-cleanup-button-command"; import { bankingButtonCommand } from "./banking-button-command"; import { Icon } from "./types"; -export const updateBankRequestInfo = ( - client: Client, - options?: ReadyActionExecutorOptions -) => readyActionExecutor(new UpdateBankRequestInfoAction(client), options); +export const updateBankRequestInfo = (client: Client, options?: ReadyActionExecutorOptions) => + readyActionExecutor(new UpdateBankRequestInfoAction(client), options); class UpdateBankRequestInfoAction extends InstructionsReadyAction { public async execute() { await this.createOrUpdateInstructions( { - embeds: [ - ...(await this.getServicesEmbeds()), - await this.getInstructionsEmbed(), - ], + embeds: [...(await this.getServicesEmbeds()), await this.getInstructionsEmbed()], components: [await this.getButtons()], }, Name.BankRequestInstructions @@ -57,9 +49,7 @@ class UpdateBankRequestInfoAction extends InstructionsReadyAction { return services.map( ({ title, icon, requestFormats, inventoryUrl, bullets }) => new EmbedBuilder({ - title: `${icon} ${inventoryUrl ? "__" : ""}${title}${ - inventoryUrl ? "__" : "" - }`, + title: `${icon} ${inventoryUrl ? "__" : ""}${title}${inventoryUrl ? "__" : ""}`, url: inventoryUrl, footer: { text: requestFormats.map((r) => `${Icon.Request} ${r}`).join("\n"), diff --git a/src/features/bp/bp-command.ts b/src/features/bp/bp-command.ts index 6816b23..489de34 100644 --- a/src/features/bp/bp-command.ts +++ b/src/features/bp/bp-command.ts @@ -10,13 +10,8 @@ import { import { Command } from "../../shared/command/command"; import { Subcommand } from "../../shared/command/subcommand"; import { getTextChannel, prismaClient } from "../.."; -import { Prisma } from "@prisma/client" -import { - batphoneChannelId, - raiderRoleId, - trackerRoleId, - wakeupChannelId, -} from "../../config"; +import { Prisma } from "@prisma/client"; +import { batphoneChannelId, raiderRoleId, trackerRoleId, wakeupChannelId } from "../../config"; import { authorizeByMemberRoles } from "../../shared/command/util"; import { officerRoleId, modRoleId, knightRoleId } from "../../config"; import { error } from "console"; @@ -26,16 +21,13 @@ import { truncate } from "lodash"; import { RequestBotButtonCommand } from "./request-bot-button-command"; import { PublicAccountsFactory } from "../../services/bot/bot-factory"; import { LocationService } from "../../services/location"; -import { log } from "../../shared/logger" +import { log } from "../../shared/logger"; class sendBp extends Subcommand { public async execute(interaction: CommandInteraction) { try { // authorize - authorizeByMemberRoles( - [officerRoleId, modRoleId, knightRoleId, trackerRoleId], - interaction - ); + authorizeByMemberRoles([officerRoleId, modRoleId, knightRoleId, trackerRoleId], interaction); const bpChannel = await getTextChannel(batphoneChannelId); const val = this.getOption("message", interaction)?.value as string; @@ -46,9 +38,7 @@ class sendBp extends Subcommand { }, }); savedBp - ? log( - `Found saved batphone ${savedBp.key} for ${savedBp.location}` - ) + ? log(`Found saved batphone ${savedBp.key} for ${savedBp.location}`) : log(`No key found for ${val}`); const message = savedBp?.message || val; if (typeof message === "string") { @@ -71,9 +61,7 @@ class sendBp extends Subcommand { // Wakeup if (wakeupChannelId) { const wakeupService = container.resolve(WakeupService); - wakeupService.runWakeup( - `Batphone. ${interaction.user} sent ${message}` - ); + wakeupService.runWakeup(`Batphone. ${interaction.user} sent ${message}`); } } else { interaction.editReply("Failed to post batphone."); @@ -83,10 +71,7 @@ class sendBp extends Subcommand { } } - public async getOptionAutocomplete( - option: string, - interaction: AutocompleteInteraction - ): Promise< + public async getOptionAutocomplete(): Promise< ApplicationCommandOptionChoiceData[] | undefined > { const res = await prismaClient.batphone.findMany(); @@ -98,24 +83,14 @@ class sendBp extends Subcommand { public get command() { return super.command.addStringOption((o) => - o - .setName("message") - .setDescription("BP Message") - .setRequired(true) - .setAutocomplete(true) + o.setName("message").setDescription("BP Message").setRequired(true).setAutocomplete(true) ); } } export const getBotButtonComponents = async (location: string) => { - const bots = await PublicAccountsFactory.getService().getBotsForBatphone( - location - ); - log( - `loading bots for batphone in ${location} - ${bots - .map((b) => b.name) - .join(",")}` - ); + const bots = await PublicAccountsFactory.getService().getBotsForBatphone(location); + log(`loading bots for batphone in ${location} - ${bots.map((b) => b.name).join(",")}`); const components: ActionRowBuilder[] = []; let row; for (let i = 0; i < bots.length; i++) { @@ -128,9 +103,7 @@ export const getBotButtonComponents = async (location: string) => { } log(`adding button for ${bots[i].name}`); row?.addComponents( - new RequestBotButtonCommand( - `requestbot_${bots[i].name}` - ).getButtonBuilder(bots[i]) + new RequestBotButtonCommand(`requestbot_${bots[i].name}`).getButtonBuilder(bots[i]) ); } return components; @@ -139,10 +112,7 @@ export const getBotButtonComponents = async (location: string) => { class setBp extends Subcommand { public async execute(interaction: CommandInteraction) { // authorize - authorizeByMemberRoles( - [officerRoleId, modRoleId, knightRoleId], - interaction - ); + authorizeByMemberRoles([officerRoleId, modRoleId, knightRoleId], interaction); const message = this.getOption("message", interaction)?.value; try { @@ -155,8 +125,7 @@ class setBp extends Subcommand { if (!key) { key = message.split(" ")[0].toLowerCase(); } - const location = this.getOption("location", interaction) - ?.value as string || ""; + const location = (this.getOption("location", interaction)?.value as string) || ""; key = truncate(String(key), { length: 100 }); // max option length = 100 await prismaClient.batphone.create({ data: { @@ -166,9 +135,7 @@ class setBp extends Subcommand { }, }); log( - `Created batphone - key: ${key}, location: ${ - location || "unset" - }, message: ${message}` + `Created batphone - key: ${key}, location: ${location || "unset"}, message: ${message}` ); interaction.editReply("Saved preset message: " + message); } else { @@ -178,8 +145,8 @@ class setBp extends Subcommand { console.error(err); let errMsg = err; if (err instanceof Prisma.PrismaClientKnownRequestError) { - if (err.code === 'P2002') { - errMsg = "Key already exists"; + if (err.code === "P2002") { + errMsg = "Key already exists"; } else { errMsg = err.code; } @@ -188,12 +155,10 @@ class setBp extends Subcommand { } } public async getOptionAutocomplete( - option: string, - interaction: AutocompleteInteraction - ): Promise< - ApplicationCommandOptionChoiceData[] | undefined - > { - switch (option) { + _option: string, + _interaction: AutocompleteInteraction + ): Promise[] | undefined> { + switch (_option) { case "location": return LocationService.getInstance().getLocationOptions(); default: @@ -204,18 +169,10 @@ class setBp extends Subcommand { public get command() { return super.command .addStringOption((o) => - o - .setName("message") - .setDescription("BP Message") - .setRequired(true) - .setAutocomplete(false) + o.setName("message").setDescription("BP Message").setRequired(true).setAutocomplete(false) ) .addStringOption((o) => - o - .setName("key") - .setDescription("Key (optional") - .setRequired(false) - .setAutocomplete(false) + o.setName("key").setDescription("Key (optional").setRequired(false).setAutocomplete(false) ) .addStringOption((o) => o @@ -230,10 +187,7 @@ class setBp extends Subcommand { class unsetBp extends Subcommand { public async execute(interaction: CommandInteraction) { // authorize - authorizeByMemberRoles( - [officerRoleId, modRoleId, knightRoleId], - interaction - ); + authorizeByMemberRoles([officerRoleId, modRoleId, knightRoleId], interaction); const key = this.getOption("message", interaction)?.value; try { @@ -252,10 +206,7 @@ class unsetBp extends Subcommand { interaction.editReply("Failed save batphone message."); } } - public async getOptionAutocomplete( - option: string, - interaction: AutocompleteInteraction - ): Promise< + public async getOptionAutocomplete(): Promise< ApplicationCommandOptionChoiceData[] | undefined > { const res = await prismaClient.batphone.findMany(); @@ -267,11 +218,7 @@ class unsetBp extends Subcommand { public get command() { return super.command.addStringOption((o) => - o - .setName("message") - .setDescription("BP Message") - .setRequired(true) - .setAutocomplete(true) + o.setName("message").setDescription("BP Message").setRequired(true).setAutocomplete(true) ); } } @@ -279,10 +226,7 @@ class unsetBp extends Subcommand { class getBp extends Subcommand { public async execute(interaction: CommandInteraction) { // authorize - authorizeByMemberRoles( - [officerRoleId, modRoleId, knightRoleId, trackerRoleId], - interaction - ); + authorizeByMemberRoles([officerRoleId, modRoleId, knightRoleId, trackerRoleId], interaction); try { const val = this.getOption("message", interaction)?.value as string; @@ -297,7 +241,7 @@ class getBp extends Subcommand { if (!message) { throw new Error(`No batphone with key ${val}`); } - + if (typeof message === "string") { const formattedMessage = message.replace( /\\n/g, @@ -314,9 +258,7 @@ Location: ${savedMsg?.location || "NO LOCATION SET"} To change this message, use \`/bp update\` to set a new message. `; savedMsg - ? log( - `Found saved batphone ${savedMsg.key} for ${savedMsg.location}` - ) + ? log(`Found saved batphone ${savedMsg.key} for ${savedMsg.location}`) : log(`No key found for ${val}`); const components: ActionRowBuilder[] = await getBotButtonComponents(savedMsg?.location || ""); @@ -334,10 +276,7 @@ To change this message, use \`/bp update\` to set a new message. } } - public async getOptionAutocomplete( - option: string, - interaction: AutocompleteInteraction - ): Promise< + public async getOptionAutocomplete(): Promise< ApplicationCommandOptionChoiceData[] | undefined > { const res = await prismaClient.batphone.findMany(); @@ -349,11 +288,7 @@ To change this message, use \`/bp update\` to set a new message. public get command() { return super.command.addStringOption((o) => - o - .setName("message") - .setDescription("BP Message") - .setRequired(true) - .setAutocomplete(true) + o.setName("message").setDescription("BP Message").setRequired(true).setAutocomplete(true) ); } } @@ -361,10 +296,7 @@ To change this message, use \`/bp update\` to set a new message. class updateBp extends Subcommand { public async execute(interaction: CommandInteraction) { // authorize - authorizeByMemberRoles( - [officerRoleId, modRoleId, knightRoleId], - interaction - ); + authorizeByMemberRoles([officerRoleId, modRoleId, knightRoleId], interaction); const message = this.getOption("message", interaction)?.value; try { @@ -377,32 +309,29 @@ class updateBp extends Subcommand { if (!key) { key = message.split(" ")[0].toLowerCase(); } - const location = this.getOption("location", interaction) - ?.value as string || ""; + const location = (this.getOption("location", interaction)?.value as string) || ""; key = truncate(String(key), { length: 100 }); // max option length = 100 - let updateNoLocation = { - message: message + const updateNoLocation = { + message: message, }; - let updateWithLocation = { + const updateWithLocation = { message: message, - location: location + location: location, }; - let update = location ? updateWithLocation : updateNoLocation; + const update = location ? updateWithLocation : updateNoLocation; await prismaClient.batphone.update({ where: { - key: key + key: key, }, - data: update + data: update, }); log( - `Updated batphone - key: ${key}, location: ${ - location || "unset" - }, message: ${message}` + `Updated batphone - key: ${key}, location: ${location || "unset"}, message: ${message}` ); interaction.editReply("Updated Batphone: " + key); } else { @@ -412,8 +341,8 @@ class updateBp extends Subcommand { console.error(err); let errMsg = err; if (err instanceof Prisma.PrismaClientKnownRequestError) { - if (err.code === 'P2025') { - errMsg = "No batphone found with the provided key"; + if (err.code === "P2025") { + errMsg = "No batphone found with the provided key"; } else { errMsg = err.code; } @@ -423,11 +352,8 @@ class updateBp extends Subcommand { } public async getOptionAutocomplete( - option: string, - interaction: AutocompleteInteraction - ): Promise< - ApplicationCommandOptionChoiceData[] | undefined - > { + option: string + ): Promise[] | undefined> { switch (option) { case "location": return LocationService.getInstance().getLocationOptions(); @@ -439,18 +365,10 @@ class updateBp extends Subcommand { public get command() { return super.command .addStringOption((o) => - o - .setName("message") - .setDescription("BP Message") - .setRequired(true) - .setAutocomplete(false) + o.setName("message").setDescription("BP Message").setRequired(true).setAutocomplete(false) ) .addStringOption((o) => - o - .setName("key") - .setDescription("Key (optional") - .setRequired(false) - .setAutocomplete(false) + o.setName("key").setDescription("Key (optional").setRequired(false).setAutocomplete(false) ) .addStringOption((o) => o @@ -462,14 +380,10 @@ class updateBp extends Subcommand { } } -export const batphoneCommand = new Command( - "bp", - "set and send batphone messages", - [ - new sendBp("send", "send batphone"), - new setBp("set", "save a BP preset"), - new unsetBp("unset", "remove BP preset"), - new getBp("get", "show BP message in this channel"), - new updateBp("update", "update a BP") - ] -); +export const batphoneCommand = new Command("bp", "set and send batphone messages", [ + new sendBp("send", "send batphone"), + new setBp("set", "save a BP preset"), + new unsetBp("unset", "remove BP preset"), + new getBp("get", "show BP message in this channel"), + new updateBp("update", "update a BP"), +]); diff --git a/src/features/bp/request-bot-button-command.ts b/src/features/bp/request-bot-button-command.ts index 962141a..6d3d987 100644 --- a/src/features/bp/request-bot-button-command.ts +++ b/src/features/bp/request-bot-button-command.ts @@ -7,20 +7,17 @@ import { } from "discord.js"; import { ButtonCommand } from "../../shared/command/button-command"; import { bot } from "@prisma/client"; -import { knightRoleId, raiderRoleId } from "../../config"; +import { raiderRoleId } from "../../config"; import { getClassAbreviation } from "../../shared/classes"; import { PublicAccountsFactory } from "../../services/bot/bot-factory"; -import { log } from "../../shared/logger" +import { log } from "../../shared/logger"; export class RequestBotButtonCommand extends ButtonCommand { constructor(name: string) { super(name); } - public async execute( - interaction: ButtonInteraction - ): Promise { - + public async execute(interaction: ButtonInteraction): Promise { await this.setButtonState(interaction, false); interaction.editReply({ @@ -29,24 +26,15 @@ export class RequestBotButtonCommand extends ButtonCommand { const name = interaction.customId.split("_")[1]; try { - const guildUser = await interaction.guild?.members.fetch( - interaction.user.id - ); - log( - `${ - guildUser?.nickname || guildUser?.user.username - } clicked batphone button for ${name}` - ); + const guildUser = await interaction.guild?.members.fetch(interaction.user.id); + log(`${guildUser?.nickname || guildUser?.user.username} clicked batphone button for ${name}`); await PublicAccountsFactory.getService().doBotCheckout(name, interaction); } catch (err: unknown) { await this.setButtonState(interaction, true); } } - private async setButtonState( - interaction: ButtonInteraction, - enabled: boolean - ) { + private async setButtonState(interaction: ButtonInteraction, enabled: boolean) { const rowIdx = interaction.message.components.findIndex((row) => row.components.find((c) => c.customId === interaction.customId) ); @@ -69,14 +57,10 @@ export class RequestBotButtonCommand extends ButtonCommand { public getButtonBuilder(bot: bot): ButtonBuilder { const icon = !bot.requiredRoles.includes(raiderRoleId) ? "🛡️" : ""; return new ButtonBuilder() - .setLabel( - `${icon}${bot.name} (${bot.level} ${getClassAbreviation(bot.class)})` - ) + .setLabel(`${icon}${bot.name} (${bot.level} ${getClassAbreviation(bot.class)})`) .setCustomId(`requestbot_${bot.name}`) .setStyle(ButtonStyle.Primary); } } -export const requestBotButtonCommand = new RequestBotButtonCommand( - "requestbot" -); +export const requestBotButtonCommand = new RequestBotButtonCommand("requestbot"); diff --git a/src/features/dkp-records/commands/bonuses-thread-subcommand.ts b/src/features/dkp-records/commands/bonuses-thread-subcommand.ts index bf22b95..c7173a5 100644 --- a/src/features/dkp-records/commands/bonuses-thread-subcommand.ts +++ b/src/features/dkp-records/commands/bonuses-thread-subcommand.ts @@ -39,10 +39,7 @@ export class BonusesThreadSubcommand extends Subcommand { throw new Error("The Castle DKP Bonuses Character ID is not set."); } - const eventName = this.getRequiredOptionValue( - Option.Event, - interaction - ); + const eventName = this.getRequiredOptionValue(Option.Event, interaction); const event = await castledkp.getEvent(eventName); if (!event) { throw new Error(`The event type "${eventName}" could not be found.`); @@ -51,9 +48,7 @@ export class BonusesThreadSubcommand extends Subcommand { const name = this.getRequiredOptionValue(Option.Name, interaction); // create thread - const channel = await interaction.guild?.channels.fetch( - dkpBonusesChannelId - ); + const channel = await interaction.guild?.channels.fetch(dkpBonusesChannelId); if (!channel) { throw new Error("Could not find DKP bonuses channel"); } @@ -123,10 +118,7 @@ export class BonusesThreadSubcommand extends Subcommand { .setRequired(true) ) .addStringOption((o) => - o - .setName(Option.Name) - .setDescription("The name of the raid bonuses.") - .setRequired(true) + o.setName(Option.Name).setDescription("The name of the raid bonuses.").setRequired(true) ); } diff --git a/src/features/dkp-records/commands/player-dkp-subcommand.ts b/src/features/dkp-records/commands/player-dkp-subcommand.ts index 9dc6eaa..80604dd 100644 --- a/src/features/dkp-records/commands/player-dkp-subcommand.ts +++ b/src/features/dkp-records/commands/player-dkp-subcommand.ts @@ -1,9 +1,4 @@ -import { - CacheType, - CommandInteraction, - TimestampStyles, - time, -} from "discord.js"; +import { CacheType, CommandInteraction, TimestampStyles, time } from "discord.js"; import { castledkp } from "../../../services/castledkp"; import { Subcommand } from "../../../shared/command/subcommand"; import { code } from "../../../shared/util"; @@ -19,10 +14,7 @@ export class PlayerDkpSubcommand extends Subcommand { } public async execute(interaction: CommandInteraction) { - const characterName = this.getRequiredOptionValue( - Option.Character, - interaction - ); + const characterName = this.getRequiredOptionValue(Option.Character, interaction); const spam = this.getOptionValue(Option.Spam, interaction); const character = await castledkp.getCharacter(characterName); if (!character) { @@ -31,11 +23,7 @@ export class PlayerDkpSubcommand extends Subcommand { const points = await castledkp.getPointsByCharacter(character.id); const net = points.currentDkp; const result = - net === 0 - ? "0" - : net > 0 - ? `+ ${net}` - : `- ${net}`; + net === 0 ? "0" : net > 0 ? `+ ${net}` : `- ${net}`; const content = `**${points.characterName}** DKP as of ${time( Date.now(), TimestampStyles.ShortDateTime @@ -48,9 +36,8 @@ ${result}${code}`; if (spam) { await interaction.channel?.send({ content }); await interaction.editReply({ - content: "Done.", - }); + }); } else { await interaction.editReply({ content, @@ -63,17 +50,13 @@ ${result}${code}`; .addStringOption((o) => o .setName(Option.Character) - .setDescription( - "The name of the character whose points you want to review." - ) + .setDescription("The name of the character whose points you want to review.") .setRequired(true) ) .addBooleanOption((o) => o .setName(Option.Spam) - .setDescription( - "Set to true if you want the response to be sent to the entire channel." - ) + .setDescription("Set to true if you want the response to be sent to the entire channel.") ); } diff --git a/src/features/dkp-records/commands/set-tick-subcommand.ts b/src/features/dkp-records/commands/set-tick-subcommand.ts index 9775eee..9064828 100644 --- a/src/features/dkp-records/commands/set-tick-subcommand.ts +++ b/src/features/dkp-records/commands/set-tick-subcommand.ts @@ -1,13 +1,5 @@ -import { - CacheType, - CommandInteraction, - GuildMemberRoleManager, -} from "discord.js"; -import { - dkpDeputyRoleId, - dkpRecordsChannelId, - officerRoleId, -} from "../../../config"; +import { CacheType, CommandInteraction, GuildMemberRoleManager } from "discord.js"; +import { dkpDeputyRoleId, dkpRecordsChannelId, officerRoleId } from "../../../config"; import { castledkp } from "../../../services/castledkp"; import { Subcommand } from "../../../shared/command/subcommand"; import { getRaidReport } from "../raid-report"; @@ -44,10 +36,7 @@ export class SetTickSubcommand extends Subcommand { // get raid report const { report } = await getRaidReport(interaction.channel); - const eventName = this.getRequiredOptionValue( - Option.Event, - interaction - ); + const eventName = this.getRequiredOptionValue(Option.Event, interaction); const note = this.getOptionValue(Option.Note, interaction); const tick = this.getOptionValue(Option.Tick, interaction); let value = this.getOptionValue(Option.Value, interaction); @@ -67,9 +56,9 @@ export class SetTickSubcommand extends Subcommand { await report.tryUpdateThreadName(interaction.channel); - const message = `${interaction.user} identified ${ticksUpdated.join( - ", " - )} as "${event.shortName} (${value})".`; + const message = `${interaction.user} identified ${ticksUpdated.join(", ")} as "${ + event.shortName + } (${value})".`; await interaction.channel.send(message); @@ -100,9 +89,7 @@ export class SetTickSubcommand extends Subcommand { ) ) .addStringOption((o) => - o - .setName(Option.Note) - .setDescription("An optional note to be added to the raid tick.") + o.setName(Option.Note).setDescription("An optional note to be added to the raid tick.") ); } diff --git a/src/features/dkp-records/create/create-raid-report-thread.ts b/src/features/dkp-records/create/create-raid-report-thread.ts index ada0434..5105ad5 100644 --- a/src/features/dkp-records/create/create-raid-report-thread.ts +++ b/src/features/dkp-records/create/create-raid-report-thread.ts @@ -1,17 +1,13 @@ import { Message, Attachment } from "discord.js"; import { dkpDeputyRoleId, dkpRecordsChannelId } from "../../../config"; -import { - MessageAction, - messageActionExecutor, -} from "../../../shared/action/message-action"; +import { MessageAction, messageActionExecutor } from "../../../shared/action/message-action"; import { read, utils, WorkSheet } from "xlsx"; import axios from "axios"; import { RaidReport } from "../raid-report"; import { addRoleToThread } from "../../../shared/command/util"; import { isValidXlsxData, SheetParser } from "./sheet-parser"; -const supportedFormat = - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; +const supportedFormat = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; export const tryCreateRaidReportThreadAction = (message: Message) => messageActionExecutor(new CreateRaidReportThreadMessageAction(message)); @@ -86,9 +82,7 @@ class CreateRaidReportThreadMessageAction extends MessageAction { }); // add credit messages - await Promise.all( - report.getCreditCommands().map((content) => thread.send({ content })) - ); + await Promise.all(report.getCreditCommands().map((content) => thread.send({ content }))); // add deputies to thread await addRoleToThread(dkpDeputyRoleId, thread); diff --git a/src/features/dkp-records/create/credit-parser.test.ts b/src/features/dkp-records/create/credit-parser.test.ts index 17d2ca0..92f736c 100644 --- a/src/features/dkp-records/create/credit-parser.test.ts +++ b/src/features/dkp-records/create/credit-parser.test.ts @@ -66,9 +66,7 @@ describe("reason", () => { }); it("handles unknown for arrow tells", () => { - const parser = new CreditParser( - "[Sat Feb 25 16:15:47 2023] Pumped -> Someone: creditt" - ); + const parser = new CreditParser("[Sat Feb 25 16:15:47 2023] Pumped -> Someone: creditt"); const credit = parser.getCredit(); expect(credit.type).toEqual("UNKNOWN"); expect(credit.character).toEqual("Pumped"); @@ -79,9 +77,7 @@ describe("reason", () => { }); it("handles unknown for arrow tells with long credit", () => { - const parser = new CreditParser( - "[Sat Feb 25 16:15:47 2023] Pumped -> Someone: credittt" - ); + const parser = new CreditParser("[Sat Feb 25 16:15:47 2023] Pumped -> Someone: credittt"); const credit = parser.getCredit(); expect(credit.type).toEqual("UNKNOWN"); expect(credit.character).toEqual("Pumped"); diff --git a/src/features/dkp-records/finish/finish-raid-report-reaction.ts b/src/features/dkp-records/finish/finish-raid-report-reaction.ts index a17d7bb..0ceaaa2 100644 --- a/src/features/dkp-records/finish/finish-raid-report-reaction.ts +++ b/src/features/dkp-records/finish/finish-raid-report-reaction.ts @@ -1,25 +1,12 @@ -import { - MessageReaction, - PartialMessageReaction, - PartialUser, - User, -} from "discord.js"; -import { - dkpDeputyRoleId, - dkpRecordsChannelId, - officerRoleId, -} from "../../../config"; -import { - ReactionAction, - reactionActionExecutor, -} from "../../../shared/action/reaction-action"; +import { MessageReaction, PartialMessageReaction, PartialUser, User } from "discord.js"; +import { dkpDeputyRoleId, dkpRecordsChannelId, officerRoleId } from "../../../config"; +import { ReactionAction, reactionActionExecutor } from "../../../shared/action/reaction-action"; import { getRaidReport, isRaidInstructionsMessage } from "../raid-report"; export const tryRaidReportFinishedReactionAction = ( reaction: MessageReaction | PartialMessageReaction, user: User | PartialUser -) => - reactionActionExecutor(new RaidReportFinishedReactionAction(reaction, user)); +) => reactionActionExecutor(new RaidReportFinishedReactionAction(reaction, user)); class RaidReportFinishedReactionAction extends ReactionAction { public async execute() { @@ -56,12 +43,7 @@ class RaidReportFinishedReactionAction extends ReactionAction { // authorize user const reactor = await this.members?.fetch(this.user.id); - if ( - !( - reactor?.roles.cache.has(dkpDeputyRoleId) || - reactor?.roles.cache.has(officerRoleId) - ) - ) { + if (!(reactor?.roles.cache.has(dkpDeputyRoleId) || reactor?.roles.cache.has(officerRoleId))) { return; } diff --git a/src/features/dkp-records/raid-report.ts b/src/features/dkp-records/raid-report.ts index c7123f1..e285362 100644 --- a/src/features/dkp-records/raid-report.ts +++ b/src/features/dkp-records/raid-report.ts @@ -1,9 +1,4 @@ -import { - Message, - EmbedBuilder, - TextBasedChannel, - ThreadChannel, -} from "discord.js"; +import { Message, EmbedBuilder, TextBasedChannel, ThreadChannel } from "discord.js"; import { every, flatMap, max, uniq } from "lodash"; import { raiderRoleId } from "../../config"; import { redisChannels, redisClient } from "../../redis/client"; @@ -29,20 +24,16 @@ const INSTRUCTIONS_TITLE = "Instructions"; const THREAD_EMBED_CHAR_LIMIT = 4000; const SECOND_COLUMN_LENGTH = 6; -const isRaidReportMessage = (m: Message) => - !!m.embeds.find((e) => e.title === RAID_REPORT_TITLE); +const isRaidReportMessage = (m: Message) => !!m.embeds.find((e) => e.title === RAID_REPORT_TITLE); -const isNotEmpty = (m: Message) => - !!m.embeds.find((e) => e.length === 0); +const isNotEmpty = (m: Message) => !!m.embeds.find((e) => e.length === 0); export const isRaidInstructionsMessage = (m: Message) => !!m.embeds.find((e) => e.title === INSTRUCTIONS_TITLE); export const getRaidReportMessages = async (channel: TextBasedChannel) => { if (!channel.isThread()) { - throw new Error( - "Could not find raid report messages because channel is not a thread." - ); + throw new Error("Could not find raid report messages because channel is not a thread."); } const starter = await channel.fetchStarterMessage(); @@ -91,11 +82,7 @@ export class RaidReport { this.ticks = data.ticks.map((t) => new RaidTick(t)); this.firstColumnLength = - max( - [...this.allAttendees, ...this.allAdjustees, EVERYONE].map( - (a) => a.length - ) - ) || 0; + max([...this.allAttendees, ...this.allAdjustees, EVERYONE].map((a) => a.length)) || 0; } public get allTicksHaveEvent(): boolean { @@ -121,11 +108,11 @@ export class RaidReport { public getThreadName(): string { const emoji = this.finished ? "✅" : this.allTicksHaveEvent ? "❕" : "❔"; const label = every(this.ticks, (t) => t.hasEvent) - ? uniq(this.ticks.map(({ eventAbreviation }) => eventAbreviation)).join( - ", " - ) + ? uniq(this.ticks.map(({ eventAbreviation }) => eventAbreviation)).join(", ") : `${this.filename.replace(/[^a-zA-Z]+/g, "")}?`; - return `${emoji} ${this.ticks[0].shortDate} (${Math.round(this.netDkp)}) ${label || "Unidentified"}`; + return `${emoji} ${this.ticks[0].shortDate} (${Math.round(this.netDkp)}) ${ + label || "Unidentified" + }`; } public getCreditCommands(): string[] { @@ -135,9 +122,7 @@ export class RaidReport { public async updateMessages(messages: Message[]) { const raidReportEmbeds = this.getRaidReportEmbeds(); if (raidReportEmbeds.length > messages.length) { - throw new Error( - "Insufficient messages for number of embeds. This should never happen" - ); + throw new Error("Insufficient messages for number of embeds. This should never happen"); } try { @@ -156,9 +141,7 @@ export class RaidReport { }) ); } catch (err) { - throw new Error( - `Could not generate edited raid report with action values: ${err}` - ); + throw new Error(`Could not generate edited raid report with action values: ${err}`); } } @@ -218,10 +201,7 @@ Kill bonus values: https://castledkp.com/index.php/External/Boss-bonuses-11.html ]); } - public getReceiptEmbeds( - created: CreateRaidResponse[], - failed: string[] - ): EmbedBuilder[] { + public getReceiptEmbeds(created: CreateRaidResponse[], failed: string[]): EmbedBuilder[] { const embeds = created.map(({ eventUrlSlug, id, invalidNames, tick }) => tick.getCreatedEmbed(eventUrlSlug, id, invalidNames) ); @@ -245,10 +225,7 @@ ${this.attendance}`; const pages: string[] = [""]; report.split("\n").forEach((line) => { - if ( - pages[pages.length - 1].length + line.length > - THREAD_EMBED_CHAR_LIMIT - ) { + if (pages[pages.length - 1].length + line.length > THREAD_EMBED_CHAR_LIMIT) { pages.push(""); } pages[pages.length - 1] += `\n${line}`; @@ -266,9 +243,7 @@ ${p}${code}`, public async uploadRemainingRaidTicks(threadUrl: string) { const settled = await Promise.allSettled( - this.ticks - .filter((t) => !t.data.finished) - .map((t) => t.uploadAsRaid(threadUrl)) + this.ticks.filter((t) => !t.data.finished).map((t) => t.uploadAsRaid(threadUrl)) ); const created: CreateRaidResponse[] = []; @@ -297,28 +272,17 @@ ${p}${code}`, this.getRaidTicks(tickNumbers).forEach((t) => t.removePlayer(name)); } - public replacePlayer( - replacer: string, - replaced: string, - tickNumbers: number[] - ) { - this.getRaidTicks(tickNumbers).forEach((t) => - t.replacePlayer(replacer, replaced) - ); + public replacePlayer(replacer: string, replaced: string, tickNumbers: number[]) { + this.getRaidTicks(tickNumbers).forEach((t) => t.replacePlayer(replacer, replaced)); } private getRaidTicks(tickNumbers: number[]): RaidTick[] { - return (tickNumbers.length === 0 ? this.allTickNumbers : tickNumbers).map( - (t) => this.getRaidTick(t) + return (tickNumbers.length === 0 ? this.allTickNumbers : tickNumbers).map((t) => + this.getRaidTick(t) ); } - public updateRaidTick( - event: RaidEventData, - value: number, - tick?: number, - note?: string - ) { + public updateRaidTick(event: RaidEventData, value: number, tick?: number, note?: string) { const tickNumbers = tick ? [tick] : this.allTickNumbers; tickNumbers.forEach((t) => this.getRaidTick(t).update(event, value, note)); return tickNumbers; diff --git a/src/features/dkp-records/raid-tick.ts b/src/features/dkp-records/raid-tick.ts index 381f803..1f2e639 100644 --- a/src/features/dkp-records/raid-tick.ts +++ b/src/features/dkp-records/raid-tick.ts @@ -10,223 +10,215 @@ export const UPLOAD_DATE_FORMAT = "YYYY-MM-DD HH:mm"; export const EVERYONE = "Everyone"; export interface AdjustmentData { - player: string; - value: number; - reason: string; + player: string; + value: number; + reason: string; } export interface RaidTickData { - finished: boolean; - tickNumber: number; - sheetName: string; - value?: number; - event?: RaidEventData; - note?: string; - loot: LootData[]; - attendees: string[]; - date: string; - credits: CreditData[]; - adjustments?: AdjustmentData[]; + finished: boolean; + tickNumber: number; + sheetName: string; + value?: number; + event?: RaidEventData; + note?: string; + loot: LootData[]; + attendees: string[]; + date: string; + credits: CreditData[]; + adjustments?: AdjustmentData[]; } interface Change { - person: string; - change: string; - reason: string; + person: string; + change: string; + reason: string; } export const getRaidUrl = (eventUrlSlug: string, raidId: number) => - `https://castledkp.com/index.php/Raids/[green]-${eventUrlSlug}-r${raidId}.html?s=`; + `https://castledkp.com/index.php/Raids/[green]-${eventUrlSlug}-r${raidId}.html?s=`; export class RaidTick { - public constructor(public readonly data: RaidTickData) { } - - public get hasEvent(): boolean { - return !!this.data.event; - } - - private get date(): Moment { - return moment(this.data.date); - } - - public get shortDateTime(): string { - return this.date.format("M-D H:mm"); - } - public get shortDate(): string { - return this.date.format("M-D"); - } - public get eventAbreviation(): string { - return this.data.event?.abreviation || ""; - } - - // todo maybe truncate this with ellipses based on param (for raid reports, since note can be long) - public get name(): string { - return `${this.data.finished ? "✅ " : ""}${this.shortDateTime} ${this.eventAbreviation || this.data.sheetName - } ${this.data.tickNumber}${this.note}`; - } - public get uploadNote(): string { - return `${this.data.finished ? "✅ " : ""}${this.shortDate} ${this.eventAbreviation || this.data.sheetName - } ${this.data.tickNumber}${this.note}`; - } - public get note(): string { - return this.data.note ? ` (${this.data.note})` : ""; - } - - public get earned(): number { - const adjustments = sumBy(this.data.adjustments, ({ value }) => value); - return this.data.value === undefined - ? 0 + adjustments - : this.data.attendees.length * this.data.value + adjustments; - } - - public get uploadDate(): string { - return this.date.format(UPLOAD_DATE_FORMAT); - } - - public get spent(): number { - return sumBy(this.data.loot, (l) => l.price); - } - - public async uploadAsRaid(threadUrl: string) { - if (this.data.finished) { - throw new Error(`${this.name} has already been uploaded.`); - } - const response = await castledkp.createRaidFromTick(this, threadUrl); - this.data.finished = true; - return response; - } - - public addAdjustment(adjustment: AdjustmentData) { - if (!this.data.adjustments) { - this.data.adjustments = []; - } - this.data.adjustments.push(adjustment); - } - - public addPlayer(name: string) { - if (!this.data.attendees.includes(name)) { - this.data.attendees.push(name); - this.data.attendees.sort(); - } - } - - public removePlayer(name: string) { - const index = this.data.attendees.indexOf(name); - if (index < 0) { - return; - } - this.data.attendees.splice(index, 1); - } - - public replacePlayer(replacer: string, replaced: string) { - const index = this.data.attendees.indexOf(replaced); - if (index < 0) { - return; - } - this.data.attendees[index] = replacer; - } - - public update(event: RaidEventData, value: number, note?: string) { - this.data.event = event; - this.data.value = value; - this.data.note = note; - } - - public renderTick(firstColumnLength: number, secondColumnLength: number) { - const ready = - this.data.value !== undefined && this.data.event !== undefined; - const all = EVERYONE.padEnd(firstColumnLength); - const attendanceValue = `${this.getPaddedDkp( - secondColumnLength, - this.data.value === undefined ? "+?" : `+${this.data.value}` - )}`; - const changes: Change[] = [ - ...this.data.loot.map((l) => ({ - person: l.buyer, - change: `-${l.price}`, - reason: l.item, - })), - ...(this.data.adjustments || []).map((a) => ({ - person: a.player, - change: `+${a.value}`, - reason: a.reason, - })), - ]; - const change = - changes.length > 0 - ? `\n${this.renderChanges( - changes, - firstColumnLength, - secondColumnLength - )}` - : ""; - return `--- ${this.name} --- + public constructor(public readonly data: RaidTickData) {} + + public get hasEvent(): boolean { + return !!this.data.event; + } + + private get date(): Moment { + return moment(this.data.date); + } + + public get shortDateTime(): string { + return this.date.format("M-D H:mm"); + } + public get shortDate(): string { + return this.date.format("M-D"); + } + public get eventAbreviation(): string { + return this.data.event?.abreviation || ""; + } + + // todo maybe truncate this with ellipses based on param (for raid reports, since note can be long) + public get name(): string { + return `${this.data.finished ? "✅ " : ""}${this.shortDateTime} ${ + this.eventAbreviation || this.data.sheetName + } ${this.data.tickNumber}${this.note}`; + } + public get uploadNote(): string { + return `${this.data.finished ? "✅ " : ""}${this.shortDate} ${ + this.eventAbreviation || this.data.sheetName + } ${this.data.tickNumber}${this.note}`; + } + public get note(): string { + return this.data.note ? ` (${this.data.note})` : ""; + } + + public get earned(): number { + const adjustments = sumBy(this.data.adjustments, ({ value }) => value); + return this.data.value === undefined + ? 0 + adjustments + : this.data.attendees.length * this.data.value + adjustments; + } + + public get uploadDate(): string { + return this.date.format(UPLOAD_DATE_FORMAT); + } + + public get spent(): number { + return sumBy(this.data.loot, (l) => l.price); + } + + public async uploadAsRaid(threadUrl: string) { + if (this.data.finished) { + throw new Error(`${this.name} has already been uploaded.`); + } + const response = await castledkp.createRaidFromTick(this, threadUrl); + this.data.finished = true; + return response; + } + + public addAdjustment(adjustment: AdjustmentData) { + if (!this.data.adjustments) { + this.data.adjustments = []; + } + this.data.adjustments.push(adjustment); + } + + public addPlayer(name: string) { + if (!this.data.attendees.includes(name)) { + this.data.attendees.push(name); + this.data.attendees.sort(); + } + } + + public removePlayer(name: string) { + const index = this.data.attendees.indexOf(name); + if (index < 0) { + return; + } + this.data.attendees.splice(index, 1); + } + + public replacePlayer(replacer: string, replaced: string) { + const index = this.data.attendees.indexOf(replaced); + if (index < 0) { + return; + } + this.data.attendees[index] = replacer; + } + + public update(event: RaidEventData, value: number, note?: string) { + this.data.event = event; + this.data.value = value; + this.data.note = note; + } + + public renderTick(firstColumnLength: number, secondColumnLength: number) { + const ready = this.data.value !== undefined && this.data.event !== undefined; + const all = EVERYONE.padEnd(firstColumnLength); + const attendanceValue = `${this.getPaddedDkp( + secondColumnLength, + this.data.value === undefined ? "+?" : `+${this.data.value}` + )}`; + const changes: Change[] = [ + ...this.data.loot.map((l) => ({ + person: l.buyer, + change: `-${l.price}`, + reason: l.item, + })), + ...(this.data.adjustments || []).map((a) => ({ + person: a.player, + change: `+${a.value}`, + reason: a.reason, + })), + ]; + const change = + changes.length > 0 + ? `\n${this.renderChanges(changes, firstColumnLength, secondColumnLength)}` + : ""; + return `--- ${this.name} --- ${ready ? "+" : "-"} ${all} ${attendanceValue} (Attendance)${change}`; - } - - public getCreatedEmbed( - eventUrlSlug: string, - id: number, - invalidNames: string[] - ): EmbedBuilder { - const net = this.earned - this.spent; - const result = - net === 0 - ? "No change to economy" - : net > 0 - ? `+ Economy increase ${net}` - : `- Economy decrease ${net}`; - const notIncluded = - invalidNames.length > 0 - ? `These characters were not included because they do not exist ${invalidNames.join( - ", " - )}` - : ""; - return new EmbedBuilder({ - title: `${this.name}`, - description: `${code}diff + } + + public getCreatedEmbed(eventUrlSlug: string, id: number, invalidNames: string[]): EmbedBuilder { + const net = this.earned - this.spent; + const result = + net === 0 + ? "No change to economy" + : net > 0 + ? `+ Economy increase ${net}` + : `- Economy decrease ${net}`; + const notIncluded = + invalidNames.length > 0 + ? `These characters were not included because they do not exist ${invalidNames.join(", ")}` + : ""; + return new EmbedBuilder({ + title: `${this.name}`, + description: `${code}diff DKP Earned ${this.earned} DKP Spent ${this.spent} ------------------------------- ${result}${code}${notIncluded}`, - url: getRaidUrl(eventUrlSlug, id), - }); - } - - private renderChanges( - changes: Change[], - firstColumnLength: number, - secondColumnLength: number - ): string { - return changes - .sort((a, b) => a.person.localeCompare(b.person)) - .map((c) => this.renderChange(c, firstColumnLength, secondColumnLength)) - .join("\n"); - } - - private renderChange( - { person, change, reason }: Change, - firstColumnLength: number, - secondColumnLength: number - ) { - return `+ ${person.padEnd(firstColumnLength)} ${this.getPaddedDkp( - secondColumnLength, - change - )} (${reason})`; - } - - public get creditCommands(): string[] { - return this.data.credits.map((c) => - c.type === "UNKNOWN" - ? `⚠️ Unparsable credit: ${c.character} said '${c.raw}' during Raid Tick ${this.data.tickNumber}` - : c.type === "PILOT" - ? `!rep ${c.character} with ${c.pilot} ${this.data.tickNumber}${c.reason ? ` (${c.reason})` : "" - }` - : `!add ${c.character} ${this.data.tickNumber} (${c.reason})` - ); - } - - private getPaddedDkp(secondColumnLength: number, value: string) { - return value.padEnd(secondColumnLength); - } + url: getRaidUrl(eventUrlSlug, id), + }); + } + + private renderChanges( + changes: Change[], + firstColumnLength: number, + secondColumnLength: number + ): string { + return changes + .sort((a, b) => a.person.localeCompare(b.person)) + .map((c) => this.renderChange(c, firstColumnLength, secondColumnLength)) + .join("\n"); + } + + private renderChange( + { person, change, reason }: Change, + firstColumnLength: number, + secondColumnLength: number + ) { + return `+ ${person.padEnd(firstColumnLength)} ${this.getPaddedDkp( + secondColumnLength, + change + )} (${reason})`; + } + + public get creditCommands(): string[] { + return this.data.credits.map((c) => + c.type === "UNKNOWN" + ? `⚠️ Unparsable credit: ${c.character} said '${c.raw}' during Raid Tick ${this.data.tickNumber}` + : c.type === "PILOT" + ? `!rep ${c.character} with ${c.pilot} ${this.data.tickNumber}${ + c.reason ? ` (${c.reason})` : "" + }` + : `!add ${c.character} ${this.data.tickNumber} (${c.reason})` + ); + } + + private getPaddedDkp(secondColumnLength: number, value: string) { + return value.padEnd(secondColumnLength); + } } diff --git a/src/features/dkp-records/request-bonus/approve-raid-bonus-request-reaction.ts b/src/features/dkp-records/request-bonus/approve-raid-bonus-request-reaction.ts index 5861a15..ffaa57d 100644 --- a/src/features/dkp-records/request-bonus/approve-raid-bonus-request-reaction.ts +++ b/src/features/dkp-records/request-bonus/approve-raid-bonus-request-reaction.ts @@ -1,22 +1,11 @@ -import { - MessageReaction, - PartialMessageReaction, - PartialUser, - User, -} from "discord.js"; -import { - ReactionAction, - reactionActionExecutor, -} from "../../../shared/action/reaction-action"; +import { MessageReaction, PartialMessageReaction, PartialUser, User } from "discord.js"; +import { ReactionAction, reactionActionExecutor } from "../../../shared/action/reaction-action"; import { getAction, getBonusMessageContent } from "./util"; export const tryApproveRaidBonusRequestReactionAction = ( reaction: MessageReaction | PartialMessageReaction, user: User | PartialUser -) => - reactionActionExecutor( - new ApproveRaidBonusRequestReactionAction(reaction, user) - ); +) => reactionActionExecutor(new ApproveRaidBonusRequestReactionAction(reaction, user)); class ApproveRaidBonusRequestReactionAction extends ReactionAction { public async execute() { diff --git a/src/features/dkp-records/request-bonus/raid-bonus-request.ts b/src/features/dkp-records/request-bonus/raid-bonus-request.ts index aa3fa24..6899113 100644 --- a/src/features/dkp-records/request-bonus/raid-bonus-request.ts +++ b/src/features/dkp-records/request-bonus/raid-bonus-request.ts @@ -14,10 +14,7 @@ export abstract class RaidBonusRequest { return new Error(`Invalid "${this.constructor.name}" format, ${error}`); } - public async tryExecute( - message: PartialMessage | Message, - actor?: GuildMember - ) { + public async tryExecute(message: PartialMessage | Message, actor?: GuildMember) { if (await checkReactionFromClient(message, "✅")) { return; } @@ -25,12 +22,7 @@ export abstract class RaidBonusRequest { await this.validateArgs(); // authorize execution - if ( - !( - actor?.roles.cache.has(dkpDeputyRoleId) || - actor?.roles.cache.has(officerRoleId) - ) - ) { + if (!(actor?.roles.cache.has(dkpDeputyRoleId) || actor?.roles.cache.has(officerRoleId))) { return false; } diff --git a/src/features/dkp-records/request-bonus/request-bonus-message-action.ts b/src/features/dkp-records/request-bonus/request-bonus-message-action.ts index a1073fa..9e3eec8 100644 --- a/src/features/dkp-records/request-bonus/request-bonus-message-action.ts +++ b/src/features/dkp-records/request-bonus/request-bonus-message-action.ts @@ -1,8 +1,5 @@ import { Message } from "discord.js"; -import { - MessageAction, - messageActionExecutor, -} from "../../../shared/action/message-action"; +import { MessageAction, messageActionExecutor } from "../../../shared/action/message-action"; import { getAction, getBonusMessageContent } from "./util"; export const tryRaidBonusMessageAction = (message: Message) => @@ -26,9 +23,7 @@ class RaidBonusMessageAction extends MessageAction { // warning emoji and dm await this.message.react("⚠️"); if (!this.message.author.bot) { - this.message.author.send( - `Command to request raid bonus is invalid. \`${err}\`` - ); + this.message.author.send(`Command to request raid bonus is invalid. \`${err}\``); } } } diff --git a/src/features/dkp-records/request-bonus/util.ts b/src/features/dkp-records/request-bonus/util.ts index 2282920..7cd71e5 100644 --- a/src/features/dkp-records/request-bonus/util.ts +++ b/src/features/dkp-records/request-bonus/util.ts @@ -4,9 +4,7 @@ import { AddAdjustmentBonus } from "./add-adjustment-bonus"; const multipleSpaces = /\s+/; -export const getBonusMessageContent = async ( - message: Message | PartialMessage -) => { +export const getBonusMessageContent = async (message: Message | PartialMessage) => { const thread = message.channel.isThread(); if (!thread) { return; @@ -27,9 +25,7 @@ export const getAction = (content: string) => { // remove parenthetical expressions const stripped = content.replace(/\(.+?\)/g, "").trim(); - const [actionType, ...actionArguments] = stripped - .slice(1) - .split(multipleSpaces); + const [actionType, ...actionArguments] = stripped.slice(1).split(multipleSpaces); switch (actionType.toLowerCase()) { case "adj": diff --git a/src/features/dkp-records/request-revision/approve-raid-report-revision-reaction.ts b/src/features/dkp-records/request-revision/approve-raid-report-revision-reaction.ts index a14c103..886e828 100644 --- a/src/features/dkp-records/request-revision/approve-raid-report-revision-reaction.ts +++ b/src/features/dkp-records/request-revision/approve-raid-report-revision-reaction.ts @@ -1,22 +1,11 @@ -import { - MessageReaction, - PartialMessageReaction, - PartialUser, - User, -} from "discord.js"; -import { - ReactionAction, - reactionActionExecutor, -} from "../../../shared/action/reaction-action"; +import { MessageReaction, PartialMessageReaction, PartialUser, User } from "discord.js"; +import { ReactionAction, reactionActionExecutor } from "../../../shared/action/reaction-action"; import { getAction, getRaidRevisionMessageContent } from "./util"; export const tryApproveRaidReportRevisionReactionAction = ( reaction: MessageReaction | PartialMessageReaction, user: User | PartialUser -) => - reactionActionExecutor( - new ApproveRaidReportRevisionReactionAction(reaction, user) - ); +) => reactionActionExecutor(new ApproveRaidReportRevisionReactionAction(reaction, user)); class ApproveRaidReportRevisionReactionAction extends ReactionAction { public async execute() { diff --git a/src/features/dkp-records/request-revision/raid-report-revision-message-action.ts b/src/features/dkp-records/request-revision/raid-report-revision-message-action.ts index 336c3f4..7a4884f 100644 --- a/src/features/dkp-records/request-revision/raid-report-revision-message-action.ts +++ b/src/features/dkp-records/request-revision/raid-report-revision-message-action.ts @@ -1,12 +1,6 @@ import { Message } from "discord.js"; -import { - MessageAction, - messageActionExecutor, -} from "../../../shared/action/message-action"; -import { - getAction, - getRaidRevisionMessageContent as getRaidRevisionMessageContent, -} from "./util"; +import { MessageAction, messageActionExecutor } from "../../../shared/action/message-action"; +import { getAction, getRaidRevisionMessageContent as getRaidRevisionMessageContent } from "./util"; export const tryRaidReportRevisionMessageAction = (message: Message) => messageActionExecutor(new RaidReportRevisionMessageAction(message)); @@ -27,9 +21,7 @@ class RaidReportRevisionMessageAction extends MessageAction { // warning emoji and dm await this.message.react("⚠️"); if (!this.message.author.bot) { - this.message.author.send( - `Command to request raid edit is invalid. \`${err}\`` - ); + this.message.author.send(`Command to request raid edit is invalid. \`${err}\``); } } } diff --git a/src/features/dkp-records/request-revision/raid-report-revision.ts b/src/features/dkp-records/request-revision/raid-report-revision.ts index 0b22744..e29c139 100644 --- a/src/features/dkp-records/request-revision/raid-report-revision.ts +++ b/src/features/dkp-records/request-revision/raid-report-revision.ts @@ -7,9 +7,7 @@ export const checkReactionFromClient = async ( message: PartialMessage | Message, emojiName: string ) => { - const reaction = message.reactions.cache.find( - (r) => r.emoji.name === emojiName - ); + const reaction = message.reactions.cache.find((r) => r.emoji.name === emojiName); if (!reaction) { return false; } @@ -31,22 +29,14 @@ export abstract class RaidReportRevision { return new Error(`Invalid "${this.constructor.name}" format, ${error}`); } - public async tryExecute( - message: PartialMessage | Message, - actor?: GuildMember - ) { + public async tryExecute(message: PartialMessage | Message, actor?: GuildMember) { if (await checkReactionFromClient(message, "✅")) { return; } await this.validateArgs(); // authorize execution - if ( - !( - actor?.roles.cache.has(dkpDeputyRoleId) || - actor?.roles.cache.has(officerRoleId) - ) - ) { + if (!(actor?.roles.cache.has(dkpDeputyRoleId) || actor?.roles.cache.has(officerRoleId))) { return false; } diff --git a/src/features/dkp-records/request-revision/util.ts b/src/features/dkp-records/request-revision/util.ts index 1dcd5d7..ddb1e62 100644 --- a/src/features/dkp-records/request-revision/util.ts +++ b/src/features/dkp-records/request-revision/util.ts @@ -7,11 +7,11 @@ import { AddAdjustmentRevision } from "./add-adjustment-revision"; const multipleSpaces = /\s+/; -export const getRaidRevisionMessageContent = async ( - message: Message | PartialMessage -) => { +export const getRaidRevisionMessageContent = async (message: Message | PartialMessage) => { if (!message) { - throw new Error("Tried to get raid revision message content but the message was undefined. Fetch?"); + throw new Error( + "Tried to get raid revision message content but the message was undefined. Fetch?" + ); } const thread = message.channel.isThread(); if (!thread) { @@ -33,9 +33,7 @@ export const getAction = (content: string) => { // remove parenthetical expressions const stripped = content.replace(/\(.+?\)/g, "").trim(); - const [actionType, ...actionArguments] = stripped - .slice(1) - .split(multipleSpaces); + const [actionType, ...actionArguments] = stripped.slice(1).split(multipleSpaces); switch (actionType.toLowerCase()) { case "add": diff --git a/src/features/dkp-records/update/update-raid-report.ts b/src/features/dkp-records/update/update-raid-report.ts index ad2c482..7123218 100644 --- a/src/features/dkp-records/update/update-raid-report.ts +++ b/src/features/dkp-records/update/update-raid-report.ts @@ -3,26 +3,21 @@ import { getGuild } from "../../.."; import { SECONDS } from "../../../shared/time"; import { getRaidReportMessages, RaidReport } from "../raid-report"; -export const updateRaidReport = debounce( - async (message: string, channel: string) => { - const words = channel.split("."); - if (words[0] !== "raid" || !words[1]) { - return; - } +export const updateRaidReport = debounce(async (message: string, channel: string) => { + const words = channel.split("."); + if (words[0] !== "raid" || !words[1]) { + return; + } - const guild = await getGuild(); - const thread = await guild.channels.fetch(words[1]); + const guild = await getGuild(); + const thread = await guild.channels.fetch(words[1]); - if (!thread?.isThread()) { - throw new Error( - `Failed to update raid report: channel ${words[1]} is not a thread` - ); - } + if (!thread?.isThread()) { + throw new Error(`Failed to update raid report: channel ${words[1]} is not a thread`); + } - const report = new RaidReport(JSON.parse(message)); - const messages = await getRaidReportMessages(thread); + const report = new RaidReport(JSON.parse(message)); + const messages = await getRaidReportMessages(thread); - await report.updateMessages(messages); - }, - 3 * SECONDS -); + await report.updateMessages(messages); +}, 3 * SECONDS); diff --git a/src/features/gatehouse-tags/reaction.ts b/src/features/gatehouse-tags/reaction.ts index a0ea1b6..da22bde 100644 --- a/src/features/gatehouse-tags/reaction.ts +++ b/src/features/gatehouse-tags/reaction.ts @@ -1,10 +1,4 @@ -import { - MessageReaction, - PartialMessageReaction, - PartialUser, - Permissions, - User, -} from "discord.js"; +import { MessageReaction, PartialMessageReaction, PartialUser, User } from "discord.js"; import { castleRoleId, gatehouseChannelId, @@ -15,10 +9,7 @@ import { guardRoleId, officerRoleId, } from "../../config"; -import { - ReactionAction, - reactionActionExecutor, -} from "../../shared/action/reaction-action"; +import { ReactionAction, reactionActionExecutor } from "../../shared/action/reaction-action"; import { greetingActivity } from "../gatehouse/guild-member-add-listener"; import { actionConfigByReaction, Emoji, ActionType } from "./config"; @@ -36,12 +27,7 @@ class GatehouseReactionAction extends ReactionAction { // authorize user const reactor = await this.members?.fetch(this.user.id); - if ( - !( - reactor?.roles.cache.has(guardRoleId) || - reactor?.roles.cache.has(officerRoleId) - ) - ) { + if (!(reactor?.roles.cache.has(guardRoleId) || reactor?.roles.cache.has(officerRoleId))) { return; } diff --git a/src/features/invite-list/add-player-button-command.ts b/src/features/invite-list/add-player-button-command.ts index bcb631e..bb121f2 100644 --- a/src/features/invite-list/add-player-button-command.ts +++ b/src/features/invite-list/add-player-button-command.ts @@ -6,10 +6,7 @@ import { updateInviteListInfo } from "./update-invite-action"; import { checkInvite } from "./util"; class AddPlayerButton extends ButtonCommand { - public constructor( - public readonly customId: string, - public readonly alt = false - ) { + public constructor(public readonly customId: string, public readonly alt = false) { super(customId); } @@ -27,11 +24,6 @@ class AddPlayerButton extends ButtonCommand { } } -export const addPlayerInviteButtonCommand = new AddPlayerButton( - "addPlayerInvite" -); +export const addPlayerInviteButtonCommand = new AddPlayerButton("addPlayerInvite"); -export const addAltInviteButtonCommand = new AddPlayerButton( - "addAltInvite", - true -); +export const addAltInviteButtonCommand = new AddPlayerButton("addAltInvite", true); diff --git a/src/features/invite-list/add-subcommand.ts b/src/features/invite-list/add-subcommand.ts index 0c8aae8..c8bd2eb 100644 --- a/src/features/invite-list/add-subcommand.ts +++ b/src/features/invite-list/add-subcommand.ts @@ -29,10 +29,7 @@ class Add extends Subcommand { public get command() { return super.command .addUserOption((o) => - o - .setName(Option.DiscordUser) - .setDescription("The Discord user to remove") - .setRequired(true) + o.setName(Option.DiscordUser).setDescription("The Discord user to remove").setRequired(true) ) .addBooleanOption((o) => o.setName(Option.Alt).setDescription("If the invite is for an alt.") diff --git a/src/features/invite-list/cleanup-invites-command.ts b/src/features/invite-list/cleanup-invites-command.ts index 5d52512..a67f1f1 100644 --- a/src/features/invite-list/cleanup-invites-command.ts +++ b/src/features/invite-list/cleanup-invites-command.ts @@ -17,10 +17,7 @@ const OLD_LIMIT = 2 * WEEKS; class CleanupInvitesCommand extends ButtonCommand { public async execute(interaction: ButtonInteraction) { - requireInteractionMemberPermission( - PermissionFlagsBits.ManageRoles, - interaction - ); + requireInteractionMemberPermission(PermissionFlagsBits.ManageRoles, interaction); const oldInvites = await this.getOldInvites(); if (!oldInvites.length) { @@ -45,14 +42,9 @@ ${removed} await updateInviteListInfo(interaction.client); } - protected getUsers( - invites: InviteSimple[], - interaction: ButtonInteraction - ) { + protected getUsers(invites: InviteSimple[], interaction: ButtonInteraction) { const discordIds = [...new Set(invites.map((i) => i.discordId))]; - return interaction.guild?.members.cache?.filter((m) => - discordIds.includes(m.id) - ); + return interaction.guild?.members.cache?.filter((m) => discordIds.includes(m.id)); } protected async removeMains( @@ -97,12 +89,8 @@ Thank you!`); const inviteRepository = dataSource.getRepository(InviteSimple); const invites = await inviteRepository.findBy({}); const now = new Date().getTime(); - return invites.filter( - (i) => Number(now - i.createdAt.getTime()) > OLD_LIMIT - ); + return invites.filter((i) => Number(now - i.createdAt.getTime()) > OLD_LIMIT); } } -export const cleanupInvitesCommand = new CleanupInvitesCommand( - "cleanupInvites" -); +export const cleanupInvitesCommand = new CleanupInvitesCommand("cleanupInvites"); diff --git a/src/features/invite-list/invite-request-finished-reaction.ts b/src/features/invite-list/invite-request-finished-reaction.ts index 013e897..a46a47c 100644 --- a/src/features/invite-list/invite-request-finished-reaction.ts +++ b/src/features/invite-list/invite-request-finished-reaction.ts @@ -1,23 +1,12 @@ -import { - MessageReaction, - PartialMessageReaction, - PartialUser, - User, -} from "discord.js"; +import { MessageReaction, PartialMessageReaction, PartialUser, User } from "discord.js"; import { inviteListChannelId, guardRoleId, officerRoleId } from "../../config"; -import { - ReactionAction, - reactionActionExecutor, -} from "../../shared/action/reaction-action"; +import { ReactionAction, reactionActionExecutor } from "../../shared/action/reaction-action"; import { removePlayer } from "./remove-subcommand"; export const tryInviteRequestFinishedReactionAction = ( reaction: MessageReaction | PartialMessageReaction, user: User | PartialUser -) => - reactionActionExecutor( - new InviteRequestFinishedReactionAction(reaction, user) - ); +) => reactionActionExecutor(new InviteRequestFinishedReactionAction(reaction, user)); class InviteRequestFinishedReactionAction extends ReactionAction { public async execute() { @@ -33,12 +22,7 @@ class InviteRequestFinishedReactionAction extends ReactionAction { // authorize user const reactor = await this.members?.fetch(this.user.id); - if ( - !( - reactor?.roles.cache.has(guardRoleId) || - reactor?.roles.cache.has(officerRoleId) - ) - ) { + if (!(reactor?.roles.cache.has(guardRoleId) || reactor?.roles.cache.has(officerRoleId))) { return; } @@ -54,9 +38,7 @@ class InviteRequestFinishedReactionAction extends ReactionAction { }) ).values(), ]; - const requesterMessages = messages.filter( - (m) => m.member?.id === this.message.member?.id - ); + const requesterMessages = messages.filter((m) => m.member?.id === this.message.member?.id); const requesterMessageIds = requesterMessages.map((m) => m.id); const replies = messages.filter( (m) => @@ -67,9 +49,7 @@ class InviteRequestFinishedReactionAction extends ReactionAction { // its a reply to a message that is queued to be deleted requesterMessageIds.includes(m.reference.messageId) ); - requesterMessages - .filter((m) => m.embeds.length === 0) - .map((m) => m.delete()); + requesterMessages.filter((m) => m.embeds.length === 0).map((m) => m.delete()); replies.filter((m) => m.embeds.length === 0).map((m) => m.delete()); } } diff --git a/src/features/invite-list/ping-invite-list-button-command.ts b/src/features/invite-list/ping-invite-list-button-command.ts index a50a4ce..a67e1e2 100644 --- a/src/features/invite-list/ping-invite-list-button-command.ts +++ b/src/features/invite-list/ping-invite-list-button-command.ts @@ -1,19 +1,10 @@ -import { - ButtonInteraction, - CacheType, - ChannelType, - PermissionFlagsBits, - Permissions, -} from "discord.js"; +import { ButtonInteraction, CacheType, ChannelType, PermissionFlagsBits } from "discord.js"; import { getGuild } from "../.."; import { inviteListChannelId } from "../../config"; import { dataSource } from "../../db/data-source"; import { InviteSimple } from "../../db/invite-simple"; import { ButtonCommand } from "../../shared/command/button-command"; -import { - getChannel, - requireInteractionMemberPermission, -} from "../../shared/command/util"; +import { getChannel, requireInteractionMemberPermission } from "../../shared/command/util"; import { HOURS } from "../../shared/time"; const getPresenceIcon = (status = "unknown") => { @@ -54,19 +45,13 @@ ${statuses.map(({ user, status }) => `${status} <@${user}>`).join("\n")}`; class PingInviteListCommand extends ButtonCommand { public async execute(interaction: ButtonInteraction) { - const inviteListChannel = await getChannel( - inviteListChannelId, - interaction - ); + const inviteListChannel = await getChannel(inviteListChannelId, interaction); if (inviteListChannel?.type !== ChannelType.GuildText) { throw new Error("The invite list channel is not a text channel."); } - requireInteractionMemberPermission( - PermissionFlagsBits.ManageRoles, - interaction - ); + requireInteractionMemberPermission(PermissionFlagsBits.ManageRoles, interaction); const users = await this.getPendingInviteUsers(); const attention = await getAttentionMessage(users); @@ -75,9 +60,7 @@ class PingInviteListCommand extends ButtonCommand { ${attention}`; - await interaction.channel - ?.send(alert) - .then((m) => setTimeout(() => m.delete(), 1 * HOURS)); + await interaction.channel?.send(alert).then((m) => setTimeout(() => m.delete(), 1 * HOURS)); await interaction.editReply("The invite list has been notified."); } @@ -89,6 +72,4 @@ ${attention}`; } } -export const pingInviteListButtonCommand = new PingInviteListCommand( - "pingInviteList" -); +export const pingInviteListButtonCommand = new PingInviteListCommand("pingInviteList"); diff --git a/src/features/invite-list/remove-player-button-command.ts b/src/features/invite-list/remove-player-button-command.ts index bd5352d..4dbc171 100644 --- a/src/features/invite-list/remove-player-button-command.ts +++ b/src/features/invite-list/remove-player-button-command.ts @@ -21,6 +21,4 @@ class RemovePlayerInvite extends ButtonCommand { } } -export const removePlayerInviteButtonCommand = new RemovePlayerInvite( - "removePlayerInvite" -); +export const removePlayerInviteButtonCommand = new RemovePlayerInvite("removePlayerInvite"); diff --git a/src/features/invite-list/remove-subcommand.ts b/src/features/invite-list/remove-subcommand.ts index 81c790f..f13847e 100644 --- a/src/features/invite-list/remove-subcommand.ts +++ b/src/features/invite-list/remove-subcommand.ts @@ -36,10 +36,7 @@ class Remove extends Subcommand { public get command() { return super.command.addUserOption((o) => - o - .setName(Option.DiscordUser) - .setDescription("The Discord user to remove") - .setRequired(true) + o.setName(Option.DiscordUser).setDescription("The Discord user to remove").setRequired(true) ); } @@ -48,7 +45,4 @@ class Remove extends Subcommand { } } -export const removeSubcommand = new Remove( - "remove", - "Remove someone from the invite list." -); +export const removeSubcommand = new Remove("remove", "Remove someone from the invite list."); diff --git a/src/features/invite-list/update-invite-action.ts b/src/features/invite-list/update-invite-action.ts index 582c6b5..bad02eb 100644 --- a/src/features/invite-list/update-invite-action.ts +++ b/src/features/invite-list/update-invite-action.ts @@ -15,10 +15,7 @@ import { dataSource } from "../../db/data-source"; import { Name } from "../../db/instructions"; import { InviteSimple } from "../../db/invite-simple"; import { InstructionsReadyAction } from "../../shared/action/instructions-ready-action"; -import { - readyActionExecutor, - ReadyActionExecutorOptions, -} from "../../shared/action/ready-action"; +import { readyActionExecutor, ReadyActionExecutorOptions } from "../../shared/action/ready-action"; import { addAltInviteButtonCommand, addPlayerInviteButtonCommand, @@ -31,10 +28,8 @@ import { removeSubcommand } from "./remove-subcommand"; import { pingInviteListButtonCommand } from "./ping-invite-list-button-command"; import { cleanupInvitesCommand } from "./cleanup-invites-command"; -export const updateInviteListInfo = ( - client: Client, - options?: ReadyActionExecutorOptions -) => readyActionExecutor(new UpdateInviteListInfoAction(client), options); +export const updateInviteListInfo = (client: Client, options?: ReadyActionExecutorOptions) => + readyActionExecutor(new UpdateInviteListInfoAction(client), options); export declare type Members = Collection | undefined; diff --git a/src/features/invite-list/util.ts b/src/features/invite-list/util.ts index 438bc13..0dbeed1 100644 --- a/src/features/invite-list/util.ts +++ b/src/features/invite-list/util.ts @@ -2,9 +2,7 @@ import { dataSource } from "../../db/data-source"; import { InviteSimple } from "../../db/invite-simple"; export const checkInvite = async (discordId: string) => { - const invite = await dataSource - .getRepository(InviteSimple) - .findOneBy({ discordId }); + const invite = await dataSource.getRepository(InviteSimple).findOneBy({ discordId }); if (invite) { throw new Error(`<@${discordId}> is already being tracked.`); } diff --git a/src/features/jewelry-request-info/crafting-button-command.ts b/src/features/jewelry-request-info/crafting-button-command.ts index be43211..c4be89d 100644 --- a/src/features/jewelry-request-info/crafting-button-command.ts +++ b/src/features/jewelry-request-info/crafting-button-command.ts @@ -1,10 +1,7 @@ import { ButtonInteraction, CacheType, ChannelType } from "discord.js"; import { jewelerRoleId, jewelryChannelId } from "../../config"; import { ButtonCommand } from "../../shared/command/button-command"; -import { - getChannel, - requireInteractionMemberRole, -} from "../../shared/command/util"; +import { getChannel, requireInteractionMemberRole } from "../../shared/command/util"; class CraftingButtonCommand extends ButtonCommand { public async execute(interaction: ButtonInteraction) { @@ -16,10 +13,7 @@ class CraftingButtonCommand extends ButtonCommand { const users = [ ...new Set( messages - .filter( - (m) => - !(m.member?.roles.cache.has(jewelerRoleId) || m.member?.user.bot) - ) + .filter((m) => !(m.member?.roles.cache.has(jewelerRoleId) || m.member?.user.bot)) .map((r) => r.member?.user) .filter(Boolean) ), @@ -32,9 +26,7 @@ class CraftingButtonCommand extends ButtonCommand { return; } - await interaction.editReply(`**${ - interaction.member?.user - } is now handling jewelry requests!** + await interaction.editReply(`**${interaction.member?.user} is now handling jewelry requests!** Attn: ${users.map((u) => `${u}`).join(" ")}`); } diff --git a/src/features/jewelry-request-info/jewelry-cleanup-button-command.ts b/src/features/jewelry-request-info/jewelry-cleanup-button-command.ts index 2ee7864..b23c1aa 100644 --- a/src/features/jewelry-request-info/jewelry-cleanup-button-command.ts +++ b/src/features/jewelry-request-info/jewelry-cleanup-button-command.ts @@ -1,16 +1,7 @@ -import { - ButtonInteraction, - CacheType, - ChannelType, - Message, - User, -} from "discord.js"; +import { ButtonInteraction, CacheType, ChannelType, Message, User } from "discord.js"; import { jewelerRoleId, jewelryChannelId } from "../../config"; import { ButtonCommand } from "../../shared/command/button-command"; -import { - getChannel, - requireInteractionMemberRole, -} from "../../shared/command/util"; +import { getChannel, requireInteractionMemberRole } from "../../shared/command/util"; class JeweleryCleanupCommand extends ButtonCommand { public async execute(interaction: ButtonInteraction) { @@ -19,9 +10,7 @@ class JeweleryCleanupCommand extends ButtonCommand { const messages = await jewelryRequestsChannel.messages.fetch(); const nonJewelerMessagesMap = messages - .filter( - (m) => !(m.member?.roles.cache.has(jewelerRoleId) || m.member?.user.bot) - ) + .filter((m) => !(m.member?.roles.cache.has(jewelerRoleId) || m.member?.user.bot)) .reduce((map, message) => { const id = message.author.id; if (!map[id]) { @@ -56,9 +45,7 @@ ${messages.map((m) => this.getQuotedContent(m.content)).join("\n")}`); }); await interaction.editReply({ - content: `Removed stale jewelry requests from: ${Object.values( - nonJewelerMessagesMap - ) + content: `Removed stale jewelry requests from: ${Object.values(nonJewelerMessagesMap) .map(({ user }) => user) .map((u) => `${u}`) .join(" ")}`, @@ -85,6 +72,4 @@ ${messages.map((m) => this.getQuotedContent(m.content)).join("\n")}`); } } -export const jewelryCleanupButtonCommand = new JeweleryCleanupCommand( - "jewelryCleanup" -); +export const jewelryCleanupButtonCommand = new JeweleryCleanupCommand("jewelryCleanup"); diff --git a/src/features/jewelry-request-info/jewelry-services.ts b/src/features/jewelry-request-info/jewelry-services.ts index 2438e13..46dffe2 100644 --- a/src/features/jewelry-request-info/jewelry-services.ts +++ b/src/features/jewelry-request-info/jewelry-services.ts @@ -3,13 +3,10 @@ import { Icon, Service } from "../bank-request-info/types"; export const services: Service[] = [ { title: "Jewelry Spreadsheet", - inventoryUrl: "https://docs.google.com/spreadsheets/d/1_Wqh3A_0Wg0JN4Fbt06j51yUqUZVKcVDLbSzzJ9FI4k/edit?usp=sharing", + inventoryUrl: + "https://docs.google.com/spreadsheets/d/1_Wqh3A_0Wg0JN4Fbt06j51yUqUZVKcVDLbSzzJ9FI4k/edit?usp=sharing", icon: Icon.Jewelry, - requestFormats: [ - "Item name, Item count (List of materials provided, Total cost)", - ], - bullets: [ - "Include the total cost of the order in your request, per the spreadsheet", - ], + requestFormats: ["Item name, Item count (List of materials provided, Total cost)"], + bullets: ["Include the total cost of the order in your request, per the spreadsheet"], }, ]; diff --git a/src/features/jewelry-request-info/update-action.ts b/src/features/jewelry-request-info/update-action.ts index b31be46..0250d67 100644 --- a/src/features/jewelry-request-info/update-action.ts +++ b/src/features/jewelry-request-info/update-action.ts @@ -10,28 +10,20 @@ import { import { jewelryChannelId } from "../../config"; import { Name } from "../../db/instructions"; import { InstructionsReadyAction } from "../../shared/action/instructions-ready-action"; -import { - readyActionExecutor, - ReadyActionExecutorOptions, -} from "../../shared/action/ready-action"; +import { readyActionExecutor, ReadyActionExecutorOptions } from "../../shared/action/ready-action"; import { services } from "./jewelry-services"; import { jewelryCleanupButtonCommand } from "./jewelry-cleanup-button-command"; import { craftingButtonCommand } from "./crafting-button-command"; import { Icon } from "../bank-request-info/types"; -export const updateJewelryRequestInfo = ( - client: Client, - options?: ReadyActionExecutorOptions -) => readyActionExecutor(new UpdateJewelryRequestInfoAction(client), options); +export const updateJewelryRequestInfo = (client: Client, options?: ReadyActionExecutorOptions) => + readyActionExecutor(new UpdateJewelryRequestInfoAction(client), options); class UpdateJewelryRequestInfoAction extends InstructionsReadyAction { public async execute() { await this.createOrUpdateInstructions( { - embeds: [ - await this.getInstructionsEmbed(), - ...(await this.getServicesEmbeds()), - ], + embeds: [await this.getInstructionsEmbed(), ...(await this.getServicesEmbeds())], components: [await this.getButtons()], }, Name.JewelryRequestInstructions @@ -67,9 +59,7 @@ class UpdateJewelryRequestInfoAction extends InstructionsReadyAction { return services.map( ({ title, icon, requestFormats, inventoryUrl, bullets }) => new EmbedBuilder({ - title: `${icon} ${inventoryUrl ? "__" : ""}${title}${ - inventoryUrl ? "__" : "" - }`, + title: `${icon} ${inventoryUrl ? "__" : ""}${title}${inventoryUrl ? "__" : ""}`, url: inventoryUrl, footer: { text: requestFormats.map((r) => `${Icon.Request} ${r}`).join("\n"), diff --git a/src/features/raid-bots/bind-subcommand.ts b/src/features/raid-bots/bind-subcommand.ts index dceeaee..b38dafa 100644 --- a/src/features/raid-bots/bind-subcommand.ts +++ b/src/features/raid-bots/bind-subcommand.ts @@ -18,14 +18,8 @@ export class BindSubcommand extends Subcommand { } public async execute(interaction: CommandInteraction) { - const name = this.getRequiredOptionValue( - Option.Name, - interaction - ) as string; - const bindLocation = this.getOptionValue( - Option.BindLocation, - interaction - ) as string; + const name = this.getRequiredOptionValue(Option.Name, interaction) as string; + const bindLocation = this.getOptionValue(Option.BindLocation, interaction) as string; try { this.publicAccountService.updateBotRowDetails(name, { @@ -72,7 +66,4 @@ export class BindSubcommand extends Subcommand { } } -export const bindSubCommand = new BindSubcommand( - "bind", - "Update a bot's bound location" -); +export const bindSubCommand = new BindSubcommand("bind", "Update a bot's bound location"); diff --git a/src/features/raid-bots/bot-embed.ts b/src/features/raid-bots/bot-embed.ts index 1a47040..f4b7f9b 100644 --- a/src/features/raid-bots/bot-embed.ts +++ b/src/features/raid-bots/bot-embed.ts @@ -1,16 +1,13 @@ -import { APIEmbed, EmbedBuilder, Utils } from "discord.js"; -import { botEmbedChannelId, knightRoleId, raiderRoleId } from "../../config"; +import { EmbedBuilder } from "discord.js"; +import { botEmbedChannelId, raiderRoleId } from "../../config"; import { Name } from "../../db/instructions"; import { Bot } from "../../services/bot/public-accounts-sheet"; import { InstructionsReadyAction } from "../../shared/action/instructions-ready-action-2"; -import { - Options, - readyActionExecutor, -} from "../../shared/action/ready-action-2"; +import { Options, readyActionExecutor } from "../../shared/action/ready-action-2"; import { PublicAccountsFactory } from "../../services/bot/bot-factory"; import moment from "moment"; import { getClassAbreviation } from "../../shared/classes"; -import { log } from "../../shared/logger" +import { log } from "../../shared/logger"; export const botEmbedInstructions = new InstructionsReadyAction( Name.BotStatusEmbed, @@ -23,15 +20,16 @@ export const updateBotEmbed = (options: Options) => { }, options); }; - const truncate = (str: string, maxLength: number) => { - if (str.length <= maxLength) return str; - return str.slice(0, maxLength - 3) + '...'; -} +const truncate = (str: string, maxLength: number) => { + if (str.length <= maxLength) { + return str; + } + return str.slice(0, maxLength - 3) + "..."; +}; export const refreshBotEmbed = async () => { const publicAccounts = PublicAccountsFactory.getService(); let botString = ""; const botMessages: string[] = []; - const start = moment.now(); const bots = await publicAccounts.getBots(); bots.forEach((bot: Bot) => { @@ -48,9 +46,9 @@ export const refreshBotEmbed = async () => { } const botRow = `${icon} ${pilotName ? "~~" : ""} ${bot.name} (${ bot.level - } ${getClassAbreviation(bot.class)}) - ${bot.location} ${ - pilotName ? "~~" : "" - } ${pilotName ? "- " + pilotName : ""}\u200B\n`; + } ${getClassAbreviation(bot.class)}) - ${bot.location} ${pilotName ? "~~" : ""} ${ + pilotName ? "- " + pilotName : "" + }\u200B\n`; if (botString.length + botRow.length > 3000) { botMessages.push(botString); botString = ""; @@ -64,10 +62,7 @@ export const refreshBotEmbed = async () => { .createOrUpdateInstructions({ embeds: botMessages.map((message: string, idx: number) => { return new EmbedBuilder({ - title: - idx === 0 - ? `Castle bots - last updated ${moment().toLocaleString()}` - : "", + title: idx === 0 ? `Castle bots - last updated ${moment().toLocaleString()}` : "", description: message, }); }), diff --git a/src/features/raid-bots/cleanup-subcommand.ts b/src/features/raid-bots/cleanup-subcommand.ts index 0856300..e1fc8c0 100644 --- a/src/features/raid-bots/cleanup-subcommand.ts +++ b/src/features/raid-bots/cleanup-subcommand.ts @@ -27,17 +27,10 @@ export class CleanupSubcommand extends Subcommand { if (!thread) { throw new Error(`Could not locate bot request thread.`); } - const hours = this.getRequiredOptionValue( - Option.Hours, - interaction - ) as number; - const cleanupCount = await this.publicAccountService.cleanupCheckouts( - hours - ); + const hours = this.getRequiredOptionValue(Option.Hours, interaction) as number; + const cleanupCount = await this.publicAccountService.cleanupCheckouts(hours); if (hours) { - await interaction.editReply( - `Checkouts older than ${hours} hour(s) have been cleaned up` - ); + await interaction.editReply(`Checkouts older than ${hours} hour(s) have been cleaned up`); const logMsg = await thread.send("OK"); logMsg.edit( `✅ ${interaction.user} ran the bot cleanup command: ${hours} hour(s) cleaned up, ${cleanupCount} bot(s) auto-parked` @@ -62,9 +55,7 @@ export class CleanupSubcommand extends Subcommand { public getOptionAutocomplete( option: string, interaction: AutocompleteInteraction - ): Promise< - ApplicationCommandOptionChoiceData[] | undefined - > { + ): Promise[] | undefined> { throw new Error("Method not implemented."); } } diff --git a/src/features/raid-bots/command.ts b/src/features/raid-bots/command.ts index da26e8e..9a27698 100644 --- a/src/features/raid-bots/command.ts +++ b/src/features/raid-bots/command.ts @@ -1,20 +1,16 @@ import { Command } from "../../shared/command/command"; import { requestSubcommand } from "./request-subcommand"; import { parkSubCommand } from "./park-subcommand"; -import { requestClassSubcommand } from "./requestclass-subcommand" +import { requestClassSubcommand } from "./requestclass-subcommand"; import { bindSubCommand } from "./bind-subcommand"; import { cleanupSubCommand } from "./cleanup-subcommand"; import { requestZoneSubcommand } from "./requestzone-subcommand"; -export const botCommand = new Command( - "bot", - "Retrieve information about bots.", - [ - requestSubcommand, - requestClassSubcommand, - requestZoneSubcommand, - parkSubCommand, - bindSubCommand, - cleanupSubCommand, - ] -); +export const botCommand = new Command("bot", "Retrieve information about bots.", [ + requestSubcommand, + requestClassSubcommand, + requestZoneSubcommand, + parkSubCommand, + bindSubCommand, + cleanupSubCommand, +]); diff --git a/src/features/raid-bots/park-bot-button-command.ts b/src/features/raid-bots/park-bot-button-command.ts index 288cf7a..1f86b2e 100644 --- a/src/features/raid-bots/park-bot-button-command.ts +++ b/src/features/raid-bots/park-bot-button-command.ts @@ -1,66 +1,44 @@ -import { - ButtonBuilder, - ButtonComponent, - ButtonInteraction, - ButtonStyle, - CacheType, - } from "discord.js"; - import { ButtonCommand } from "../../shared/command/button-command"; - import { bot } from "@prisma/client"; - import { knightRoleId, raiderRoleId } from "../../config"; - import { getClassAbreviation } from "../../shared/classes"; - import { PublicAccountsFactory } from "../../services/bot/bot-factory"; - import { BOT_SPREADSHEET_COLUMNS } from "../../services/sheet-updater/public-sheet"; - import { log } from "../../shared/logger"; - - export class ParkBotButtonCommand extends ButtonCommand { - constructor(name: string) { - super(name); - } +import { ButtonBuilder, ButtonInteraction, ButtonStyle, CacheType } from "discord.js"; +import { ButtonCommand } from "../../shared/command/button-command"; +import { bot } from "@prisma/client"; +import { PublicAccountsFactory } from "../../services/bot/bot-factory"; +import { BOT_SPREADSHEET_COLUMNS } from "../../services/sheet-updater/public-sheet"; +import { log } from "../../shared/logger"; - public async execute( - interaction: ButtonInteraction - ): Promise { - - interaction.editReply({ - content: "Checking permissions", - }); - - const name = interaction.customId.split("_")[1]; - const guildUser = await interaction.guild?.members.fetch( - interaction.user.id - ); - log(`${guildUser?.nickname || guildUser?.user.username} clicked bot park button for ${name}`); - - try { - const parkDetails = { - [BOT_SPREADSHEET_COLUMNS.CurrentPilot]: "", - [BOT_SPREADSHEET_COLUMNS.CheckoutTime]: "", - [BOT_SPREADSHEET_COLUMNS.CurrentLocation]: undefined, - }; - - await PublicAccountsFactory.getService().updateBotRowDetails(name, parkDetails); - await interaction.editReply(`${name} was released in its previous location`); - - - } catch (error) { - await interaction.editReply(`Failed to move bot: ${error}`); - } - - } - - public getButtonBuilder(bot: bot): ButtonBuilder { - return new ButtonBuilder() - .setLabel( - `Park ${bot.name} at ${bot.location}` - ) - .setCustomId(this.customId) - .setStyle(ButtonStyle.Success); +export class ParkBotButtonCommand extends ButtonCommand { + constructor(name: string) { + super(name); + } + + public async execute(interaction: ButtonInteraction): Promise { + interaction.editReply({ + content: "Checking permissions", + }); + + const name = interaction.customId.split("_")[1]; + const guildUser = await interaction.guild?.members.fetch(interaction.user.id); + log(`${guildUser?.nickname || guildUser?.user.username} clicked bot park button for ${name}`); + + try { + const parkDetails = { + [BOT_SPREADSHEET_COLUMNS.CurrentPilot]: "", + [BOT_SPREADSHEET_COLUMNS.CheckoutTime]: "", + [BOT_SPREADSHEET_COLUMNS.CurrentLocation]: undefined, + }; + + await PublicAccountsFactory.getService().updateBotRowDetails(name, parkDetails); + await interaction.editReply(`${name} was released in its previous location`); + } catch (error) { + await interaction.editReply(`Failed to move bot: ${error}`); } + } + public getButtonBuilder(bot: bot): ButtonBuilder { + return new ButtonBuilder() + .setLabel(`Park ${bot.name} at ${bot.location}`) + .setCustomId(this.customId) + .setStyle(ButtonStyle.Success); } - - export const parkBotButtonCommand = new ParkBotButtonCommand( - "parkbot" - ); - \ No newline at end of file +} + +export const parkBotButtonCommand = new ParkBotButtonCommand("parkbot"); diff --git a/src/features/raid-bots/park-subcommand.ts b/src/features/raid-bots/park-subcommand.ts index 528a10a..f102cec 100644 --- a/src/features/raid-bots/park-subcommand.ts +++ b/src/features/raid-bots/park-subcommand.ts @@ -4,7 +4,7 @@ import { IPublicAccountService } from "../../services/bot/public-accounts.i"; import { LocationService } from "../../services/location"; import { PublicAccountsFactory } from "../../services/bot/bot-factory"; import { BOT_SPREADSHEET_COLUMNS } from "../../services/sheet-updater/public-sheet"; -import { log } from "../../shared/logger" +import { log } from "../../shared/logger"; export enum Option { Name = "name", @@ -19,14 +19,8 @@ export class ParkSubcommand extends Subcommand { } public async execute(interaction: CommandInteraction) { - const name = this.getRequiredOptionValue( - Option.Name, - interaction - ) as string; - const location = this.getOptionValue( - Option.Location, - interaction - ) as string; + const name = this.getRequiredOptionValue(Option.Name, interaction) as string; + const location = this.getOptionValue(Option.Location, interaction) as string; try { const parkDetails = { @@ -37,17 +31,11 @@ export class ParkSubcommand extends Subcommand { await this.publicAccountService.updateBotRowDetails(name, parkDetails); if (location) { - await interaction.editReply( - `${name} was released and moved to ${location}` - ); + await interaction.editReply(`${name} was released and moved to ${location}`); } else { - await interaction.editReply( - `${name} was released in its previous location` - ); + await interaction.editReply(`${name} was released in its previous location`); } - const guildUser = await interaction.guild?.members.fetch( - interaction.user.id - ); + const guildUser = await interaction.guild?.members.fetch(interaction.user.id); log( `${guildUser?.nickname || guildUser?.user.username} parked ${name} ${ location ? `in ${location}` : "" diff --git a/src/features/raid-bots/request-subcommand.ts b/src/features/raid-bots/request-subcommand.ts index f7f7c5f..dc034ce 100644 --- a/src/features/raid-bots/request-subcommand.ts +++ b/src/features/raid-bots/request-subcommand.ts @@ -1,15 +1,6 @@ -import { - CacheType, - CommandInteraction, - GuildMemberRoleManager, - spoiler, -} from "discord.js"; +import { CacheType, CommandInteraction } from "discord.js"; import { Subcommand } from "../../shared/command/subcommand"; -import { accounts } from "../../services/accounts"; -import { raidBotInstructions } from "./update-bots"; -import moment from "moment"; import { PublicAccountsFactory } from "../../services/bot/bot-factory"; -import { BOT_SPREADSHEET_COLUMNS } from "../../services/sheet-updater/public-sheet"; import { IPublicAccountService } from "../../services/bot/public-accounts.i"; export enum Option { diff --git a/src/features/raid-bots/requestclass-subcommand.ts b/src/features/raid-bots/requestclass-subcommand.ts index c1517b7..d8798df 100644 --- a/src/features/raid-bots/requestclass-subcommand.ts +++ b/src/features/raid-bots/requestclass-subcommand.ts @@ -1,9 +1,4 @@ -import { - CacheType, - CommandInteraction, - GuildMemberRoleManager, - spoiler, -} from "discord.js"; +import { CacheType, CommandInteraction, GuildMemberRoleManager, spoiler } from "discord.js"; import { Subcommand } from "../../shared/command/subcommand"; import { accounts } from "../../services/accounts"; import { raidBotInstructions } from "./update-bots"; @@ -14,8 +9,7 @@ import { Mutex } from "async-mutex"; import { LocationService } from "../../services/location"; import { PublicAccountsFactory } from "../../services/bot/bot-factory"; import { BOT_SPREADSHEET_COLUMNS } from "../../services/sheet-updater/public-sheet"; -import { log } from "../../shared/logger" - +import { log } from "../../shared/logger"; export enum Option { Class = "class", @@ -31,13 +25,9 @@ export class RequestClassSubcommand extends Subcommand { } public async execute(interaction: CommandInteraction) { - const botClass = capitalize( - this.getOption(Option.Class, interaction)?.value as string - ); - const location = this.getOption(Option.Location, interaction) - ?.value as string; - const bindLocation = this.getOption(Option.BindLocation, interaction) - ?.value as string; + const botClass = capitalize(this.getOption(Option.Class, interaction)?.value as string); + const location = this.getOption(Option.Location, interaction)?.value as string; + const bindLocation = this.getOption(Option.BindLocation, interaction)?.value as string; const thread = await raidBotInstructions.getThread(); if (!thread) { throw new Error(`Could not locate bot request thread.`); @@ -48,9 +38,7 @@ export class RequestClassSubcommand extends Subcommand { const release = await this.mutex.acquire(); const publicAccounts = PublicAccountsFactory.getService(); - const guildUser = await interaction.guild?.members.fetch( - interaction.user.id - ); + const guildUser = await interaction.guild?.members.fetch(interaction.user.id); if (!guildUser) { throw new Error("Couldn't identify user requesting bot"); @@ -58,9 +46,9 @@ export class RequestClassSubcommand extends Subcommand { try { log( - `${ - guildUser.nickname || guildUser.user.username - } requested ${botClass} ${location ? `in ${location}` : ""}` + `${guildUser.nickname || guildUser.user.username} requested ${botClass} ${ + location ? `in ${location}` : "" + }` ); try { firstBot = await publicAccounts.getFirstAvailableBotByClass( @@ -71,9 +59,7 @@ export class RequestClassSubcommand extends Subcommand { ); } catch (err) { status = "❌ Denied"; - await interaction.editReply( - `No bot was found matching the provided criteria.` - ); + await interaction.editReply(`No bot was found matching the provided criteria.`); const message = await thread.send("OK"); let response = `${status} ${interaction.user} access to the first available ${botClass}`; if (location) { @@ -108,9 +94,7 @@ Please use \`/bot park \` when you are finished [BOT_SPREADSHEET_COLUMNS.CheckoutTime]: moment().toString(), }); } catch (err) { - throw new Error( - "Failed to update public record, check the configuration" - ); + throw new Error("Failed to update public record, check the configuration"); } } catch (err) { status = "❌ Denied"; diff --git a/src/features/raid-bots/requestzone-subcommand.ts b/src/features/raid-bots/requestzone-subcommand.ts index 1350333..789ea0f 100644 --- a/src/features/raid-bots/requestzone-subcommand.ts +++ b/src/features/raid-bots/requestzone-subcommand.ts @@ -1,20 +1,13 @@ -import { - CacheType, - CommandInteraction, - GuildMemberRoleManager, - spoiler, -} from "discord.js"; +import { CacheType, CommandInteraction, GuildMemberRoleManager, spoiler } from "discord.js"; import { Subcommand } from "../../shared/command/subcommand"; import { accounts } from "../../services/accounts"; import { raidBotInstructions } from "./update-bots"; import moment from "moment"; -import { Class } from "../../shared/classes"; -import { capitalize } from "../../shared/util"; import { Mutex } from "async-mutex"; import { LocationService } from "../../services/location"; import { PublicAccountsFactory } from "../../services/bot/bot-factory"; import { BOT_SPREADSHEET_COLUMNS } from "../../services/sheet-updater/public-sheet"; -import { log } from "../../shared/logger" +import { log } from "../../shared/logger"; export enum Option { Location = "location", @@ -28,8 +21,7 @@ export class RequestZoneSubcommand extends Subcommand { } public async execute(interaction: CommandInteraction) { - const location = this.getOption(Option.Location, interaction) - ?.value as string; + const location = this.getOption(Option.Location, interaction)?.value as string; const thread = await raidBotInstructions.getThread(); if (!thread) { throw new Error(`Could not locate bot request thread.`); @@ -40,20 +32,14 @@ export class RequestZoneSubcommand extends Subcommand { const release = await this.mutex.acquire(); const publicAccounts = PublicAccountsFactory.getService(); - const guildUser = await interaction.guild?.members.fetch( - interaction.user.id - ); + const guildUser = await interaction.guild?.members.fetch(interaction.user.id); if (!guildUser) { throw new Error("Couldn't identify user requesting bot"); } try { - log( - `${ - guildUser.nickname || guildUser.user.username - } requested anything in ${location}` - ); + log(`${guildUser.nickname || guildUser.user.username} requested anything in ${location}`); try { firstBot = await publicAccounts.getFirstAvailableBotByLocation( location, @@ -61,9 +47,7 @@ export class RequestZoneSubcommand extends Subcommand { ); } catch (err) { status = "❌ Denied"; - await interaction.editReply( - `No bot was found matching the provided criteria.` - ); + await interaction.editReply(`No bot was found matching the provided criteria.`); const message = await thread.send("OK"); let response = `${status} ${interaction.user} access to the first available bot at ${location}`; response += `. (${err})`; @@ -95,9 +79,7 @@ Please use \`/bot park \` when you are finished [BOT_SPREADSHEET_COLUMNS.CheckoutTime]: moment().toString(), }); } catch (err) { - throw new Error( - "Failed to update public record, check the configuration" - ); + throw new Error("Failed to update public record, check the configuration"); } } catch (err) { status = "❌ Denied"; diff --git a/src/features/raid-bots/update-bots.ts b/src/features/raid-bots/update-bots.ts index b9bd4a4..7e48224 100644 --- a/src/features/raid-bots/update-bots.ts +++ b/src/features/raid-bots/update-bots.ts @@ -1,19 +1,8 @@ import { EmbedBuilder } from "discord.js"; -import { - bankOfficeChannelId, - bankerRoleId, - clientId, - guardOfficeChannelId, - guardRoleId, - raidBotsChannelId, - raiderRoleId, -} from "../../config"; +import { clientId, guardOfficeChannelId, guardRoleId, raidBotsChannelId } from "../../config"; import { Name } from "../../db/instructions"; import { accounts } from "../../services/accounts"; -import { - Options, - readyActionExecutor, -} from "../../shared/action/ready-action-2"; +import { Options, readyActionExecutor } from "../../shared/action/ready-action-2"; import { InstructionsReadyAction } from "../../shared/action/instructions-ready-action-2"; import { sortBy } from "lodash"; import { checkGoogleCredentials } from "../../services/gdrive"; @@ -34,12 +23,6 @@ export const updateRaidBotsInfo = (options: Options) => ); return; } - const raiderAccounts = await accounts.getAccountsForRole(raiderRoleId); - const sorted = sortBy( - raiderAccounts, - (b) => b.purpose, - (b) => b.characters - ); await raidBotInstructions.createOrUpdateInstructions({ embeds: [ new EmbedBuilder({ diff --git a/src/features/raid-schedule-info/event-renderer.ts b/src/features/raid-schedule-info/event-renderer.ts index c8c1661..3032f57 100644 --- a/src/features/raid-schedule-info/event-renderer.ts +++ b/src/features/raid-schedule-info/event-renderer.ts @@ -1,6 +1,5 @@ import { GuildScheduledEvent } from "discord.js"; import { HOURS } from "../../shared/time"; -import { compactDescription } from "../../shared/util"; export class EventRenderer { public constructor( @@ -15,9 +14,7 @@ ${this.date}${this.countdown}${this.description}`; private get countdown() { return this.within24Hours(this.data.scheduledStartTimestamp || 0) - ? ` ()` + ? ` ()` : ""; } @@ -57,14 +54,5 @@ ${this.date}${this.countdown}${this.description}`; return ""; } return `\n([more info](${this.data.url}))`; - // const compact = compactDescription( - // this.data.description, - // this.descriptionLength - //); - //let moreInfo = ""; - //if (compact.length < this.data.description.length) { - // moreInfo = ` ([more info](${this.data.url}))`; - //} - //return `\n${compact}${moreInfo}`; } } diff --git a/src/features/raid-schedule-info/raid-started.ts b/src/features/raid-schedule-info/raid-started.ts index 13cd5cf..aea43bb 100644 --- a/src/features/raid-schedule-info/raid-started.ts +++ b/src/features/raid-schedule-info/raid-started.ts @@ -1,16 +1,8 @@ -import { - Client, - GuildScheduledEvent, - EmbedBuilder, - ChannelType, -} from "discord.js"; +import { Client, GuildScheduledEvent, EmbedBuilder, ChannelType } from "discord.js"; import { startedRaidsDumpThreadId } from "../../config"; import { EventRenderer } from "./event-renderer"; -export const recordRaidStarted = async ( - client: Client, - raid: GuildScheduledEvent -) => { +export const recordRaidStarted = async (client: Client, raid: GuildScheduledEvent) => { const channel = await client.channels.fetch(startedRaidsDumpThreadId); if (!channel) { throw new Error("Could not locate the started raids dump channel"); diff --git a/src/features/raid-schedule-info/update-action.ts b/src/features/raid-schedule-info/update-action.ts index ca95370..d2fc1c2 100644 --- a/src/features/raid-schedule-info/update-action.ts +++ b/src/features/raid-schedule-info/update-action.ts @@ -7,24 +7,15 @@ import { PermissionFlagsBits, } from "discord.js"; import { getGuild } from "../.."; -import { - raiderRoleId, - membersAndAlliesRoleId, - raidScheduleChannelId -} from "../../config"; +import { raiderRoleId, membersAndAlliesRoleId, raidScheduleChannelId } from "../../config"; import { Name } from "../../db/instructions"; import { InstructionsReadyAction } from "../../shared/action/instructions-ready-action"; -import { - readyActionExecutor, - ReadyActionExecutorOptions, -} from "../../shared/action/ready-action"; +import { readyActionExecutor, ReadyActionExecutorOptions } from "../../shared/action/ready-action"; import { DAYS } from "../../shared/time"; import { EventRenderer } from "./event-renderer"; -export const updateRaidSchedule = ( - client: Client, - options?: ReadyActionExecutorOptions -) => readyActionExecutor(new UpdateRaidScheduleInfoAction(client), options); +export const updateRaidSchedule = (client: Client, options?: ReadyActionExecutorOptions) => + readyActionExecutor(new UpdateRaidScheduleInfoAction(client), options); class UpdateRaidScheduleInfoAction extends InstructionsReadyAction { public async execute() { @@ -67,7 +58,6 @@ ${events.map((e) => e.toString()).join("\n\n")}` if (!membersRole) { throw new Error("Could not locate the members role"); } - const nextWeek = Date.now() + 7 * DAYS; @@ -75,25 +65,16 @@ ${events.map((e) => e.toString()).join("\n\n")}` .filter( (e) => e.channel?.type != ChannelType.GuildVoice || - e.channel?.type === ChannelType.GuildVoice && - !!e.scheduledStartTimestamp && - [ - GuildScheduledEventStatus.Scheduled, - GuildScheduledEventStatus.Active, - ].includes(e.status) && ( - e.channel - .permissionsFor(raiderRole) - .has(PermissionFlagsBits.ViewChannel) || - e.channel - .permissionsFor(membersRole) - .has(PermissionFlagsBits.ViewChannel) - ) && - e.scheduledStartTimestamp <= nextWeek // Added filter condition - ) - .sort( - (a, b) => - (a.scheduledStartTimestamp || 0) - (b.scheduledStartTimestamp || 0) + (e.channel?.type === ChannelType.GuildVoice && + !!e.scheduledStartTimestamp && + [GuildScheduledEventStatus.Scheduled, GuildScheduledEventStatus.Active].includes( + e.status + ) && + (e.channel.permissionsFor(raiderRole).has(PermissionFlagsBits.ViewChannel) || + e.channel.permissionsFor(membersRole).has(PermissionFlagsBits.ViewChannel)) && + e.scheduledStartTimestamp <= nextWeek) // Added filter condition ) + .sort((a, b) => (a.scheduledStartTimestamp || 0) - (b.scheduledStartTimestamp || 0)) .map((e) => new EventRenderer(e, 100)) .slice(0, 12); } diff --git a/src/features/raider-enlistment/join-reinforcements-button-command.ts b/src/features/raider-enlistment/join-reinforcements-button-command.ts index 2beb9ff..8d7fc2c 100644 --- a/src/features/raider-enlistment/join-reinforcements-button-command.ts +++ b/src/features/raider-enlistment/join-reinforcements-button-command.ts @@ -1,8 +1,4 @@ -import { - ButtonInteraction, - CacheType, - GuildMemberRoleManager, -} from "discord.js"; +import { ButtonInteraction, CacheType, GuildMemberRoleManager } from "discord.js"; import { reinforcementsRoleId } from "../../config"; import { ButtonCommand } from "../../shared/command/button-command"; @@ -26,6 +22,4 @@ class JoinReinforcementsButton extends ButtonCommand { } } -export const joinReinforcementsButtonCommand = new JoinReinforcementsButton( - "joinReinforcements" -); +export const joinReinforcementsButtonCommand = new JoinReinforcementsButton("joinReinforcements"); diff --git a/src/features/raider-enlistment/leave-reinforcements-button-command.ts b/src/features/raider-enlistment/leave-reinforcements-button-command.ts index c969940..f5aee40 100644 --- a/src/features/raider-enlistment/leave-reinforcements-button-command.ts +++ b/src/features/raider-enlistment/leave-reinforcements-button-command.ts @@ -1,8 +1,4 @@ -import { - ButtonInteraction, - CacheType, - GuildMemberRoleManager, -} from "discord.js"; +import { ButtonInteraction, CacheType, GuildMemberRoleManager } from "discord.js"; import { reinforcementsRoleId } from "../../config"; import { ButtonCommand } from "../../shared/command/button-command"; diff --git a/src/features/raider-enlistment/raider-enlisted-reaction.ts b/src/features/raider-enlistment/raider-enlisted-reaction.ts index 26a5cba..cfda5a9 100644 --- a/src/features/raider-enlistment/raider-enlisted-reaction.ts +++ b/src/features/raider-enlistment/raider-enlisted-reaction.ts @@ -1,9 +1,4 @@ -import { - MessageReaction, - PartialMessageReaction, - PartialUser, - User, -} from "discord.js"; +import { MessageReaction, PartialMessageReaction, PartialUser, User } from "discord.js"; import { inactiveRaiderRoleId, knightRoleId, @@ -11,10 +6,7 @@ import { raiderEnlistmentChannelId, raiderRoleId, } from "../../config"; -import { - ReactionAction, - reactionActionExecutor, -} from "../../shared/action/reaction-action"; +import { ReactionAction, reactionActionExecutor } from "../../shared/action/reaction-action"; export const tryRaiderEnlistedReactionAction = ( reaction: MessageReaction | PartialMessageReaction, @@ -35,12 +27,7 @@ class RaiderEnlistedReactionAction extends ReactionAction { // authorize user const reactor = await this.members?.fetch(this.user.id); - if ( - !( - reactor?.roles.cache.has(knightRoleId) || - reactor?.roles.cache.has(officerRoleId) - ) - ) { + if (!(reactor?.roles.cache.has(knightRoleId) || reactor?.roles.cache.has(officerRoleId))) { return; } @@ -67,9 +54,7 @@ class RaiderEnlistedReactionAction extends ReactionAction { }) ).values(), ]; - const newRaiderMessages = messages.filter( - (m) => m.author.id === newRaider.id - ); + const newRaiderMessages = messages.filter((m) => m.author.id === newRaider.id); const newRaiderMessagesIds = newRaiderMessages.map((m) => m.id); const repliesToNewRaiderMessages = messages.filter( (m) => @@ -80,11 +65,7 @@ class RaiderEnlistedReactionAction extends ReactionAction { // its a reply to a message that is queued to be deleted newRaiderMessagesIds.includes(m.reference.messageId) ); - newRaiderMessages - .filter((m) => m.embeds.length === 0) - .map((m) => m.delete()); - repliesToNewRaiderMessages - .filter((m) => m.embeds.length === 0) - .map((m) => m.delete()); + newRaiderMessages.filter((m) => m.embeds.length === 0).map((m) => m.delete()); + repliesToNewRaiderMessages.filter((m) => m.embeds.length === 0).map((m) => m.delete()); } } diff --git a/src/features/raider-enlistment/raider-enlisted.ts b/src/features/raider-enlistment/raider-enlisted.ts index 81e8d1f..45a101a 100644 --- a/src/features/raider-enlistment/raider-enlisted.ts +++ b/src/features/raider-enlistment/raider-enlisted.ts @@ -1,10 +1,7 @@ import { ChannelType, Client, GuildMember } from "discord.js"; import { raiderEnlistedThreadId } from "../../config"; -export const recordRaiderEnlisted = async ( - client: Client, - member: GuildMember -) => { +export const recordRaiderEnlisted = async (client: Client, member: GuildMember) => { const channel = await client.channels.fetch(raiderEnlistedThreadId); if (!channel) { throw new Error("Could not locate the raider enlisted dump channel"); diff --git a/src/features/raider-enlistment/update-raider-action.ts b/src/features/raider-enlistment/update-raider-action.ts index 83fba4b..a54d0c5 100644 --- a/src/features/raider-enlistment/update-raider-action.ts +++ b/src/features/raider-enlistment/update-raider-action.ts @@ -2,15 +2,10 @@ import { Client, Colors, EmbedBuilder } from "discord.js"; import { raiderEnlistmentChannelId, raiderRoleId } from "../../config"; import { Name } from "../../db/instructions"; import { InstructionsReadyAction } from "../../shared/action/instructions-ready-action"; -import { - readyActionExecutor, - ReadyActionExecutorOptions, -} from "../../shared/action/ready-action"; +import { readyActionExecutor, ReadyActionExecutorOptions } from "../../shared/action/ready-action"; -export const updateRaiderInfo = ( - client: Client, - options?: ReadyActionExecutorOptions -) => readyActionExecutor(new UpdateRaiderInfoAction(client), options); +export const updateRaiderInfo = (client: Client, options?: ReadyActionExecutorOptions) => + readyActionExecutor(new UpdateRaiderInfoAction(client), options); class UpdateRaiderInfoAction extends InstructionsReadyAction { public async execute(): Promise { diff --git a/src/features/raider-enlistment/update-reinforcement-action.ts b/src/features/raider-enlistment/update-reinforcement-action.ts index 3e276ef..49034c2 100644 --- a/src/features/raider-enlistment/update-reinforcement-action.ts +++ b/src/features/raider-enlistment/update-reinforcement-action.ts @@ -10,17 +10,12 @@ import { import { raiderEnlistmentChannelId, reinforcementsRoleId } from "../../config"; import { Name } from "../../db/instructions"; import { InstructionsReadyAction } from "../../shared/action/instructions-ready-action"; -import { - readyActionExecutor, - ReadyActionExecutorOptions, -} from "../../shared/action/ready-action"; +import { readyActionExecutor, ReadyActionExecutorOptions } from "../../shared/action/ready-action"; import { joinReinforcementsButtonCommand } from "./join-reinforcements-button-command"; import { leaveReinforcementsButtonCommand } from "./leave-reinforcements-button-command"; -export const updateReinforcementInfo = ( - client: Client, - options?: ReadyActionExecutorOptions -) => readyActionExecutor(new UpdateReinforcementsInfoAction(client), options); +export const updateReinforcementInfo = (client: Client, options?: ReadyActionExecutorOptions) => + readyActionExecutor(new UpdateReinforcementsInfoAction(client), options); class UpdateReinforcementsInfoAction extends InstructionsReadyAction { public async execute(): Promise { diff --git a/src/features/removed/guild-member-leave-listener.ts b/src/features/removed/guild-member-leave-listener.ts index ad941bd..3672893 100644 --- a/src/features/removed/guild-member-leave-listener.ts +++ b/src/features/removed/guild-member-leave-listener.ts @@ -2,9 +2,7 @@ import { ChannelType, GuildMember, PartialGuildMember } from "discord.js"; import moment from "moment"; import { membersAndAlliesRoleId, removedChannelId } from "../../config"; -export const guildMemberLeaveListener = async ( - member: GuildMember | PartialGuildMember -) => { +export const guildMemberLeaveListener = async (member: GuildMember | PartialGuildMember) => { // Verify they're a member if (!member.roles.cache.has(membersAndAlliesRoleId)) { return; diff --git a/src/features/threads/add-subcommand.ts b/src/features/threads/add-subcommand.ts index 042d311..22b1c9b 100644 --- a/src/features/threads/add-subcommand.ts +++ b/src/features/threads/add-subcommand.ts @@ -32,10 +32,7 @@ class Add extends Subcommand { public get command() { return super.command.addRoleOption((o) => - o - .setName(Option.RoleId) - .setDescription("The Discord role to add") - .setRequired(true) + o.setName(Option.RoleId).setDescription("The Discord role to add").setRequired(true) ); } @@ -44,7 +41,4 @@ class Add extends Subcommand { } } -export const addSubcommand = new Add( - "add", - "Add all members of a role to the thread." -); +export const addSubcommand = new Add("add", "Add all members of a role to the thread."); diff --git a/src/features/threads/command.ts b/src/features/threads/command.ts index 8414ec2..07ba407 100644 --- a/src/features/threads/command.ts +++ b/src/features/threads/command.ts @@ -2,8 +2,7 @@ import { Command } from "../../shared/command/command"; import { addSubcommand } from "./add-subcommand"; import { listSubcommand } from "./list-subcommand"; -export const threadUtilCommand = new Command( - "threadutil", - "Utilities for working with threads.", - [addSubcommand, listSubcommand] -); +export const threadUtilCommand = new Command("threadutil", "Utilities for working with threads.", [ + addSubcommand, + listSubcommand, +]); diff --git a/src/features/wakeup/setsong-subcommand.ts b/src/features/wakeup/setsong-subcommand.ts index 8540cf6..f3f5e6e 100644 --- a/src/features/wakeup/setsong-subcommand.ts +++ b/src/features/wakeup/setsong-subcommand.ts @@ -1,12 +1,5 @@ -import { - ApplicationCommandOptionChoiceData, - AutocompleteInteraction, - CacheType, - CommandInteraction, -} from "discord.js"; +import { ApplicationCommandOptionChoiceData, CacheType, CommandInteraction } from "discord.js"; import { Subcommand } from "../../shared/command/subcommand"; -import { IPublicAccountService } from "../../services/bot/public-accounts.i"; -import { PublicAccountsFactory } from "../../services/bot/bot-factory"; import { authorizeByMemberRoles } from "../../shared/command/util"; import { officerRoleId, knightRoleId } from "../../config"; import { redisClient } from "../../redis/client"; @@ -15,16 +8,12 @@ export enum SetSongOption { URL = "url", } export class SetSongSubcommand extends Subcommand { - constructor(name: string, description: string) { super(name, description); } public async execute(interaction: CommandInteraction) { - const URL = this.getRequiredOptionValue( - SetSongOption.URL, - interaction - ) as string; + const URL = this.getRequiredOptionValue(SetSongOption.URL, interaction) as string; try { authorizeByMemberRoles([officerRoleId, knightRoleId], interaction); @@ -46,17 +35,11 @@ export class SetSongSubcommand extends Subcommand { return command; } - public getOptionAutocomplete( - option: string, - interaction: AutocompleteInteraction - ): Promise< + public getOptionAutocomplete(): Promise< ApplicationCommandOptionChoiceData[] | undefined > { throw new Error("Method not implemented."); } } -export const setSongSubCommand = new SetSongSubcommand( - "setsong", - "Sets the wakeup song (be nice)" -); +export const setSongSubCommand = new SetSongSubcommand("setsong", "Sets the wakeup song (be nice)"); diff --git a/src/features/wakeup/wakeup-command.ts b/src/features/wakeup/wakeup-command.ts index cef4e54..4442f31 100644 --- a/src/features/wakeup/wakeup-command.ts +++ b/src/features/wakeup/wakeup-command.ts @@ -2,6 +2,7 @@ import { Command } from "../../shared/command/command"; import { setSongSubCommand } from "./setsong-subcommand"; import { wakeupTestSubCommand } from "./wakeuptest-command"; -export const wakeupCommand = new Command("wakeup", "Wakeup commands.", - [setSongSubCommand, - wakeupTestSubCommand]); +export const wakeupCommand = new Command("wakeup", "Wakeup commands.", [ + setSongSubCommand, + wakeupTestSubCommand, +]); diff --git a/src/features/wakeup/wakeup.service.i.ts b/src/features/wakeup/wakeup.service.i.ts index 2a168d1..7afa7d8 100644 --- a/src/features/wakeup/wakeup.service.i.ts +++ b/src/features/wakeup/wakeup.service.i.ts @@ -1,4 +1,3 @@ - export interface IWakeupService { runWakeup(batphoneMessageId: string): void; } diff --git a/src/features/wakeup/wakeup.service.ts b/src/features/wakeup/wakeup.service.ts index 324d633..c8ba4b4 100644 --- a/src/features/wakeup/wakeup.service.ts +++ b/src/features/wakeup/wakeup.service.ts @@ -1,6 +1,5 @@ import { VoiceChannel, Guild } from "discord.js"; import { - AudioResource, StreamType, VoiceConnectionStatus, createAudioPlayer, @@ -41,59 +40,56 @@ export class WakeupService implements IWakeupService { adapterCreator: this.wakeupChannel.guild.voiceAdapterCreator, }); - voiceConnection.on( - VoiceConnectionStatus.Ready, - async (oldState, newState) => { - try { - // First TTS - this.wakeupChannel?.send({ - content: textMessage, - tts: true, - }); - const player = createAudioPlayer(); + voiceConnection.on(VoiceConnectionStatus.Ready, async () => { + try { + // First TTS + this.wakeupChannel?.send({ + content: textMessage, + tts: true, + }); + const player = createAudioPlayer(); - player.on("error", (error) => { - console.error(`Error: ${error.message}`); - }); + player.on("error", (error) => { + console.error(`Error: ${error.message}`); + }); - // Play wakeup song - let songUrl = await redisClient.hGet("wakeup", "song"); - if (!songUrl) { - songUrl = "media/daddychill.mp3"; - } + // Play wakeup song + let songUrl = await redisClient.hGet("wakeup", "song"); + if (!songUrl) { + songUrl = "media/daddychill.mp3"; + } - console.log(`Wakeup song url ${songUrl}`); + console.log(`Wakeup song url ${songUrl}`); - let audio: string | internal.Readable | undefined = undefined; - if (songUrl.includes("youtu")) { - audio = ytdl(songUrl, { - filter: "audioonly", - }); - } else if (songUrl.includes(".mp3")) { - audio = songUrl; - } + let audio: string | internal.Readable | undefined = undefined; + if (songUrl.includes("youtu")) { + audio = ytdl(songUrl, { + filter: "audioonly", + }); + } else if (songUrl.includes(".mp3")) { + audio = songUrl; + } - if (!audio) { - throw new Error("No valid audio provided"); - } + if (!audio) { + throw new Error("No valid audio provided"); + } - const resource = createAudioResource(audio, { - inputType: StreamType.Arbitrary, - }); + const resource = createAudioResource(audio, { + inputType: StreamType.Arbitrary, + }); - voiceConnection.subscribe(player); - player.play(resource); + voiceConnection.subscribe(player); + player.play(resource); - setTimeout(async () => { - player.stop(true); - // Leave channel - voiceConnection.destroy(); - }, 60000); - } catch (error: unknown) { - console.log(`Error during wakeup: ${error}`); - } + setTimeout(async () => { + player.stop(true); + // Leave channel + voiceConnection.destroy(); + }, 60000); + } catch (error: unknown) { + console.log(`Error during wakeup: ${error}`); } - ); + }); } } } diff --git a/src/features/wakeup/wakeuptest-command.ts b/src/features/wakeup/wakeuptest-command.ts index bd5595f..cabe435 100644 --- a/src/features/wakeup/wakeuptest-command.ts +++ b/src/features/wakeup/wakeuptest-command.ts @@ -1,37 +1,20 @@ -import { - ApplicationCommandOptionChoiceData, - AutocompleteInteraction, - CacheType, - CommandInteraction, - ThreadMemberFlagsBitField, -} from "discord.js"; +import { ApplicationCommandOptionChoiceData, CacheType, CommandInteraction } from "discord.js"; import { Subcommand } from "../../shared/command/subcommand"; import { authorizeByMemberRoles } from "../../shared/command/util"; -import { - officerRoleId, - knightRoleId, - wakeupChannelId, - modRoleId, -} from "../../config"; +import { officerRoleId, knightRoleId, wakeupChannelId, modRoleId } from "../../config"; import { container } from "tsyringe"; import { WakeupService } from "./wakeup.service"; export class WakeupTestSubcommand extends Subcommand { - constructor(name: string, description: string) { super(name, description); } public async execute(interaction: CommandInteraction) { - authorizeByMemberRoles( - [officerRoleId, modRoleId, knightRoleId], - interaction - ); + authorizeByMemberRoles([officerRoleId, modRoleId, knightRoleId], interaction); if (wakeupChannelId) { const wakeupService = container.resolve(WakeupService); - await wakeupService.runWakeup( - `Batphone. ${interaction.user} sent a test command` - ); + await wakeupService.runWakeup(`Batphone. ${interaction.user} sent a test command`); await interaction.editReply("Test command executed"); } } @@ -40,17 +23,11 @@ export class WakeupTestSubcommand extends Subcommand { return super.command; } - public getOptionAutocomplete( - option: string, - interaction: AutocompleteInteraction - ): Promise< + public getOptionAutocomplete(): Promise< ApplicationCommandOptionChoiceData[] | undefined > { throw new Error("Method not implemented."); } } -export const wakeupTestSubCommand = new WakeupTestSubcommand( - "test", - "Test the wakeup" -); +export const wakeupTestSubCommand = new WakeupTestSubcommand("test", "Test the wakeup"); diff --git a/src/index.ts b/src/index.ts index 4c708a6..2ce2b69 100644 --- a/src/index.ts +++ b/src/index.ts @@ -17,7 +17,7 @@ import { updateRaidReport } from "./features/dkp-records/update/update-raid-repo import { guildMemberUpdateListener } from "./listeners/guild-member-update-listener"; import "reflect-metadata"; import { PrismaClient } from "@prisma/client"; -import { log } from "./shared/logger" +import { log } from "./shared/logger"; // Global https.globalAgent.maxSockets = 5; diff --git a/src/listeners/guild-scheduled-event-listener.ts b/src/listeners/guild-scheduled-event-listener.ts index 8b664c7..777b54a 100644 --- a/src/listeners/guild-scheduled-event-listener.ts +++ b/src/listeners/guild-scheduled-event-listener.ts @@ -20,10 +20,7 @@ export const guildScheduledEventStartedListener = async ( } // run when its completed or canceled if ( - [ - GuildScheduledEventStatus.Completed, - GuildScheduledEventStatus.Canceled, - ].includes(after.status) + [GuildScheduledEventStatus.Completed, GuildScheduledEventStatus.Canceled].includes(after.status) ) { recordRaidStarted(client, after); } diff --git a/src/listeners/interaction-create-listener.ts b/src/listeners/interaction-create-listener.ts index f24d439..d7665ef 100644 --- a/src/listeners/interaction-create-listener.ts +++ b/src/listeners/interaction-create-listener.ts @@ -1,10 +1,8 @@ import { CacheType, Interaction } from "discord.js"; import { getButton, getCommand } from "./register-commands"; -import { log } from "../shared/logger" +import { log } from "../shared/logger"; -export const interactionCreateListener = async ( - interaction: Interaction -) => { +export const interactionCreateListener = async (interaction: Interaction) => { if (interaction.isAutocomplete()) { getCommand(interaction)?.autocomplete(interaction).catch(console.error); return; diff --git a/src/listeners/message-reaction-add-listener.ts b/src/listeners/message-reaction-add-listener.ts index 47abf09..d130305 100644 --- a/src/listeners/message-reaction-add-listener.ts +++ b/src/listeners/message-reaction-add-listener.ts @@ -1,9 +1,4 @@ -import { - MessageReaction, - PartialMessageReaction, - PartialUser, - User, -} from "discord.js"; +import { MessageReaction, PartialMessageReaction, PartialUser, User } from "discord.js"; import { tryGatehouseReactionAction } from "../features/gatehouse-tags/reaction"; import { tryAuctionFinishedReactionAction } from "../features/auctions/auction-finished-reaction"; import { tryRaiderEnlistedReactionAction } from "../features/raider-enlistment/raider-enlisted-reaction"; diff --git a/src/listeners/ready-listener.ts b/src/listeners/ready-listener.ts index 2bceef5..7c3b197 100644 --- a/src/listeners/ready-listener.ts +++ b/src/listeners/ready-listener.ts @@ -6,10 +6,7 @@ import { updateRaiderInfo } from "../features/raider-enlistment/update-raider-ac import { updateReinforcementInfo } from "../features/raider-enlistment/update-reinforcement-action"; import { updateApplicationInfo as updateApplicationInfo } from "../features/applications/update-applications"; import { updateRaidSchedule } from "../features/raid-schedule-info/update-action"; -import { - updateGuardBotInfo, - updateRaidBotsInfo, -} from "../features/raid-bots/update-bots"; +import { updateGuardBotInfo, updateRaidBotsInfo } from "../features/raid-bots/update-bots"; import { HOURS } from "../shared/time"; import { updateBotEmbed } from "../features/raid-bots/bot-embed"; diff --git a/src/listeners/register-commands.ts b/src/listeners/register-commands.ts index baecf5c..2f4b509 100644 --- a/src/listeners/register-commands.ts +++ b/src/listeners/register-commands.ts @@ -7,7 +7,7 @@ import { CommandInteraction, } from "discord.js"; import { clientId, guildId, token } from "../config"; -import { applicationCommandButton } from "../features/applications/update-applications"; +import { applicationCommandButton } from "../features/applications"; import { auctionCommand } from "../features/auctions/command"; import { bankHourCommand } from "../features/bank-hours/command"; import { bankCleanupButtonCommand } from "../features/bank-request-info/bank-cleanup-button-command"; @@ -31,7 +31,7 @@ import { botCommand } from "../features/raid-bots/command"; import { batphoneCommand } from "../features/bp/bp-command"; import { wakeupCommand } from "../features/wakeup/wakeup-command"; import { requestBotButtonCommand } from "../features/bp/request-bot-button-command"; -import { parkBotButtonCommand } from "../features/raid-bots/park-bot-button-command" +import { parkBotButtonCommand } from "../features/raid-bots/park-bot-button-command"; const slashCommands = [ bankHourCommand, @@ -59,31 +59,23 @@ const buttonCommands = [ removePlayerInviteButtonCommand, applicationCommandButton, requestBotButtonCommand, - parkBotButtonCommand + parkBotButtonCommand, ]; export const getCommand = ( - interaction: - | CommandInteraction - | AutocompleteInteraction + interaction: CommandInteraction | AutocompleteInteraction ) => { const command = slashCommands.find((c) => c.name === interaction.commandName); if (!command) { - throw new Error( - `Could not find slash command **/${interaction.commandName}**` - ); + throw new Error(`Could not find slash command **/${interaction.commandName}**`); } return command; }; export const getButton = (interaction: ButtonInteraction) => { - const command = buttonCommands.find((c) => - interaction.customId.includes(c.customId) - ); + const command = buttonCommands.find((c) => interaction.customId.includes(c.customId)); if (!command) { - throw new Error( - `Could not find button command **${interaction.customId}**` - ); + throw new Error(`Could not find button command **${interaction.customId}**`); } return command; }; diff --git a/src/redis/client.ts b/src/redis/client.ts index f2711b7..bb4b624 100644 --- a/src/redis/client.ts +++ b/src/redis/client.ts @@ -6,9 +6,7 @@ export const redisChannels = { }; const onError = (err: Error) => - err instanceof SocketClosedUnexpectedlyError - ? null - : console.error("Redis client error", err); + err instanceof SocketClosedUnexpectedlyError ? null : console.error("Redis client error", err); export const redisClient = createClient({ url: REDIS_URL }); try { diff --git a/src/services/accounts.ts b/src/services/accounts.ts index fb0addd..4dabaa8 100644 --- a/src/services/accounts.ts +++ b/src/services/accounts.ts @@ -11,15 +11,12 @@ import { } from "../config"; import LRUCache from "lru-cache"; import { MINUTES } from "../shared/time"; -import { - ApplicationCommandOptionChoiceData, - GuildMemberRoleManager, -} from "discord.js"; -import { some, truncate } from "lodash"; +import { ApplicationCommandOptionChoiceData, GuildMemberRoleManager } from "discord.js"; +import { some } from "lodash"; import { checkGoogleCredentials } from "./gdrive"; import moment from "moment"; import { getClassAbreviation } from "../shared/classes"; -import { log } from "../shared/logger" +import { log } from "../shared/logger"; enum SPREADSHEET_COLUMNS { Characters = "Characters", @@ -118,14 +115,10 @@ const getAccounts = async () => { export const accounts = { getAccountsForRole: async (roleId: string): Promise => { const accounts = await getAccounts(); - return [...accounts.values()].filter((c) => - c.requiredRoles.map((r) => r.id).includes(roleId) - ); + return [...accounts.values()].filter((c) => c.requiredRoles.map((r) => r.id).includes(roleId)); }, - getOptions: async (): Promise< - ApplicationCommandOptionChoiceData[] - > => { + getOptions: async (): Promise[]> => { const accounts = await getAccounts(); return [...accounts.values()].map((c) => ({ name: `${c.characters} (${c.class})`, @@ -143,10 +136,7 @@ export const accounts = { return d.requiredRoles; }, - getAccount: async ( - name: string, - roles: GuildMemberRoleManager - ): Promise => { + getAccount: async (name: string, roles: GuildMemberRoleManager): Promise => { const accounts = await getAccounts(); let d = accounts.get(name.toLowerCase()); const toSentenceCase = (str: string) => { @@ -158,9 +148,7 @@ export const accounts = { throw new Error(`${name} is not a shared account`); } } - const hasRole = some( - d.requiredRoles.map((r) => r.id).map((id) => roles.cache.has(id)) - ); + const hasRole = some(d.requiredRoles.map((r) => r.id).map((id) => roles.cache.has(id))); if (!hasRole) { throw new Error(`You do not have the required role to access ${name}`); } diff --git a/src/services/betaDkpService.ts b/src/services/betaDkpService.ts index fd1926e..da3a0ff 100644 --- a/src/services/betaDkpService.ts +++ b/src/services/betaDkpService.ts @@ -22,10 +22,10 @@ client.interceptors.request.use((config) => { export const betaDkpService = { upsertRaidActivityType: async (name: string, defaultPayout: number) => { - const response = await client.post<{ id: number }>( - "/api/v1/raid-activity-type/upsert", - { name, defaultPayout } - ); + const response = await client.post<{ id: number }>("/api/v1/raid-activity-type/upsert", { + name, + defaultPayout, + }); return response.data.id; }, @@ -44,10 +44,7 @@ export const betaDkpService = { activity: { typeId, createdAt: raidTick.data.date, - payout: - raidTick.data.value === undefined - ? undefined - : Number(raidTick.data.value), + payout: raidTick.data.value === undefined ? undefined : Number(raidTick.data.value), note: raidTick.note, attendees: raidTick.data.attendees.map((name) => ({ characterName: name, diff --git a/src/services/bot/bot-prisma.ts b/src/services/bot/bot-prisma.ts index 021b3b2..f72e9c7 100644 --- a/src/services/bot/bot-prisma.ts +++ b/src/services/bot/bot-prisma.ts @@ -6,13 +6,10 @@ import { spoiler, ActionRowBuilder, MessageActionRowComponentBuilder, - ComponentType + ComponentType, } from "discord.js"; import { Moment } from "moment"; -import { - BOT_SPREADSHEET_COLUMNS, - PublicSheetService, -} from "../sheet-updater/public-sheet"; +import { BOT_SPREADSHEET_COLUMNS, PublicSheetService } from "../sheet-updater/public-sheet"; import { IPublicAccountService } from "./public-accounts.i"; import { bot, PrismaClient } from "@prisma/client"; import moment from "moment"; @@ -24,7 +21,7 @@ import { getMembers, prismaClient } from "../.."; import { refreshBotEmbed } from "../../features/raid-bots/bot-embed"; import { getClassAbreviation } from "../../shared/classes"; import { raidBotInstructions } from "../../features/raid-bots/update-bots"; -import { ParkBotButtonCommand } from "../../features/raid-bots/park-bot-button-command" +import { ParkBotButtonCommand } from "../../features/raid-bots/park-bot-button-command"; export class PrismaPublicAccounts implements IPublicAccountService { private prisma!: PrismaClient; @@ -43,9 +40,7 @@ export class PrismaPublicAccounts implements IPublicAccountService { await prismaClient.bot.deleteMany({}); for (const row of rows) { const time = moment(row[BOT_SPREADSHEET_COLUMNS.CheckoutTime]); - const roles = await accounts.getRolesForAccount( - row[BOT_SPREADSHEET_COLUMNS.Name] - ); + const roles = await accounts.getRolesForAccount(row[BOT_SPREADSHEET_COLUMNS.Name]); await prismaClient.bot.create({ data: { @@ -62,25 +57,24 @@ export class PrismaPublicAccounts implements IPublicAccountService { } } - async getBotParkButtonComponents (name: string) - { + async getBotParkButtonComponents(name: string) { const components: ActionRowBuilder[] = []; - let row = new ActionRowBuilder({ - type: ComponentType.ActionRow, - components: [], + const row = new ActionRowBuilder({ + type: ComponentType.ActionRow, + components: [], }); components.push(row); try { - let bot = await this.getBotByName(name); + const bot = await this.getBotByName(name); if (bot) { - row.addComponents(new ParkBotButtonCommand( - `parkbot_${name}` - ).getButtonBuilder(bot)); + row.addComponents(new ParkBotButtonCommand(`parkbot_${name}`).getButtonBuilder(bot)); } - } catch {} + } catch { + // Ignore bot lookup errors, continue without park button + } return components; - }; + } async doBotCheckout( name: string, @@ -111,48 +105,37 @@ Password: ${spoiler(details.password)} let components: ActionRowBuilder[] = []; if (currentPilot) { response += `**Please note that ${currentPilot} is marked as the pilot of ${foundBot} and you may not be able to log in. Your name will not be added as the botpilot in the public bot sheet! **\n\n`; - } - else - { + } else { components = await this.getBotParkButtonComponents(name); } response += `The credentials for ${foundBot} have been DM'd to you. Please remember to use \`/bot park\` when you are done!`; - await interaction.editReply({ content: response, - components: components + components: components, }); const logMsg = await thread.send("OK"); logMsg.edit(`${status} ${interaction.user} access to ${foundBot}`); if (await this.isBotPublic(foundBot)) { try { - const guildUser = await interaction.guild?.members.fetch( - interaction.user.id - ); + const guildUser = await interaction.guild?.members.fetch(interaction.user.id); log( - `${ - guildUser?.nickname || guildUser?.user.username - } requested ${name} and got ${details.characters} ${ - currentPilot ? `who is checked out by ${currentPilot}` : "" - }` + `${guildUser?.nickname || guildUser?.user.username} requested ${name} and got ${ + details.characters + } ${currentPilot ? `who is checked out by ${currentPilot}` : ""}` ); if (!currentPilot) { await this.updateBotRowDetails(foundBot, { [BOT_SPREADSHEET_COLUMNS.CurrentPilot]: - guildUser?.nickname || - guildUser?.user.username || - "UNKNOWN USER", + guildUser?.nickname || guildUser?.user.username || "UNKNOWN USER", [BOT_SPREADSHEET_COLUMNS.CheckoutTime]: moment().toString(), }); } } catch (err) { - throw new Error( - "Failed to update public record, check the configuration" - ); + throw new Error("Failed to update public record, check the configuration"); } } @@ -162,9 +145,7 @@ Password: ${spoiler(details.password)} const logMsg = await thread.send("OK"); logMsg.edit(`${status} ${interaction.user} access to ${name}.`); - await interaction.editReply( - `You do not have the correct permissions to access ${name}.` - ); + await interaction.editReply(`You do not have the correct permissions to access ${name}.`); } } @@ -177,13 +158,13 @@ Password: ${spoiler(details.password)} }, }, }); - + return bot; } async getCurrentBotPilot(botName: string): Promise { const bot = await this.getBotByName(botName); - + if (bot) { return bot.currentPilot; } @@ -203,12 +184,8 @@ Password: ${spoiler(details.password)} requiredRoles: { hasSome: Array.from(roles.valueOf().keys()), }, - ...(location - ? { location: { equals: location, mode: "insensitive" } } - : {}), - ...(bindLocation - ? { bindLocation: { equals: bindLocation, mode: "insensitive" } } - : {}), + ...(location ? { location: { equals: location, mode: "insensitive" } } : {}), + ...(bindLocation ? { bindLocation: { equals: bindLocation, mode: "insensitive" } } : {}), }, orderBy: { bindLocation: "desc", @@ -231,9 +208,7 @@ Password: ${spoiler(details.password)} return bot.name; } else { - throw new Error( - `Couldn't find an available ${botClass}${locationString}` - ); + throw new Error(`Couldn't find an available ${botClass}${locationString}`); } } @@ -254,9 +229,7 @@ Password: ${spoiler(details.password)} }, }); if (bot && bot.name) { - log( - `PublicAccountsPrisma - found bot ${bot.name} when looking for a bot in ${location}` - ); + log(`PublicAccountsPrisma - found bot ${bot.name} when looking for a bot in ${location}`); bot.currentPilot = "reserved"; @@ -347,27 +320,21 @@ Password: ${spoiler(details.password)} const pilot = botRowData[BOT_SPREADSHEET_COLUMNS.CurrentPilot]; const location = botRowData[BOT_SPREADSHEET_COLUMNS.CurrentLocation]; const bindLocation = botRowData[BOT_SPREADSHEET_COLUMNS.BindLocation]; - log(`bot-prisma: updateBotRowDetails for bot ${bot.name}. Pilot ${pilot}. location ${location} `) + log( + `bot-prisma: updateBotRowDetails for bot ${bot.name}. Pilot ${pilot}. location ${location} ` + ); if (checkoutTime !== undefined) { // Set time or clear if not undefined - bot.checkoutTime = botRowData[ - BOT_SPREADSHEET_COLUMNS.CheckoutTime - ] as string; + bot.checkoutTime = botRowData[BOT_SPREADSHEET_COLUMNS.CheckoutTime] as string; } if (pilot !== undefined) { - bot.currentPilot = botRowData[ - BOT_SPREADSHEET_COLUMNS.CurrentPilot - ] as string; + bot.currentPilot = botRowData[BOT_SPREADSHEET_COLUMNS.CurrentPilot] as string; } if (location !== undefined) { - bot.location = botRowData[ - BOT_SPREADSHEET_COLUMNS.CurrentLocation - ] as string; + bot.location = botRowData[BOT_SPREADSHEET_COLUMNS.CurrentLocation] as string; } if (bindLocation !== undefined) { - bot.bindLocation = botRowData[ - BOT_SPREADSHEET_COLUMNS.BindLocation - ] as string; + bot.bindLocation = botRowData[BOT_SPREADSHEET_COLUMNS.BindLocation] as string; } await prismaClient.bot.update({ where: { @@ -378,14 +345,10 @@ Password: ${spoiler(details.password)} refreshBotEmbed(); } - SheetPublicAccountService.getInstance().updateBotRowDetails( - botName, - botRowData - ); + SheetPublicAccountService.getInstance().updateBotRowDetails(botName, botRowData); } async cleanupCheckouts(hours: number): Promise { - const cleanupCount = 0; const cutoffTime = moment().subtract(hours, "hours"); const botsToPark: Bot[] = []; // Could probably use a DateTime lte comparison here but the schema @@ -445,17 +408,12 @@ If you are still piloting ${botName}, sorry for the inconvenience and please use }); // Update sheet - await SheetPublicAccountService.getInstance().updateBotRowDetails( - bot.name, - { - [BOT_SPREADSHEET_COLUMNS.CheckoutTime]: "", - [BOT_SPREADSHEET_COLUMNS.CurrentPilot]: "", - } - ); + await SheetPublicAccountService.getInstance().updateBotRowDetails(bot.name, { + [BOT_SPREADSHEET_COLUMNS.CheckoutTime]: "", + [BOT_SPREADSHEET_COLUMNS.CurrentPilot]: "", + }); - log( - `Auto-parked ${bot.name} and sent a DM to ${pilot.user.username}` - ); + log(`Auto-parked ${bot.name} and sent a DM to ${pilot.user.username}`); cleanupCount++; } @@ -482,10 +440,7 @@ If you are still piloting ${botName}, sorry for the inconvenience and please use }); // Also update the sheet - SheetPublicAccountService.getInstance().updateBotCheckoutTime( - botName, - dateTime - ); + SheetPublicAccountService.getInstance().updateBotCheckoutTime(botName, dateTime); } } @@ -504,9 +459,7 @@ If you are still piloting ${botName}, sorry for the inconvenience and please use }, data: bot, }); - log( - `PublicAccountsPrisma - updated bot location. Name: ${name}, Location: ${location}` - ); + log(`PublicAccountsPrisma - updated bot location. Name: ${name}, Location: ${location}`); // Also update the sheet SheetPublicAccountService.getInstance().updateBotLocation(name, location); } else { @@ -531,9 +484,7 @@ If you are still piloting ${botName}, sorry for the inconvenience and please use }, data: bot, }); - log( - `PublicAccountsPrisma - updated bot pilot. Name: ${name}, Pilot: ${pilotName}` - ); + log(`PublicAccountsPrisma - updated bot pilot. Name: ${name}, Pilot: ${pilotName}`); // Also update the sheet SheetPublicAccountService.getInstance().updateBotPilot(name, pilotName); } else { diff --git a/src/services/bot/public-accounts-sheet.ts b/src/services/bot/public-accounts-sheet.ts index 265ff34..dfb810c 100644 --- a/src/services/bot/public-accounts-sheet.ts +++ b/src/services/bot/public-accounts-sheet.ts @@ -6,19 +6,14 @@ import { } from "../../config"; import LRUCache from "lru-cache"; import { MINUTES } from "../../shared/time"; -import { - ApplicationCommandOptionChoiceData, - CommandInteraction, - GuildMemberRoleManager, - MessageComponentInteraction, -} from "discord.js"; +import { ApplicationCommandOptionChoiceData, GuildMemberRoleManager } from "discord.js"; import { truncate } from "lodash"; import { checkGoogleCredentials } from "../gdrive"; import moment from "moment"; import { IPublicAccountService } from "./public-accounts.i"; import { BOT_SPREADSHEET_COLUMNS } from "../sheet-updater/public-sheet"; import { bot } from "@prisma/client"; -import { log } from "../../shared/logger" +import { log } from "../../shared/logger"; export const SHEET_TITLE = "Bot Info"; @@ -39,13 +34,13 @@ export class SheetPublicAccountService implements IPublicAccountService { } this.sheet = new GoogleSpreadsheet(publicCharactersGoogleSheetId); } - doBotCheckout(name: string, interaction: MessageComponentInteraction | CommandInteraction): Promise { + doBotCheckout(): Promise { throw new Error("Method not implemented."); } - getBotsForBatphone(location: string): Promise { + getBotsForBatphone(): Promise { throw new Error("Method not implemented."); } - getFirstAvailableBotByLocation(location: string, roles: GuildMemberRoleManager): Promise { + getFirstAvailableBotByLocation(): Promise { throw new Error("Method not implemented."); } @@ -65,25 +60,14 @@ export class SheetPublicAccountService implements IPublicAccountService { } public async updateBotLocation(botName: string, location: string) { - await this.updatePublicAccountSheet( - botName, - BOT_SPREADSHEET_COLUMNS.CurrentLocation, - location - ); + await this.updatePublicAccountSheet(botName, BOT_SPREADSHEET_COLUMNS.CurrentLocation, location); } public async updateBotPilot(botName: string, botPilot: string) { - await this.updatePublicAccountSheet( - botName, - BOT_SPREADSHEET_COLUMNS.CurrentPilot, - botPilot - ); + await this.updatePublicAccountSheet(botName, BOT_SPREADSHEET_COLUMNS.CurrentPilot, botPilot); } - public async updateBotCheckoutTime( - botName: string, - dateTime: moment.Moment | null - ) { + public async updateBotCheckoutTime(botName: string, dateTime: moment.Moment | null) { await this.updatePublicAccountSheet( botName, BOT_SPREADSHEET_COLUMNS.CheckoutTime, @@ -94,15 +78,13 @@ export class SheetPublicAccountService implements IPublicAccountService { private async updatePublicAccountSheet( botName: string, cell: BOT_SPREADSHEET_COLUMNS, - value: any + value: string | number ) { await this.loadBots(); if (this.sheet) { const rows = await this.botInfoSheet.getRows(); const botRowIndex = rows.findIndex( - (r) => - r[BOT_SPREADSHEET_COLUMNS.Name].toLowerCase() === - botName.toLowerCase() + (r) => r[BOT_SPREADSHEET_COLUMNS.Name].toLowerCase() === botName.toLowerCase() ); if (botRowIndex !== -1) { // do update @@ -121,16 +103,18 @@ export class SheetPublicAccountService implements IPublicAccountService { botName: string, rowDataMap: { [id: string]: moment.Moment | string | undefined } ) { - let currentPilot = rowDataMap[BOT_SPREADSHEET_COLUMNS.CurrentPilot] || ""; - log(`public-accounts-sheet updateBotRowDetails - loading bots - ${botName} - pilot ${currentPilot}`); + const currentPilot = rowDataMap[BOT_SPREADSHEET_COLUMNS.CurrentPilot] || ""; + log( + `public-accounts-sheet updateBotRowDetails - loading bots - ${botName} - pilot ${currentPilot}` + ); await this.loadBots(); - log(`public-accounts-sheet updateBotRowDetails - bots loaded - ${botName} - pilot ${currentPilot}`); + log( + `public-accounts-sheet updateBotRowDetails - bots loaded - ${botName} - pilot ${currentPilot}` + ); if (this.sheet) { const rows = await this.botInfoSheet.getRows(); const botRowIndex = rows.findIndex( - (r) => - r[BOT_SPREADSHEET_COLUMNS.Name].toLowerCase() === - botName.toLowerCase() + (r) => r[BOT_SPREADSHEET_COLUMNS.Name].toLowerCase() === botName.toLowerCase() ); if (botRowIndex !== -1) { // do update @@ -141,9 +125,13 @@ export class SheetPublicAccountService implements IPublicAccountService { row[cellData[0]] = cellData[1]; } }); - log(`public-accounts-sheet updateBotRowDetails - save started for - ${botName} - pilot ${currentPilot}`); + log( + `public-accounts-sheet updateBotRowDetails - save started for - ${botName} - pilot ${currentPilot}` + ); await row.save(); - log(`public-accounts-sheet updateBotRowDetails - row saved for - ${botName} - pilot ${currentPilot}`); + log( + `public-accounts-sheet updateBotRowDetails - row saved for - ${botName} - pilot ${currentPilot}` + ); } } else { throw Error(`Bot ${botName} not found.`); @@ -161,21 +149,14 @@ export class SheetPublicAccountService implements IPublicAccountService { const rows = await this.botInfoSheet.getRows(); const classRows = rows.filter( (r) => - (r[BOT_SPREADSHEET_COLUMNS.Class] as string)?.toUpperCase() === - botClass.toUpperCase() + (r[BOT_SPREADSHEET_COLUMNS.Class] as string)?.toUpperCase() === botClass.toUpperCase() ); if (!classRows.length) { throw Error(`Could not find any classes matching ${botClass}.`); } - log( - `Looking for ${botClass} and found ${classRows.length} options.` - ); - const availableClassRows = classRows.filter( - (r) => !r[BOT_SPREADSHEET_COLUMNS.CurrentPilot] - ); - log( - `Looking for ${botClass} and found ${classRows.length} available.` - ); + log(`Looking for ${botClass} and found ${classRows.length} options.`); + const availableClassRows = classRows.filter((r) => !r[BOT_SPREADSHEET_COLUMNS.CurrentPilot]); + log(`Looking for ${botClass} and found ${classRows.length} available.`); const matches = location ? availableClassRows.filter((r) => (r[BOT_SPREADSHEET_COLUMNS.CurrentLocation] as string) @@ -198,15 +179,11 @@ export class SheetPublicAccountService implements IPublicAccountService { throw new Error("Method not implemented."); } - public async getCurrentBotPilot( - botName: string - ): Promise { + public async getCurrentBotPilot(botName: string): Promise { await this.loadBots(); if (this.sheet) { const rows = await this.botInfoSheet.getRows(); - const botRowIndex = rows.findIndex( - (r) => r[BOT_SPREADSHEET_COLUMNS.Name] === botName - ); + const botRowIndex = rows.findIndex((r) => r[BOT_SPREADSHEET_COLUMNS.Name] === botName); if (botRowIndex !== -1) { // do update const row = rows.at(botRowIndex); @@ -224,9 +201,7 @@ export class SheetPublicAccountService implements IPublicAccountService { if (this.sheet) { const rows = await this.botInfoSheet.getRows(); const botRowIndex = rows.findIndex( - (r) => - r[BOT_SPREADSHEET_COLUMNS.Name].toLowerCase() === - botName.toLowerCase() + (r) => r[BOT_SPREADSHEET_COLUMNS.Name].toLowerCase() === botName.toLowerCase() ); return botRowIndex !== -1; } @@ -275,9 +250,7 @@ export class SheetPublicAccountService implements IPublicAccountService { if (this.sheet) { return this.sheet.useServiceAccountAuth({ client_email: GOOGLE_CLIENT_EMAIL, - private_key: (GOOGLE_PRIVATE_KEY || "") - .split(String.raw`\n`) - .join("\n"), + private_key: (GOOGLE_PRIVATE_KEY || "").split(String.raw`\n`).join("\n"), }); } } diff --git a/src/services/bot/public-accounts.i.ts b/src/services/bot/public-accounts.i.ts index a464c40..cd92c16 100644 --- a/src/services/bot/public-accounts.i.ts +++ b/src/services/bot/public-accounts.i.ts @@ -1,13 +1,11 @@ import { ApplicationCommandOptionChoiceData, - ButtonInteraction, CommandInteraction, GuildMemberRoleManager, MessageComponentInteraction, - MessageInteraction, } from "discord.js"; import { Bot } from "./public-accounts-sheet"; -import { bot, Prisma } from "@prisma/client"; +import { bot } from "@prisma/client"; export interface IPublicAccountService { getBotsForBatphone(location: string): Promise; @@ -26,10 +24,7 @@ export interface IPublicAccountService { location?: string, bindLocation?: string ): Promise; - getFirstAvailableBotByLocation( - location: string, - roles: GuildMemberRoleManager - ): Promise; + getFirstAvailableBotByLocation(location: string, roles: GuildMemberRoleManager): Promise; getBotOptions(): Promise[]>; isBotPublic(botName: string): Promise; getBots(): Promise; diff --git a/src/services/castledkp.ts b/src/services/castledkp.ts index fed0bee..25f7465 100644 --- a/src/services/castledkp.ts +++ b/src/services/castledkp.ts @@ -4,321 +4,289 @@ import { partition } from "lodash"; import LRUCache from "lru-cache"; import moment from "moment"; import { castleDkpTokenRO } from "../config"; -import { - AdjustmentData, - RaidTick, - UPLOAD_DATE_FORMAT, -} from "../features/dkp-records/raid-tick"; +import { AdjustmentData, RaidTick, UPLOAD_DATE_FORMAT } from "../features/dkp-records/raid-tick"; import { MINUTES, MONTHS } from "../shared/time"; import { betaDkpService } from "./betaDkpService"; const route = (f: string) => `api.php?function=${f}`; const client = axios.create({ - baseURL: "https://castledkp.com", + baseURL: "https://castledkp.com", }); axiosRetry(client, { retries: 5, retryDelay: axiosRetry.exponentialDelay }); client.interceptors.request.use((config) => { - if (!castleDkpTokenRO) { - throw new Error("Cannot query CastleDKP without an RO token."); - } - config.params = { - ...config.params, - atoken: castleDkpTokenRO, - atype: "api", - format: "json", - }; - return config; + if (!castleDkpTokenRO) { + throw new Error("Cannot query CastleDKP without an RO token."); + } + config.params = { + ...config.params, + atoken: castleDkpTokenRO, + atype: "api", + format: "json", + }; + return config; }); interface Character { - id: number; - name: string; - main: boolean; - classname: string; + id: number; + name: string; + main: boolean; + classname: string; } export interface RaidEventData { - name: string; - shortName: string; - abreviation: string; - value: number; - id: number; + name: string; + shortName: string; + abreviation: string; + value: number; + id: number; } const characters = new LRUCache({ - max: 1000, - ttl: 3 * MONTHS, - updateAgeOnGet: true, + max: 1000, + ttl: 3 * MONTHS, + updateAgeOnGet: true, }); const events = new LRUCache({ - max: 1000, - ttl: 10 * MINUTES, + max: 1000, + ttl: 10 * MINUTES, }); const CASTLE_DKP_EVENT_URL_STRIP = /[-()'\s]/g; const getEvents = async () => { - events.purgeStale(); - if (events.size) { - return events; + events.purgeStale(); + if (events.size) { + return events; + } + const { data } = await client.get<{ + [_: string]: { name: string; value: number; id: number }; + }>(route("events")); + delete data.status; + Object.values(data).forEach(({ id, name, value }) => { + if (name.includes("legacy")) { + return; } - const { data } = await client.get<{ - [_: string]: { name: string; value: number; id: number }; - }>(route("events")); - delete data.status; - Object.values(data).forEach(({ id, name, value }) => { - if (name.includes("legacy")) { - return; - } - const abreviation = name.substring( - name.indexOf("[") + 1, - name.indexOf("]") - ); - const shortName = name.replace(`[${abreviation}]`, "").trim(); - events.set(name.trim(), { - id, - value, - name, - abreviation, - shortName, - }); + const abreviation = name.substring(name.indexOf("[") + 1, name.indexOf("]")); + const shortName = name.replace(`[${abreviation}]`, "").trim(); + events.set(name.trim(), { + id, + value, + name, + abreviation, + shortName, }); - return events; + }); + return events; }; export interface CreateRaidResponse { - eventUrlSlug: string; - id: number; - tick: RaidTick; - invalidNames: string[]; + eventUrlSlug: string; + id: number; + tick: RaidTick; + invalidNames: string[]; } const getCharacter = async (name: string) => { - const character = characters.get(name); - if (character) { - return character; - } - const result = await client - .get<{ direct?: { [key: string]: Character } }>(route("search"), { - params: { - in: "charname", - for: name, - }, - }) - .then(({ data }) => { - if (!data.direct) { - return undefined; - } - return Object.values(data.direct)[0]; - }); - if (result) { - characters.set(name, result); - } - return result; + const character = characters.get(name); + if (character) { + return character; + } + const result = await client + .get<{ direct?: { [key: string]: Character } }>(route("search"), { + params: { + in: "charname", + for: name, + }, + }) + .then(({ data }) => { + if (!data.direct) { + return undefined; + } + return Object.values(data.direct)[0]; + }); + if (result) { + characters.set(name, result); + } + return result; }; export const castledkp = { - getPointsByCharacter: async (characterId: number) => { - const { data } = await client.get(route("points"), { - params: { - filter: "character", - filterid: characterId, - }, - }); - const character = data?.players?.[`player:${characterId}`]; - const dkp = character?.points?.[`multidkp_points:1`]; - return { - characterId: characterId, - characterName: character.name as string, - class: character.class_name as string, - currentDkp: Number(dkp.points_current), - lifetimeDkp: Number(dkp.points_earned) + Number(dkp.points_adjustment), - spentDkp: Number(dkp.points_spent), - }; - }, + getPointsByCharacter: async (characterId: number) => { + const { data } = await client.get(route("points"), { + params: { + filter: "character", + filterid: characterId, + }, + }); + const character = data?.players?.[`player:${characterId}`]; + const dkp = character?.points?.[`multidkp_points:1`]; + return { + characterId: characterId, + characterName: character.name as string, + class: character.class_name as string, + currentDkp: Number(dkp.points_current), + lifetimeDkp: Number(dkp.points_earned) + Number(dkp.points_adjustment), + spentDkp: Number(dkp.points_spent), + }; + }, - getEvent: async (label: string) => { - const events = await getEvents(); - return events.get(label); - }, + getEvent: async (label: string) => { + const events = await getEvents(); + return events.get(label); + }, - getEvents: async () => { - const events = await getEvents(); - return [...events.values()]; - }, + getEvents: async () => { + const events = await getEvents(); + return [...events.values()]; + }, - createRaid: async ( - name: string, - event: RaidEventData, - characterId: string, - threadUrl: string - ) => { - const payload = { - raid_date: moment().format(UPLOAD_DATE_FORMAT), - raid_attendees: { member: [Number(characterId)] }, - raid_value: 0, - raid_event_id: event.id, - raid_note: `${name} ${threadUrl}`, - }; - console.log("Creating new raid:", payload); - const { data } = await client.post<{ raid_id: number }>( - route("add_raid"), - payload - ); + createRaid: async ( + name: string, + event: RaidEventData, + characterId: string, + threadUrl: string + ) => { + const payload = { + raid_date: moment().format(UPLOAD_DATE_FORMAT), + raid_attendees: { member: [Number(characterId)] }, + raid_value: 0, + raid_event_id: event.id, + raid_note: `${name} ${threadUrl}`, + }; + console.log("Creating new raid:", payload); + const { data } = await client.post<{ raid_id: number }>(route("add_raid"), payload); - return { - eventUrlSlug: event.name - .toLowerCase() - .replace(CASTLE_DKP_EVENT_URL_STRIP, "-"), - id: data.raid_id, - }; - }, + return { + eventUrlSlug: event.name.toLowerCase().replace(CASTLE_DKP_EVENT_URL_STRIP, "-"), + id: data.raid_id, + }; + }, - createRaidFromTick: async ( - tick: RaidTick, - threadUrl: string - ): Promise => { - // validate ticks - if (tick.data.event === undefined) { - throw new Error(`Tick is missing an event type.`); - } - if (tick.data.value === undefined) { - throw new Error(`Tick is missing a value.`); - } + createRaidFromTick: async (tick: RaidTick, threadUrl: string): Promise => { + // validate ticks + if (tick.data.event === undefined) { + throw new Error(`Tick is missing an event type.`); + } + if (tick.data.value === undefined) { + throw new Error(`Tick is missing a value.`); + } - // get character ids - const { characters, invalidNames } = await castledkp.getCharacters([ - ...tick.data.attendees, - ]); - const characterIds = characters.map((v) => v.id); - if (!characterIds.length) { - throw new Error(`Tick has no valid characters.`); - } + // get character ids + const { characters, invalidNames } = await castledkp.getCharacters([...tick.data.attendees]); + const characterIds = characters.map((v) => v.id); + if (!characterIds.length) { + throw new Error(`Tick has no valid characters.`); + } - // create raid - const payload = { - raid_date: tick.uploadDate, - raid_attendees: { member: characterIds }, - raid_value: tick.data.value, - raid_event_id: tick.data.event.id, - raid_note: `${tick.uploadNote} ${threadUrl}`, - }; - console.log("Creating raid tick", payload); - const { data } = await client.post<{ raid_id: number }>( - route("add_raid"), - payload - ); + // create raid + const payload = { + raid_date: tick.uploadDate, + raid_attendees: { member: characterIds }, + raid_value: tick.data.value, + raid_event_id: tick.data.event.id, + raid_note: `${tick.uploadNote} ${threadUrl}`, + }; + console.log("Creating raid tick", payload); + const { data } = await client.post<{ raid_id: number }>(route("add_raid"), payload); - // add items to raid - console.log("Adding items to raid", tick.data.loot); - await Promise.all( - tick.data.loot.map((l) => castledkp.addItem(data.raid_id, l)) - ); + // add items to raid + console.log("Adding items to raid", tick.data.loot); + await Promise.all(tick.data.loot.map((l) => castledkp.addItem(data.raid_id, l))); - // add adjustments to raid - console.log("Adding adjustments to raid", tick.data.adjustments); - await Promise.all( - tick.data.adjustments?.map((a) => - castledkp.addAdjustment(data.raid_id, a) - ) || [] - ); + // add adjustments to raid + console.log("Adding adjustments to raid", tick.data.adjustments); + await Promise.all( + tick.data.adjustments?.map((a) => castledkp.addAdjustment(data.raid_id, a)) || [] + ); - // Temporarily create data using the beta service as well; this is not async and is fault tolerant. - // Primarily, this is being used to test the beta service by ingesting real data. - betaDkpService - .createRaid({ - raidTick: tick, - raidActivityType: { - name: tick.data.event.name, - defaultPayout: tick.data.event.value, - }, - }) - .catch((error) => { - console.error(`Failed to create raid in beta service:`, { - message: error.message, - statusCode: error.response ? error.response.status : "N/A", - data: error.response ? error.response.data : "N/A", - config: error.config, - }); - }); + // Temporarily create data using the beta service as well; this is not async and is fault tolerant. + // Primarily, this is being used to test the beta service by ingesting real data. + betaDkpService + .createRaid({ + raidTick: tick, + raidActivityType: { + name: tick.data.event.name, + defaultPayout: tick.data.event.value, + }, + }) + .catch((error) => { + console.error(`Failed to create raid in beta service:`, { + message: error.message, + statusCode: error.response ? error.response.status : "N/A", + data: error.response ? error.response.data : "N/A", + config: error.config, + }); + }); - return { - eventUrlSlug: tick.data.event.name - .toLowerCase() - .replace(CASTLE_DKP_EVENT_URL_STRIP, "-"), - id: data.raid_id, - tick: tick, - invalidNames, - }; - }, + return { + eventUrlSlug: tick.data.event.name.toLowerCase().replace(CASTLE_DKP_EVENT_URL_STRIP, "-"), + id: data.raid_id, + tick: tick, + invalidNames, + }; + }, - getCharacters: async (names: string[]) => { - const [characters, invalidNames] = partition( - await Promise.all( - names.map(async (n) => ({ - name: n, - character: await getCharacter(n), - })) - ), - (c) => !!c.character - ); - return { - characters: characters.map((v) => v.character as unknown as Character), - invalidNames: invalidNames.map((v) => v.name), - }; - }, + getCharacters: async (names: string[]) => { + const [characters, invalidNames] = partition( + await Promise.all( + names.map(async (n) => ({ + name: n, + character: await getCharacter(n), + })) + ), + (c) => !!c.character + ); + return { + characters: characters.map((v) => v.character as unknown as Character), + invalidNames: invalidNames.map((v) => v.name), + }; + }, - getCharacter: async (name: string, requireExists = true) => { - const character = await getCharacter(name); - if (!character && requireExists) { - throw new Error( - `Character named '${name}' does not exist on CastleDKP.com` - ); - } - return character; - }, + getCharacter: async (name: string, requireExists = true) => { + const character = await getCharacter(name); + if (!character && requireExists) { + throw new Error(`Character named '${name}' does not exist on CastleDKP.com`); + } + return character; + }, - addItem: async ( - raidId: number, - loot: { - item: string; - buyer: string; - price: number; - } - ) => { - const character = await castledkp.getCharacter(loot.buyer); - if (!character) { - throw new Error( - `Cannot add item to non-existent character ${loot.buyer}` - ); - } - return client.post(route("add_item"), { - item_date: moment().format(UPLOAD_DATE_FORMAT), - item_name: loot.item, - item_buyers: { member: [character.id] }, - item_raid_id: raidId, - item_value: loot.price, - item_itempool_id: 1, - }); - }, + addItem: async ( + raidId: number, + loot: { + item: string; + buyer: string; + price: number; + } + ) => { + const character = await castledkp.getCharacter(loot.buyer); + if (!character) { + throw new Error(`Cannot add item to non-existent character ${loot.buyer}`); + } + return client.post(route("add_item"), { + item_date: moment().format(UPLOAD_DATE_FORMAT), + item_name: loot.item, + item_buyers: { member: [character.id] }, + item_raid_id: raidId, + item_value: loot.price, + item_itempool_id: 1, + }); + }, - addAdjustment: async (raidId: number, adjustment: AdjustmentData) => { - const character = await castledkp.getCharacter(adjustment.player); - if (!character) { - throw new Error( - `Cannot add adjustment to non-existent character ${adjustment.player}` - ); - } - return client.post(route("add_adjustment"), { - adjustment_date: moment().format(UPLOAD_DATE_FORMAT), - adjustment_reason: adjustment.reason, - adjustment_members: { member: [character.id] }, - adjustment_value: adjustment.value, - adjustment_raid_id: raidId, - adjustment_event_id: 20, - }); - }, + addAdjustment: async (raidId: number, adjustment: AdjustmentData) => { + const character = await castledkp.getCharacter(adjustment.player); + if (!character) { + throw new Error(`Cannot add adjustment to non-existent character ${adjustment.player}`); + } + return client.post(route("add_adjustment"), { + adjustment_date: moment().format(UPLOAD_DATE_FORMAT), + adjustment_reason: adjustment.reason, + adjustment_members: { member: [character.id] }, + adjustment_value: adjustment.value, + adjustment_raid_id: raidId, + adjustment_event_id: 20, + }); + }, }; diff --git a/src/services/gdrive.ts b/src/services/gdrive.ts index 2719a50..cef46a1 100644 --- a/src/services/gdrive.ts +++ b/src/services/gdrive.ts @@ -23,10 +23,7 @@ export const findFiles = async (query: string) => { return files; }; -export const uploadFileToFolder = async ( - file: DriveFile, - folder: string -) => { +export const uploadFileToFolder = async (file: DriveFile, folder: string) => { const auth = await authorize(); const drive = google.drive({ version: "v3", auth }); drive.files.create( @@ -78,17 +75,12 @@ export const updateFile = async (fileId: string, file: DriveFile) => { export const getFile = async (fileId: string) => { const auth = await authorize(); const drive = google.drive({ version: "v3", auth }); - try { - const file = await drive.files.get({ - fileId: fileId, - alt: 'media', - }); - return file.data; - } catch (err) { - // TODO(developer) - Handle error - throw err; - } -} + const file = await drive.files.get({ + fileId: fileId, + alt: "media", + }); + return file.data; +}; export const checkGoogleCredentials = () => { if (!GOOGLE_CLIENT_EMAIL || !GOOGLE_PRIVATE_KEY) { diff --git a/src/services/location.ts b/src/services/location.ts index e288471..ece6396 100644 --- a/src/services/location.ts +++ b/src/services/location.ts @@ -55,9 +55,7 @@ export class LocationService implements ILocationService { return Array.from(this.locationCache.values()); } - async getLocationOptions(): Promise< - ApplicationCommandOptionChoiceData[] - > { + async getLocationOptions(): Promise[]> { const locations = await this.getLocations(); return locations.map((b) => ({ diff --git a/src/services/sheet-updater/public-sheet.ts b/src/services/sheet-updater/public-sheet.ts index a9a697d..af9226a 100644 --- a/src/services/sheet-updater/public-sheet.ts +++ b/src/services/sheet-updater/public-sheet.ts @@ -44,9 +44,7 @@ export class PublicSheetService { if (this.sheet) { return this.sheet.useServiceAccountAuth({ client_email: GOOGLE_CLIENT_EMAIL, - private_key: (GOOGLE_PRIVATE_KEY || "") - .split(String.raw`\n`) - .join("\n"), + private_key: (GOOGLE_PRIVATE_KEY || "").split(String.raw`\n`).join("\n"), }); } } diff --git a/src/shared/action/instructions-ready-action-2.ts b/src/shared/action/instructions-ready-action-2.ts index 3033163..c844107 100644 --- a/src/shared/action/instructions-ready-action-2.ts +++ b/src/shared/action/instructions-ready-action-2.ts @@ -10,10 +10,7 @@ export class InstructionsReadyAction { private readonly threadName?: string ) {} - public async createOrUpdateInstructions( - options: BaseMessageOptions, - pin = false - ) { + public async createOrUpdateInstructions(options: BaseMessageOptions, pin = false) { let message = await this.getInstructionsMessage(); if (!message) { diff --git a/src/shared/action/instructions-ready-action.ts b/src/shared/action/instructions-ready-action.ts index bc40edf..c904c1d 100644 --- a/src/shared/action/instructions-ready-action.ts +++ b/src/shared/action/instructions-ready-action.ts @@ -23,10 +23,7 @@ export abstract class InstructionsReadyAction extends ReadyAction { | TextChannel | ThreadChannel; - protected async createOrUpdateInstructions( - options: BaseMessageOptions, - name: Name - ) { + protected async createOrUpdateInstructions(options: BaseMessageOptions, name: Name) { const embed = await this.getEmbed(name); if (embed) { diff --git a/src/shared/action/message-action.ts b/src/shared/action/message-action.ts index e9ded5f..377a140 100644 --- a/src/shared/action/message-action.ts +++ b/src/shared/action/message-action.ts @@ -23,17 +23,15 @@ export abstract class MessageAction { public async replyError(err: string) { try { await this.message.reply(`⚠️${err}`); - } catch(err) { - console.error(err) + } catch (err) { + console.error(err); } } protected get authorId() { const authorId = this.message.author?.id; if (!authorId) { - throw new Error( - "Something went wrong when retrieving the message author." - ); + throw new Error("Something went wrong when retrieving the message author."); } return authorId; } diff --git a/src/shared/action/reaction-action.ts b/src/shared/action/reaction-action.ts index aefcac5..17e1448 100644 --- a/src/shared/action/reaction-action.ts +++ b/src/shared/action/reaction-action.ts @@ -1,9 +1,4 @@ -import { - MessageReaction, - PartialMessageReaction, - PartialUser, - User, -} from "discord.js"; +import { MessageReaction, PartialMessageReaction, PartialUser, User } from "discord.js"; export const reactionActionExecutor = async (action: ReactionAction) => { await action.initialize(); @@ -21,10 +16,10 @@ export abstract class ReactionAction { public async initialize() { if (this.reaction.partial) { - await this.reaction.fetch().catch((err) => { - console.error(err); - this.replyError(err); - }); + await this.reaction.fetch().catch((err) => { + console.error(err); + this.replyError(err); + }); } return this; } @@ -32,17 +27,15 @@ export abstract class ReactionAction { public abstract execute(): Promise; public async replyError(err: string) { - await this.message.reply(`⚠️${err}`).catch((err) => { - console.error(err); - }); + await this.message.reply(`⚠️${err}`).catch((err) => { + console.error(err); + }); } protected get authorId() { const authorId = this.reaction.message.author?.id; if (!authorId) { - throw new Error( - "Something went wrong when retrieving the message author." - ); + throw new Error("Something went wrong when retrieving the message author."); } return authorId; } diff --git a/src/shared/action/ready-action-2.ts b/src/shared/action/ready-action-2.ts index 61a68a7..cef5416 100644 --- a/src/shared/action/ready-action-2.ts +++ b/src/shared/action/ready-action-2.ts @@ -2,10 +2,7 @@ export interface Options { repeatDuration?: number; } -export const readyActionExecutor = async ( - action: () => Promise, - options: Options -) => { +export const readyActionExecutor = async (action: () => Promise, options: Options) => { await action().catch(console.error); const { repeatDuration } = options; diff --git a/src/shared/command/base-command.ts b/src/shared/command/base-command.ts index aa1b57e..2a34bbe 100644 --- a/src/shared/command/base-command.ts +++ b/src/shared/command/base-command.ts @@ -30,7 +30,5 @@ export abstract class BaseCommand { interaction: AutocompleteInteraction ): Promise; - public abstract execute( - interaction: CommandInteraction - ): Promise; + public abstract execute(interaction: CommandInteraction): Promise; } diff --git a/src/shared/command/button-command.ts b/src/shared/command/button-command.ts index 47571d9..37329fd 100644 --- a/src/shared/command/button-command.ts +++ b/src/shared/command/button-command.ts @@ -3,7 +3,5 @@ import { ButtonInteraction, CacheType } from "discord.js"; export abstract class ButtonCommand { public constructor(public readonly customId: string) {} - public abstract execute( - interaction: ButtonInteraction - ): Promise; + public abstract execute(interaction: ButtonInteraction): Promise; } diff --git a/src/shared/command/command.ts b/src/shared/command/command.ts index 4e8101b..a167cc3 100644 --- a/src/shared/command/command.ts +++ b/src/shared/command/command.ts @@ -1,8 +1,4 @@ -import { - AutocompleteInteraction, - CacheType, - ChatInputCommandInteraction, -} from "discord.js"; +import { AutocompleteInteraction, CacheType, ChatInputCommandInteraction } from "discord.js"; import { BaseCommand } from "./base-command"; import { Subcommand } from "./subcommand"; import { SlashCommandBuilder } from "@discordjs/builders"; @@ -17,9 +13,7 @@ export class Command extends BaseCommand { private readonly _subcommands: Subcommand[] ) { super(`${name}${commandSuffix || ""}`, description); - this.command = new SlashCommandBuilder() - .setName(this.name) - .setDescription(this.description); + this.command = new SlashCommandBuilder().setName(this.name).setDescription(this.description); this._subcommands.forEach((s) => this.command.addSubcommand(s.command)); } @@ -40,9 +34,6 @@ export class Command extends BaseCommand { interaction: AutocompleteInteraction ) { const subcommand = interaction.options.getSubcommand(true); - return this.subcommands[subcommand].getOptionAutocomplete( - option, - interaction - ); + return this.subcommands[subcommand].getOptionAutocomplete(option, interaction); } } diff --git a/src/shared/command/subcommand.ts b/src/shared/command/subcommand.ts index 8eaeae9..8bdc47a 100644 --- a/src/shared/command/subcommand.ts +++ b/src/shared/command/subcommand.ts @@ -1,21 +1,13 @@ import { SlashCommandSubcommandBuilder } from "@discordjs/builders"; -import { - AutocompleteInteraction, - CacheType, - CommandInteraction, -} from "discord.js"; +import { AutocompleteInteraction, CacheType, CommandInteraction } from "discord.js"; import { BaseCommand } from "./base-command"; export const getOption = ( subcommandName: string, option: string, - interaction: - | CommandInteraction - | AutocompleteInteraction + interaction: CommandInteraction | AutocompleteInteraction ) => { - const subcommand = interaction.options.data.find( - (d) => d.name === subcommandName - ); + const subcommand = interaction.options.data.find((d) => d.name === subcommandName); if (!subcommand || !subcommand.options) { throw new Error("Subcommand has no options"); } @@ -24,25 +16,19 @@ export const getOption = ( export abstract class Subcommand extends BaseCommand { public get command() { - return new SlashCommandSubcommandBuilder() - .setName(this.name) - .setDescription(this.description); + return new SlashCommandSubcommandBuilder().setName(this.name).setDescription(this.description); } protected getOption( name: string, - interaction: - | CommandInteraction - | AutocompleteInteraction + interaction: CommandInteraction | AutocompleteInteraction ) { return getOption(this.name, name, interaction); } protected getOptionValue( name: string, - interaction: - | CommandInteraction - | AutocompleteInteraction + interaction: CommandInteraction | AutocompleteInteraction ) { const o = this.getOption(name, interaction); if (o?.value === undefined) { @@ -53,9 +39,7 @@ export abstract class Subcommand extends BaseCommand { protected getRequiredOptionValue( name: string, - interaction: - | CommandInteraction - | AutocompleteInteraction + interaction: CommandInteraction | AutocompleteInteraction ) { const o = this.getOption(name, interaction); if (!o) { diff --git a/src/shared/command/util.ts b/src/shared/command/util.ts index c7b49f5..255146e 100644 --- a/src/shared/command/util.ts +++ b/src/shared/command/util.ts @@ -53,18 +53,13 @@ export const requireInteractionMemberPermission = ( } }; -export const getChannel = async ( - channelId: string, - interaction: ButtonInteraction -) => { +export const getChannel = async (channelId: string, interaction: ButtonInteraction) => { return await interaction.guild?.channels.fetch(channelId); }; export const getRole = ( roleId: string, - interaction: - | CommandInteraction - | AutocompleteInteraction + interaction: CommandInteraction | AutocompleteInteraction ) => { return interaction.guild?.roles.cache.get(roleId); }; @@ -72,9 +67,7 @@ export const getRole = ( export const requireUserRole = ( userId: string, roleId: string, - interaction: - | CommandInteraction - | AutocompleteInteraction + interaction: CommandInteraction | AutocompleteInteraction ) => { const role = getRole(roleId, interaction); if (!role?.members.get(userId)) { @@ -82,10 +75,7 @@ export const requireUserRole = ( } }; -export const fetchRole = async ( - interaction: CommandInteraction, - roleId: string -) => { +export const fetchRole = async (interaction: CommandInteraction, roleId: string) => { const roles = await interaction.guild?.roles.fetch(); const role = roles?.filter((r) => r.id === roleId); if (!role) { @@ -96,9 +86,7 @@ export const fetchRole = async ( const MESSAGE_CHAR_LIMIT = 1800; -export const listThreadMembers = async ( - interaction: CommandInteraction -) => { +export const listThreadMembers = async (interaction: CommandInteraction) => { if (!interaction.channel?.isThread()) { throw new Error(`Channel is not a thread.`); } @@ -144,10 +132,7 @@ export const listThreadMembers = async ( return names.length; }; -export const addRoleToThread = async ( - roleId: string, - channel: ThreadChannel -) => { +export const addRoleToThread = async (roleId: string, channel: ThreadChannel) => { const roles = await getRoles(); const everyone = await getMembers(); const message = await channel.send("Temporary message."); diff --git a/src/shared/items.ts b/src/shared/items.ts index a0027ae..0080f12 100644 --- a/src/shared/items.ts +++ b/src/shared/items.ts @@ -1,5 +1,3 @@ -import { replaceAll } from "./string-util"; - export const itemsData = { "10 dose adrenaline tap": "/10_Dose_Adrenaline_Tap", "10 dose ant's potion": "/10_Dose_Ant%27s_Potion", @@ -149,8 +147,7 @@ export const itemsData = { "a stone key": "/A_Stone_Key", "a strategic map of kithicor": "/A_strategic_map_of_Kithicor", "a tattered note": "/A_tattered_note", - "a tattered note (shaman skull quest 2)": - "/A_Tattered_Note_(Shaman_Skull_Quest_2)", + "a tattered note (shaman skull quest 2)": "/A_Tattered_Note_(Shaman_Skull_Quest_2)", "a torch": "/A_Torch", "a tump stump": "/A_Tump_Stump", "a twisted stalk": "/A_Twisted_Stalk", @@ -688,8 +685,7 @@ export const itemsData = { "bixie essence": "/Bixie_Essence", "bixie parts": "/Bixie_Parts", "bixie stinger": "/Bixie_Stinger", - "bixie stinger (bixie god's stinger)": - "/Bixie_Stinger_(Bixie_God%27s_Stinger)", + "bixie stinger (bixie god's stinger)": "/Bixie_Stinger_(Bixie_God%27s_Stinger)", "bixie sword blade": "/Bixie_Sword_Blade", "bixie wing": "/Bixie_Wing", "bjek's head": "/Bjek%27s_Head", @@ -944,8 +940,7 @@ export const itemsData = { "blood spirit": "/Blood_Spirit", "blood splattered veil": "/Blood_Splattered_Veil", "blood stained note": "/Blood_Stained_Note", - "blood stained note (klunga's blood)": - "/Blood_Stained_Note_(Klunga%27s_Blood)", + "blood stained note (klunga's blood)": "/Blood_Stained_Note_(Klunga%27s_Blood)", "blood temper": "/Blood_Temper", "blood thorn extract": "/Blood_Thorn_Extract", "blood wolf harness": "/Blood_Wolf_Harness", @@ -1410,8 +1405,7 @@ export const itemsData = { "carved darkwood 1-cam bow (linen)": "/Carved_Darkwood_1-Cam_Bow_(Linen)", "carved darkwood 1-cam bow (silk)": "/Carved_Darkwood_1-Cam_Bow_(Silk)", "carved darkwood compound bow (hemp)": "/Carved_Darkwood_Compound_Bow_(Hemp)", - "carved darkwood compound bow (linen)": - "/Carved_Darkwood_Compound_Bow_(Linen)", + "carved darkwood compound bow (linen)": "/Carved_Darkwood_Compound_Bow_(Linen)", "carved darkwood compound bow (silk)": "/Carved_Darkwood_Compound_Bow_(Silk)", "carved darkwood recurve bow (hemp)": "/Carved_Darkwood_Recurve_Bow_(Hemp)", "carved darkwood recurve bow (linen)": "/Carved_Darkwood_Recurve_Bow_(Linen)", @@ -2570,8 +2564,7 @@ export const itemsData = { "dwarven battle shield": "/Dwarven_Battle_Shield", "dwarven battle shield (imbued)": "/Dwarven_Battle_Shield_(Imbued)", "dwarven blood": "/Dwarven_Blood", - "dwarven breastplate (enchanted imbued)": - "/Dwarven_Breastplate_(Enchanted_Imbued)", + "dwarven breastplate (enchanted imbued)": "/Dwarven_Breastplate_(Enchanted_Imbued)", "dwarven chain boots": "/Dwarven_Chain_Boots", "dwarven chain bracelet": "/Dwarven_Chain_Bracelet", "dwarven chain cloak": "/Dwarven_Chain_Cloak", @@ -2586,42 +2579,31 @@ export const itemsData = { "dwarven chain veil": "/Dwarven_Chain_Veil", "dwarven mace": "/Dwarven_Mace", "dwarven plate boots": "/Dwarven_Plate_Boots", - "dwarven plate boots (enchanted imbued)": - "/Dwarven_Plate_Boots_(Enchanted_Imbued)", + "dwarven plate boots (enchanted imbued)": "/Dwarven_Plate_Boots_(Enchanted_Imbued)", "dwarven plate bracers": "/Dwarven_Plate_Bracers", - "dwarven plate bracers (enchanted imbued)": - "/Dwarven_Plate_Bracers_(Enchanted_Imbued)", + "dwarven plate bracers (enchanted imbued)": "/Dwarven_Plate_Bracers_(Enchanted_Imbued)", "dwarven plate breastplate": "/Dwarven_Plate_Breastplate", "dwarven plate collar": "/Dwarven_Plate_Collar", - "dwarven plate collar (enchanted imbued)": - "/Dwarven_Plate_Collar_(Enchanted_Imbued)", + "dwarven plate collar (enchanted imbued)": "/Dwarven_Plate_Collar_(Enchanted_Imbued)", "dwarven plate gauntlets": "/Dwarven_Plate_Gauntlets", - "dwarven plate gauntlets (enchanted imbued)": - "/Dwarven_Plate_Gauntlets_(Enchanted_Imbued)", + "dwarven plate gauntlets (enchanted imbued)": "/Dwarven_Plate_Gauntlets_(Enchanted_Imbued)", "dwarven plate girdle": "/Dwarven_Plate_Girdle", - "dwarven plate girdle (enchanted imbued)": - "/Dwarven_Plate_Girdle_(Enchanted_Imbued)", + "dwarven plate girdle (enchanted imbued)": "/Dwarven_Plate_Girdle_(Enchanted_Imbued)", "dwarven plate greaves": "/Dwarven_Plate_Greaves", - "dwarven plate greaves (enchanted imbued)": - "/Dwarven_Plate_Greaves_(Enchanted_Imbued)", + "dwarven plate greaves (enchanted imbued)": "/Dwarven_Plate_Greaves_(Enchanted_Imbued)", "dwarven plate helm": "/Dwarven_Plate_Helm", - "dwarven plate helm (enchanted imbued)": - "/Dwarven_Plate_Helm_(Enchanted_Imbued)", + "dwarven plate helm (enchanted imbued)": "/Dwarven_Plate_Helm_(Enchanted_Imbued)", "dwarven plate pauldron": "/Dwarven_Plate_Pauldron", - "dwarven plate pauldron (enchanted imbued)": - "/Dwarven_Plate_Pauldron_(Enchanted_Imbued)", + "dwarven plate pauldron (enchanted imbued)": "/Dwarven_Plate_Pauldron_(Enchanted_Imbued)", "dwarven plate vambraces": "/Dwarven_Plate_Vambraces", - "dwarven plate vambraces (enchanted imbued)": - "/Dwarven_Plate_Vambraces_(Enchanted_Imbued)", + "dwarven plate vambraces (enchanted imbued)": "/Dwarven_Plate_Vambraces_(Enchanted_Imbued)", "dwarven plate visor": "/Dwarven_Plate_Visor", - "dwarven plate visor (enchanted imbued)": - "/Dwarven_Plate_Visor_(Enchanted_Imbued)", + "dwarven plate visor (enchanted imbued)": "/Dwarven_Plate_Visor_(Enchanted_Imbued)", "dwarven ringmail tunic": "/Dwarven_Ringmail_Tunic", "dwarven sap": "/Dwarven_Sap", "dwarven smithy hammer": "/Dwarven_Smithy_Hammer", "dwarven splinted cloak": "/Dwarven_Splinted_Cloak", - "dwarven splinted cloak (enchanted imbued)": - "/Dwarven_Splinted_Cloak_(Enchanted_Imbued)", + "dwarven splinted cloak (enchanted imbued)": "/Dwarven_Splinted_Cloak_(Enchanted_Imbued)", "dwarven two-handed axe": "/Dwarven_Two-Handed_Axe", "dwarven wire": "/Dwarven_Wire", "dwarven work boots": "/Dwarven_Work_Boots", @@ -2816,10 +2798,8 @@ export const itemsData = { "encased velium etched rune": "/Encased_Velium_etched_rune", "enchanted adamantite jointing": "/Enchanted_Adamantite_Jointing", "enchanted adamantite rings": "/Enchanted_Adamantite_Rings", - "enchanted antonian long sword (fire emerald)": - "/Enchanted_Antonian_Long_Sword_(Fire_Emerald)", - "enchanted antonian long sword (star ruby)": - "/Enchanted_Antonian_Long_Sword_(Star_Ruby)", + "enchanted antonian long sword (fire emerald)": "/Enchanted_Antonian_Long_Sword_(Fire_Emerald)", + "enchanted antonian long sword (star ruby)": "/Enchanted_Antonian_Long_Sword_(Star_Ruby)", "enchanted block of adamantite": "/Enchanted_Block_of_Adamantite", "enchanted block of brellium": "/Enchanted_Block_of_Brellium", "enchanted block of mithril": "/Enchanted_Block_of_Mithril", @@ -2860,90 +2840,54 @@ export const itemsData = { "enchanted folded brellium sheet": "/Enchanted_Folded_Brellium_Sheet", "enchanted folded sheet metal": "/Enchanted_Folded_Sheet_Metal", "enchanted folded sheet of mithril": "/Enchanted_Folded_Sheet_of_Mithril", - "enchanted full breastplate (electrum)": - "/Enchanted_Full_Breastplate_(electrum)", + "enchanted full breastplate (electrum)": "/Enchanted_Full_Breastplate_(electrum)", "enchanted full breastplate (gold)": "/Enchanted_Full_Breastplate_(gold)", - "enchanted full breastplate (platinum)": - "/Enchanted_Full_Breastplate_(platinum)", + "enchanted full breastplate (platinum)": "/Enchanted_Full_Breastplate_(platinum)", "enchanted full breastplate (silver)": "/Enchanted_Full_Breastplate_(silver)", - "enchanted full plate boots (electrum)": - "/Enchanted_Full_Plate_Boots_(electrum)", + "enchanted full plate boots (electrum)": "/Enchanted_Full_Plate_Boots_(electrum)", "enchanted full plate boots (gold)": "/Enchanted_Full_Plate_Boots_(gold)", - "enchanted full plate boots (platinum)": - "/Enchanted_Full_Plate_Boots_(platinum)", + "enchanted full plate boots (platinum)": "/Enchanted_Full_Plate_Boots_(platinum)", "enchanted full plate boots (silver)": "/Enchanted_Full_Plate_Boots_(silver)", - "enchanted full plate bracers (electrum)": - "/Enchanted_Full_Plate_Bracers_(electrum)", + "enchanted full plate bracers (electrum)": "/Enchanted_Full_Plate_Bracers_(electrum)", "enchanted full plate bracers (gold)": "/Enchanted_Full_Plate_Bracers_(gold)", - "enchanted full plate bracers (platinum)": - "/Enchanted_Full_Plate_Bracers_(platinum)", - "enchanted full plate bracers (silver)": - "/Enchanted_Full_Plate_Bracers_(silver)", - "enchanted full plate collar (electrum)": - "/Enchanted_Full_Plate_Collar_(electrum)", + "enchanted full plate bracers (platinum)": "/Enchanted_Full_Plate_Bracers_(platinum)", + "enchanted full plate bracers (silver)": "/Enchanted_Full_Plate_Bracers_(silver)", + "enchanted full plate collar (electrum)": "/Enchanted_Full_Plate_Collar_(electrum)", "enchanted full plate collar (gold)": "/Enchanted_Full_Plate_Collar_(gold)", - "enchanted full plate collar (platinum)": - "/Enchanted_Full_Plate_Collar_(platinum)", - "enchanted full plate collar (silver)": - "/Enchanted_Full_Plate_Collar_(silver)", - "enchanted full plate gauntlets (electrum)": - "/Enchanted_Full_Plate_Gauntlets_(electrum)", - "enchanted full plate gauntlets (gold)": - "/Enchanted_Full_Plate_Gauntlets_(gold)", - "enchanted full plate gauntlets (platinum)": - "/Enchanted_Full_Plate_Gauntlets_(platinum)", - "enchanted full plate gauntlets (silver)": - "/Enchanted_Full_Plate_Gauntlets_(silver)", - "enchanted full plate girdle (electrum)": - "/Enchanted_Full_Plate_Girdle_(electrum)", + "enchanted full plate collar (platinum)": "/Enchanted_Full_Plate_Collar_(platinum)", + "enchanted full plate collar (silver)": "/Enchanted_Full_Plate_Collar_(silver)", + "enchanted full plate gauntlets (electrum)": "/Enchanted_Full_Plate_Gauntlets_(electrum)", + "enchanted full plate gauntlets (gold)": "/Enchanted_Full_Plate_Gauntlets_(gold)", + "enchanted full plate gauntlets (platinum)": "/Enchanted_Full_Plate_Gauntlets_(platinum)", + "enchanted full plate gauntlets (silver)": "/Enchanted_Full_Plate_Gauntlets_(silver)", + "enchanted full plate girdle (electrum)": "/Enchanted_Full_Plate_Girdle_(electrum)", "enchanted full plate girdle (gold)": "/Enchanted_Full_Plate_Girdle_(gold)", - "enchanted full plate girdle (platinum)": - "/Enchanted_Full_Plate_Girdle_(platinum)", - "enchanted full plate girdle (silver)": - "/Enchanted_Full_Plate_Girdle_(silver)", - "enchanted full plate greaves (electrum)": - "/Enchanted_Full_Plate_Greaves_(electrum)", + "enchanted full plate girdle (platinum)": "/Enchanted_Full_Plate_Girdle_(platinum)", + "enchanted full plate girdle (silver)": "/Enchanted_Full_Plate_Girdle_(silver)", + "enchanted full plate greaves (electrum)": "/Enchanted_Full_Plate_Greaves_(electrum)", "enchanted full plate greaves (gold)": "/Enchanted_Full_Plate_Greaves_(gold)", - "enchanted full plate greaves (platinum)": - "/Enchanted_Full_Plate_Greaves_(platinum)", - "enchanted full plate greaves (silver)": - "/Enchanted_Full_Plate_Greaves_(silver)", - "enchanted full plate helm (electrum)": - "/Enchanted_Full_Plate_Helm_(electrum)", + "enchanted full plate greaves (platinum)": "/Enchanted_Full_Plate_Greaves_(platinum)", + "enchanted full plate greaves (silver)": "/Enchanted_Full_Plate_Greaves_(silver)", + "enchanted full plate helm (electrum)": "/Enchanted_Full_Plate_Helm_(electrum)", "enchanted full plate helm (gold)": "/Enchanted_Full_Plate_Helm_(gold)", - "enchanted full plate helm (platinum)": - "/Enchanted_Full_Plate_Helm_(platinum)", + "enchanted full plate helm (platinum)": "/Enchanted_Full_Plate_Helm_(platinum)", "enchanted full plate helm (silver)": "/Enchanted_Full_Plate_Helm_(silver)", - "enchanted full plate pauldron (electrum)": - "/Enchanted_Full_Plate_Pauldron_(electrum)", - "enchanted full plate pauldron (gold)": - "/Enchanted_Full_Plate_Pauldron_(gold)", - "enchanted full plate pauldron (platinum)": - "/Enchanted_Full_Plate_Pauldron_(platinum)", - "enchanted full plate pauldron (silver)": - "/Enchanted_Full_Plate_Pauldron_(silver)", - "enchanted full plate vambraces (electrum)": - "/Enchanted_Full_Plate_Vambraces_(electrum)", - "enchanted full plate vambraces (gold)": - "/Enchanted_Full_Plate_Vambraces_(gold)", - "enchanted full plate vambraces (platinum)": - "/Enchanted_Full_Plate_Vambraces_(platinum)", - "enchanted full plate vambraces (silver)": - "/Enchanted_Full_Plate_Vambraces_(silver)", - "enchanted full plate visor (electrum)": - "/Enchanted_Full_Plate_Visor_(electrum)", + "enchanted full plate pauldron (electrum)": "/Enchanted_Full_Plate_Pauldron_(electrum)", + "enchanted full plate pauldron (gold)": "/Enchanted_Full_Plate_Pauldron_(gold)", + "enchanted full plate pauldron (platinum)": "/Enchanted_Full_Plate_Pauldron_(platinum)", + "enchanted full plate pauldron (silver)": "/Enchanted_Full_Plate_Pauldron_(silver)", + "enchanted full plate vambraces (electrum)": "/Enchanted_Full_Plate_Vambraces_(electrum)", + "enchanted full plate vambraces (gold)": "/Enchanted_Full_Plate_Vambraces_(gold)", + "enchanted full plate vambraces (platinum)": "/Enchanted_Full_Plate_Vambraces_(platinum)", + "enchanted full plate vambraces (silver)": "/Enchanted_Full_Plate_Vambraces_(silver)", + "enchanted full plate visor (electrum)": "/Enchanted_Full_Plate_Visor_(electrum)", "enchanted full plate visor (gold)": "/Enchanted_Full_Plate_Visor_(gold)", - "enchanted full plate visor (platinum)": - "/Enchanted_Full_Plate_Visor_(platinum)", + "enchanted full plate visor (platinum)": "/Enchanted_Full_Plate_Visor_(platinum)", "enchanted full plate visor (silver)": "/Enchanted_Full_Plate_Visor_(silver)", - "enchanted full splinted cloak (electrum)": - "/Enchanted_Full_Splinted_Cloak_(electrum)", - "enchanted full splinted cloak (gold)": - "/Enchanted_Full_Splinted_Cloak_(gold)", - "enchanted full splinted cloak (platinum)": - "/Enchanted_Full_Splinted_Cloak_(platinum)", - "enchanted full splinted cloak (silver)": - "/Enchanted_Full_Splinted_Cloak_(silver)", + "enchanted full splinted cloak (electrum)": "/Enchanted_Full_Splinted_Cloak_(electrum)", + "enchanted full splinted cloak (gold)": "/Enchanted_Full_Splinted_Cloak_(gold)", + "enchanted full splinted cloak (platinum)": "/Enchanted_Full_Splinted_Cloak_(platinum)", + "enchanted full splinted cloak (silver)": "/Enchanted_Full_Splinted_Cloak_(silver)", "enchanted gloves": "/Enchanted_Gloves", "enchanted gold bar": "/Enchanted_Gold_Bar", "enchanted kelp gauntlets": "/Enchanted_Kelp_Gauntlets", @@ -3251,8 +3195,7 @@ export const itemsData = { "fine steel morning star": "/Fine_Steel_Morning_Star", "fine steel naginata": "/Fine_Steel_Naginata", "fine steel rapier": "/Fine_Steel_Rapier", - "fine steel rapier (gunthak pirate rapier)": - "/Fine_Steel_Rapier_(Gunthak_Pirate_Rapier)", + "fine steel rapier (gunthak pirate rapier)": "/Fine_Steel_Rapier_(Gunthak_Pirate_Rapier)", "fine steel scimitar": "/Fine_Steel_Scimitar", "fine steel short sword": "/Fine_Steel_Short_Sword", "fine steel spear": "/Fine_Steel_Spear", @@ -4414,8 +4357,7 @@ export const itemsData = { "holgresh spirit beads": "/Holgresh_Spirit_Beads", "holgresh wing": "/Holgresh_Wing", "hollow bone shank": "/Hollow_Bone_Shank", - "hollow skull (skull of the tower cook)": - "/Hollow_Skull_(Skull_of_the_Tower_Cook)", + "hollow skull (skull of the tower cook)": "/Hollow_Skull_(Skull_of_the_Tower_Cook)", "hollow skull (skull of wun toque)": "/Hollow_Skull_(Skull_of_Wun_Toque)", "hollowed bone bracers": "/Hollowed_Bone_Bracers", "holy cask": "/Holy_Cask", @@ -4618,12 +4560,9 @@ export const itemsData = { "imbued black pearl electrum choker": "/Imbued_Black_Pearl_Electrum_Choker", "imbued black pearl platinum ring": "/Imbued_Black_Pearl_Platinum_Ring", "imbued black sapphire": "/Imbued_Black_Sapphire", - "imbued black sapphire electrum earring": - "/Imbued_Black_Sapphire_Electrum_Earring", - "imbued black sapphire platinum necklace": - "/Imbued_Black_Sapphire_Platinum_Necklace", - "imbued black sapphire silvered necklace": - "/Imbued_Black_Sapphire_Silvered_Necklace", + "imbued black sapphire electrum earring": "/Imbued_Black_Sapphire_Electrum_Earring", + "imbued black sapphire platinum necklace": "/Imbued_Black_Sapphire_Platinum_Necklace", + "imbued black sapphire silvered necklace": "/Imbued_Black_Sapphire_Silvered_Necklace", "imbued blackened pearl silver ring": "/Imbued_Blackened_Pearl_Silver_Ring", "imbued cabilis scale belt": "/Imbued_Cabilis_Scale_Belt", "imbued cabilis scale boots": "/Imbued_Cabilis_Scale_Boots", @@ -4640,54 +4579,30 @@ export const itemsData = { "imbued diamond": "/Imbued_Diamond", "imbued diamond electrum mask": "/Imbued_Diamond_Electrum_Mask", "imbued dwarven breastplate": "/Imbued_Dwarven_Breastplate", - "imbued dwarven chain boots (brell serilis)": - "/Imbued_Dwarven_Chain_Boots_(Brell_Serilis)", - "imbued dwarven chain boots (bristlebane)": - "/Imbued_Dwarven_Chain_Boots_(Bristlebane)", - "imbued dwarven chain bracelet (brell serilis)": - "/Imbued_Dwarven_Chain_Bracelet_(Brell_Serilis)", - "imbued dwarven chain bracelet (bristlebane)": - "/Imbued_Dwarven_Chain_Bracelet_(Bristlebane)", - "imbued dwarven chain cloak (brell serilis)": - "/Imbued_Dwarven_Chain_Cloak_(Brell_Serilis)", - "imbued dwarven chain cloak (bristlebane)": - "/Imbued_Dwarven_Chain_Cloak_(Bristlebane)", - "imbued dwarven chain coif (brell serilis)": - "/Imbued_Dwarven_Chain_Coif_(Brell_Serilis)", - "imbued dwarven chain coif (bristlebane)": - "/Imbued_Dwarven_Chain_Coif_(Bristlebane)", - "imbued dwarven chain gloves (brell serilis)": - "/Imbued_Dwarven_Chain_Gloves_(Brell_Serilis)", - "imbued dwarven chain gloves (bristlebane)": - "/Imbued_Dwarven_Chain_Gloves_(Bristlebane)", - "imbued dwarven chain gorget (brell serilis)": - "/Imbued_Dwarven_Chain_Gorget_(Brell_Serilis)", - "imbued dwarven chain gorget (bristlebane)": - "/Imbued_Dwarven_Chain_Gorget_(Bristlebane)", - "imbued dwarven chain leggings (brell serilis)": - "/Imbued_Dwarven_Chain_Leggings_(Brell_Serilis)", - "imbued dwarven chain leggings (bristlebane)": - "/Imbued_Dwarven_Chain_Leggings_(Bristlebane)", - "imbued dwarven chain mail (brell serilis)": - "/Imbued_Dwarven_Chain_Mail_(Brell_Serilis)", - "imbued dwarven chain mail (bristlebane)": - "/Imbued_Dwarven_Chain_Mail_(Bristlebane)", - "imbued dwarven chain mantle (brell serilis)": - "/Imbued_Dwarven_Chain_Mantle_(Brell_Serilis)", - "imbued dwarven chain mantle (bristlebane)": - "/Imbued_Dwarven_Chain_Mantle_(Bristlebane)", - "imbued dwarven chain skirt (brell serilis)": - "/Imbued_Dwarven_Chain_Skirt_(Brell_Serilis)", - "imbued dwarven chain skirt (bristlebane)": - "/Imbued_Dwarven_Chain_Skirt_(Bristlebane)", - "imbued dwarven chain sleeves (brell serilis)": - "/Imbued_Dwarven_Chain_Sleeves_(Brell_Serilis)", - "imbued dwarven chain sleeves (bristlebane)": - "/Imbued_Dwarven_Chain_Sleeves_(Bristlebane)", - "imbued dwarven chain veil (brell serilis)": - "/Imbued_Dwarven_Chain_Veil_(Brell_Serilis)", - "imbued dwarven chain veil (bristlebane)": - "/Imbued_Dwarven_Chain_Veil_(Bristlebane)", + "imbued dwarven chain boots (brell serilis)": "/Imbued_Dwarven_Chain_Boots_(Brell_Serilis)", + "imbued dwarven chain boots (bristlebane)": "/Imbued_Dwarven_Chain_Boots_(Bristlebane)", + "imbued dwarven chain bracelet (brell serilis)": "/Imbued_Dwarven_Chain_Bracelet_(Brell_Serilis)", + "imbued dwarven chain bracelet (bristlebane)": "/Imbued_Dwarven_Chain_Bracelet_(Bristlebane)", + "imbued dwarven chain cloak (brell serilis)": "/Imbued_Dwarven_Chain_Cloak_(Brell_Serilis)", + "imbued dwarven chain cloak (bristlebane)": "/Imbued_Dwarven_Chain_Cloak_(Bristlebane)", + "imbued dwarven chain coif (brell serilis)": "/Imbued_Dwarven_Chain_Coif_(Brell_Serilis)", + "imbued dwarven chain coif (bristlebane)": "/Imbued_Dwarven_Chain_Coif_(Bristlebane)", + "imbued dwarven chain gloves (brell serilis)": "/Imbued_Dwarven_Chain_Gloves_(Brell_Serilis)", + "imbued dwarven chain gloves (bristlebane)": "/Imbued_Dwarven_Chain_Gloves_(Bristlebane)", + "imbued dwarven chain gorget (brell serilis)": "/Imbued_Dwarven_Chain_Gorget_(Brell_Serilis)", + "imbued dwarven chain gorget (bristlebane)": "/Imbued_Dwarven_Chain_Gorget_(Bristlebane)", + "imbued dwarven chain leggings (brell serilis)": "/Imbued_Dwarven_Chain_Leggings_(Brell_Serilis)", + "imbued dwarven chain leggings (bristlebane)": "/Imbued_Dwarven_Chain_Leggings_(Bristlebane)", + "imbued dwarven chain mail (brell serilis)": "/Imbued_Dwarven_Chain_Mail_(Brell_Serilis)", + "imbued dwarven chain mail (bristlebane)": "/Imbued_Dwarven_Chain_Mail_(Bristlebane)", + "imbued dwarven chain mantle (brell serilis)": "/Imbued_Dwarven_Chain_Mantle_(Brell_Serilis)", + "imbued dwarven chain mantle (bristlebane)": "/Imbued_Dwarven_Chain_Mantle_(Bristlebane)", + "imbued dwarven chain skirt (brell serilis)": "/Imbued_Dwarven_Chain_Skirt_(Brell_Serilis)", + "imbued dwarven chain skirt (bristlebane)": "/Imbued_Dwarven_Chain_Skirt_(Bristlebane)", + "imbued dwarven chain sleeves (brell serilis)": "/Imbued_Dwarven_Chain_Sleeves_(Brell_Serilis)", + "imbued dwarven chain sleeves (bristlebane)": "/Imbued_Dwarven_Chain_Sleeves_(Bristlebane)", + "imbued dwarven chain veil (brell serilis)": "/Imbued_Dwarven_Chain_Veil_(Brell_Serilis)", + "imbued dwarven chain veil (bristlebane)": "/Imbued_Dwarven_Chain_Veil_(Bristlebane)", "imbued dwarven plate boots": "/Imbued_Dwarven_Plate_Boots", "imbued dwarven plate bracers": "/Imbued_Dwarven_Plate_Bracers", "imbued dwarven plate collar": "/Imbued_Dwarven_Plate_Collar", @@ -4719,166 +4634,95 @@ export const itemsData = { "imbued elven chainmail sleeves": "/Imbued_Elven_Chainmail_Sleeves", "imbued emerald": "/Imbued_Emerald", "imbued emerald electrum bracelet": "/Imbued_Emerald_Electrum_Bracelet", - "imbued field breastplate (bertoxxulous)": - "/Imbued_Field_Breastplate_(Bertoxxulous)", - "imbued field breastplate (erollisi marr)": - "/Imbued_Field_Breastplate_(Erollisi_Marr)", + "imbued field breastplate (bertoxxulous)": "/Imbued_Field_Breastplate_(Bertoxxulous)", + "imbued field breastplate (erollisi marr)": "/Imbued_Field_Breastplate_(Erollisi_Marr)", "imbued field breastplate (innoruuk)": "/Imbued_Field_Breastplate_(Innoruuk)", "imbued field breastplate (karana)": "/Imbued_Field_Breastplate_(Karana)", - "imbued field breastplate (mithaniel marr)": - "/Imbued_Field_Breastplate_(Mithaniel_Marr)", - "imbued field breastplate (rallos zek)": - "/Imbued_Field_Breastplate_(Rallos_Zek)", - "imbued field breastplate (rodcet nife)": - "/Imbued_Field_Breastplate_(Rodcet_Nife)", - "imbued field plate boots (bertoxxulous)": - "/Imbued_Field_Plate_Boots_(Bertoxxulous)", - "imbued field plate boots (erollisi marr)": - "/Imbued_Field_Plate_Boots_(Erollisi_Marr)", + "imbued field breastplate (mithaniel marr)": "/Imbued_Field_Breastplate_(Mithaniel_Marr)", + "imbued field breastplate (rallos zek)": "/Imbued_Field_Breastplate_(Rallos_Zek)", + "imbued field breastplate (rodcet nife)": "/Imbued_Field_Breastplate_(Rodcet_Nife)", + "imbued field plate boots (bertoxxulous)": "/Imbued_Field_Plate_Boots_(Bertoxxulous)", + "imbued field plate boots (erollisi marr)": "/Imbued_Field_Plate_Boots_(Erollisi_Marr)", "imbued field plate boots (innoruuk)": "/Imbued_Field_Plate_Boots_(Innoruuk)", "imbued field plate boots (karana)": "/Imbued_Field_Plate_Boots_(Karana)", - "imbued field plate boots (mithaniel marr)": - "/Imbued_Field_Plate_Boots_(Mithaniel_Marr)", - "imbued field plate boots (rallos zek)": - "/Imbued_Field_Plate_Boots_(Rallos_Zek)", - "imbued field plate boots (rodcet nife)": - "/Imbued_Field_Plate_Boots_(Rodcet_Nife)", - "imbued field plate bracers (bertoxxulous)": - "/Imbued_Field_Plate_Bracers_(Bertoxxulous)", - "imbued field plate bracers (erollisi marr)": - "/Imbued_Field_Plate_Bracers_(Erollisi_Marr)", - "imbued field plate bracers (innoruuk)": - "/Imbued_Field_Plate_Bracers_(Innoruuk)", + "imbued field plate boots (mithaniel marr)": "/Imbued_Field_Plate_Boots_(Mithaniel_Marr)", + "imbued field plate boots (rallos zek)": "/Imbued_Field_Plate_Boots_(Rallos_Zek)", + "imbued field plate boots (rodcet nife)": "/Imbued_Field_Plate_Boots_(Rodcet_Nife)", + "imbued field plate bracers (bertoxxulous)": "/Imbued_Field_Plate_Bracers_(Bertoxxulous)", + "imbued field plate bracers (erollisi marr)": "/Imbued_Field_Plate_Bracers_(Erollisi_Marr)", + "imbued field plate bracers (innoruuk)": "/Imbued_Field_Plate_Bracers_(Innoruuk)", "imbued field plate bracers (karana)": "/Imbued_Field_Plate_Bracers_(Karana)", - "imbued field plate bracers (mithaniel marr)": - "/Imbued_Field_Plate_Bracers_(Mithaniel_Marr)", - "imbued field plate bracers (rallos zek)": - "/Imbued_Field_Plate_Bracers_(Rallos_Zek)", - "imbued field plate bracers (rodcet nife)": - "/Imbued_Field_Plate_Bracers_(Rodcet_Nife)", - "imbued field plate cloak (bertoxxulous)": - "/Imbued_Field_Plate_Cloak_(Bertoxxulous)", - "imbued field plate cloak (erollisi marr)": - "/Imbued_Field_Plate_Cloak_(Erollisi_Marr)", + "imbued field plate bracers (mithaniel marr)": "/Imbued_Field_Plate_Bracers_(Mithaniel_Marr)", + "imbued field plate bracers (rallos zek)": "/Imbued_Field_Plate_Bracers_(Rallos_Zek)", + "imbued field plate bracers (rodcet nife)": "/Imbued_Field_Plate_Bracers_(Rodcet_Nife)", + "imbued field plate cloak (bertoxxulous)": "/Imbued_Field_Plate_Cloak_(Bertoxxulous)", + "imbued field plate cloak (erollisi marr)": "/Imbued_Field_Plate_Cloak_(Erollisi_Marr)", "imbued field plate cloak (innoruuk)": "/Imbued_Field_Plate_Cloak_(Innoruuk)", "imbued field plate cloak (karana)": "/Imbued_Field_Plate_Cloak_(Karana)", - "imbued field plate cloak (mithaniel marr)": - "/Imbued_Field_Plate_Cloak_(Mithaniel_Marr)", - "imbued field plate cloak (rallos zek)": - "/Imbued_Field_Plate_Cloak_(Rallos_Zek)", - "imbued field plate cloak (rodcet nife)": - "/Imbued_Field_Plate_Cloak_(Rodcet_Nife)", - "imbued field plate collar (bertoxxulous)": - "/Imbued_Field_Plate_Collar_(Bertoxxulous)", - "imbued field plate collar (erollisi marr)": - "/Imbued_Field_Plate_Collar_(Erollisi_Marr)", - "imbued field plate collar (innoruuk)": - "/Imbued_Field_Plate_Collar_(Innoruuk)", + "imbued field plate cloak (mithaniel marr)": "/Imbued_Field_Plate_Cloak_(Mithaniel_Marr)", + "imbued field plate cloak (rallos zek)": "/Imbued_Field_Plate_Cloak_(Rallos_Zek)", + "imbued field plate cloak (rodcet nife)": "/Imbued_Field_Plate_Cloak_(Rodcet_Nife)", + "imbued field plate collar (bertoxxulous)": "/Imbued_Field_Plate_Collar_(Bertoxxulous)", + "imbued field plate collar (erollisi marr)": "/Imbued_Field_Plate_Collar_(Erollisi_Marr)", + "imbued field plate collar (innoruuk)": "/Imbued_Field_Plate_Collar_(Innoruuk)", "imbued field plate collar (karana)": "/Imbued_Field_Plate_Collar_(Karana)", - "imbued field plate collar (mithaniel marr)": - "/Imbued_Field_Plate_Collar_(Mithaniel_Marr)", - "imbued field plate collar (rallos zek)": - "/Imbued_Field_Plate_Collar_(Rallos_Zek)", - "imbued field plate collar (rodcet nife)": - "/Imbued_Field_Plate_Collar_(Rodcet_Nife)", - "imbued field plate gauntlets (bertoxxulous)": - "/Imbued_Field_Plate_Gauntlets_(Bertoxxulous)", - "imbued field plate gauntlets (erollisi marr)": - "/Imbued_Field_Plate_Gauntlets_(Erollisi_Marr)", - "imbued field plate gauntlets (innoruuk)": - "/Imbued_Field_Plate_Gauntlets_(Innoruuk)", - "imbued field plate gauntlets (karana)": - "/Imbued_Field_Plate_Gauntlets_(Karana)", - "imbued field plate gauntlets (mithaniel marr)": - "/Imbued_Field_Plate_Gauntlets_(Mithaniel_Marr)", - "imbued field plate gauntlets (rallos zek)": - "/Imbued_Field_Plate_Gauntlets_(Rallos_Zek)", - "imbued field plate gauntlets (rodcet nife)": - "/Imbued_Field_Plate_Gauntlets_(Rodcet_Nife)", - "imbued field plate girdle (bertoxxulous)": - "/Imbued_Field_Plate_Girdle_(Bertoxxulous)", - "imbued field plate girdle (erollisi marr)": - "/Imbued_Field_Plate_Girdle_(Erollisi_Marr)", - "imbued field plate girdle (innoruuk)": - "/Imbued_Field_Plate_Girdle_(Innoruuk)", + "imbued field plate collar (mithaniel marr)": "/Imbued_Field_Plate_Collar_(Mithaniel_Marr)", + "imbued field plate collar (rallos zek)": "/Imbued_Field_Plate_Collar_(Rallos_Zek)", + "imbued field plate collar (rodcet nife)": "/Imbued_Field_Plate_Collar_(Rodcet_Nife)", + "imbued field plate gauntlets (bertoxxulous)": "/Imbued_Field_Plate_Gauntlets_(Bertoxxulous)", + "imbued field plate gauntlets (erollisi marr)": "/Imbued_Field_Plate_Gauntlets_(Erollisi_Marr)", + "imbued field plate gauntlets (innoruuk)": "/Imbued_Field_Plate_Gauntlets_(Innoruuk)", + "imbued field plate gauntlets (karana)": "/Imbued_Field_Plate_Gauntlets_(Karana)", + "imbued field plate gauntlets (mithaniel marr)": "/Imbued_Field_Plate_Gauntlets_(Mithaniel_Marr)", + "imbued field plate gauntlets (rallos zek)": "/Imbued_Field_Plate_Gauntlets_(Rallos_Zek)", + "imbued field plate gauntlets (rodcet nife)": "/Imbued_Field_Plate_Gauntlets_(Rodcet_Nife)", + "imbued field plate girdle (bertoxxulous)": "/Imbued_Field_Plate_Girdle_(Bertoxxulous)", + "imbued field plate girdle (erollisi marr)": "/Imbued_Field_Plate_Girdle_(Erollisi_Marr)", + "imbued field plate girdle (innoruuk)": "/Imbued_Field_Plate_Girdle_(Innoruuk)", "imbued field plate girdle (karana)": "/Imbued_Field_Plate_Girdle_(Karana)", - "imbued field plate girdle (mithaniel marr)": - "/Imbued_Field_Plate_Girdle_(Mithaniel_Marr)", - "imbued field plate girdle (rallos zek)": - "/Imbued_Field_Plate_Girdle_(Rallos_Zek)", - "imbued field plate girdle (rodcet nife)": - "/Imbued_Field_Plate_Girdle_(Rodcet_Nife)", - "imbued field plate greaves (bertoxxulous)": - "/Imbued_Field_Plate_Greaves_(Bertoxxulous)", - "imbued field plate greaves (erollisi marr)": - "/Imbued_Field_Plate_Greaves_(Erollisi_Marr)", - "imbued field plate greaves (innoruuk)": - "/Imbued_Field_Plate_Greaves_(Innoruuk)", + "imbued field plate girdle (mithaniel marr)": "/Imbued_Field_Plate_Girdle_(Mithaniel_Marr)", + "imbued field plate girdle (rallos zek)": "/Imbued_Field_Plate_Girdle_(Rallos_Zek)", + "imbued field plate girdle (rodcet nife)": "/Imbued_Field_Plate_Girdle_(Rodcet_Nife)", + "imbued field plate greaves (bertoxxulous)": "/Imbued_Field_Plate_Greaves_(Bertoxxulous)", + "imbued field plate greaves (erollisi marr)": "/Imbued_Field_Plate_Greaves_(Erollisi_Marr)", + "imbued field plate greaves (innoruuk)": "/Imbued_Field_Plate_Greaves_(Innoruuk)", "imbued field plate greaves (karana)": "/Imbued_Field_Plate_Greaves_(Karana)", - "imbued field plate greaves (mithaniel marr)": - "/Imbued_Field_Plate_Greaves_(Mithaniel_Marr)", - "imbued field plate greaves (rallos zek)": - "/Imbued_Field_Plate_Greaves_(Rallos_Zek)", - "imbued field plate greaves (rodcet nife)": - "/Imbued_Field_Plate_Greaves_(Rodcet_Nife)", - "imbued field plate helm (bertoxxulous)": - "/Imbued_Field_Plate_Helm_(Bertoxxulous)", - "imbued field plate helm (erollisi marr)": - "/Imbued_Field_Plate_Helm_(Erollisi_Marr)", + "imbued field plate greaves (mithaniel marr)": "/Imbued_Field_Plate_Greaves_(Mithaniel_Marr)", + "imbued field plate greaves (rallos zek)": "/Imbued_Field_Plate_Greaves_(Rallos_Zek)", + "imbued field plate greaves (rodcet nife)": "/Imbued_Field_Plate_Greaves_(Rodcet_Nife)", + "imbued field plate helm (bertoxxulous)": "/Imbued_Field_Plate_Helm_(Bertoxxulous)", + "imbued field plate helm (erollisi marr)": "/Imbued_Field_Plate_Helm_(Erollisi_Marr)", "imbued field plate helm (innoruuk)": "/Imbued_Field_Plate_Helm_(Innoruuk)", "imbued field plate helm (karana)": "/Imbued_Field_Plate_Helm_(Karana)", - "imbued field plate helm (mithaniel marr)": - "/Imbued_Field_Plate_Helm_(Mithaniel_Marr)", - "imbued field plate helm (rallos zek)": - "/Imbued_Field_Plate_Helm_(Rallos_Zek)", - "imbued field plate helm (rodcet nife)": - "/Imbued_Field_Plate_Helm_(Rodcet_Nife)", - "imbued field plate pauldron (bertoxxulous)": - "/Imbued_Field_Plate_Pauldron_(Bertoxxulous)", - "imbued field plate pauldron (erollisi marr)": - "/Imbued_Field_Plate_Pauldron_(Erollisi_Marr)", - "imbued field plate pauldron (innoruuk)": - "/Imbued_Field_Plate_Pauldron_(Innoruuk)", - "imbued field plate pauldron (karana)": - "/Imbued_Field_Plate_Pauldron_(Karana)", - "imbued field plate pauldron (mithaniel marr)": - "/Imbued_Field_Plate_Pauldron_(Mithaniel_Marr)", - "imbued field plate pauldron (rallos zek)": - "/Imbued_Field_Plate_Pauldron_(Rallos_Zek)", - "imbued field plate pauldron (rodcet nife)": - "/Imbued_Field_Plate_Pauldron_(Rodcet_Nife)", - "imbued field plate vambraces (bertoxxulous)": - "/Imbued_Field_Plate_Vambraces_(Bertoxxulous)", - "imbued field plate vambraces (erollisi marr)": - "/Imbued_Field_Plate_Vambraces_(Erollisi_Marr)", - "imbued field plate vambraces (innoruuk)": - "/Imbued_Field_Plate_Vambraces_(Innoruuk)", - "imbued field plate vambraces (karana)": - "/Imbued_Field_Plate_Vambraces_(Karana)", - "imbued field plate vambraces (mithaniel marr)": - "/Imbued_Field_Plate_Vambraces_(Mithaniel_Marr)", - "imbued field plate vambraces (rallos zek)": - "/Imbued_Field_Plate_Vambraces_(Rallos_Zek)", - "imbued field plate vambraces (rodcet nife)": - "/Imbued_Field_Plate_Vambraces_(Rodcet_Nife)", - "imbued field plate visor (bertoxxulous)": - "/Imbued_Field_Plate_Visor_(Bertoxxulous)", - "imbued field plate visor (erollisi marr)": - "/Imbued_Field_Plate_Visor_(Erollisi_Marr)", + "imbued field plate helm (mithaniel marr)": "/Imbued_Field_Plate_Helm_(Mithaniel_Marr)", + "imbued field plate helm (rallos zek)": "/Imbued_Field_Plate_Helm_(Rallos_Zek)", + "imbued field plate helm (rodcet nife)": "/Imbued_Field_Plate_Helm_(Rodcet_Nife)", + "imbued field plate pauldron (bertoxxulous)": "/Imbued_Field_Plate_Pauldron_(Bertoxxulous)", + "imbued field plate pauldron (erollisi marr)": "/Imbued_Field_Plate_Pauldron_(Erollisi_Marr)", + "imbued field plate pauldron (innoruuk)": "/Imbued_Field_Plate_Pauldron_(Innoruuk)", + "imbued field plate pauldron (karana)": "/Imbued_Field_Plate_Pauldron_(Karana)", + "imbued field plate pauldron (mithaniel marr)": "/Imbued_Field_Plate_Pauldron_(Mithaniel_Marr)", + "imbued field plate pauldron (rallos zek)": "/Imbued_Field_Plate_Pauldron_(Rallos_Zek)", + "imbued field plate pauldron (rodcet nife)": "/Imbued_Field_Plate_Pauldron_(Rodcet_Nife)", + "imbued field plate vambraces (bertoxxulous)": "/Imbued_Field_Plate_Vambraces_(Bertoxxulous)", + "imbued field plate vambraces (erollisi marr)": "/Imbued_Field_Plate_Vambraces_(Erollisi_Marr)", + "imbued field plate vambraces (innoruuk)": "/Imbued_Field_Plate_Vambraces_(Innoruuk)", + "imbued field plate vambraces (karana)": "/Imbued_Field_Plate_Vambraces_(Karana)", + "imbued field plate vambraces (mithaniel marr)": "/Imbued_Field_Plate_Vambraces_(Mithaniel_Marr)", + "imbued field plate vambraces (rallos zek)": "/Imbued_Field_Plate_Vambraces_(Rallos_Zek)", + "imbued field plate vambraces (rodcet nife)": "/Imbued_Field_Plate_Vambraces_(Rodcet_Nife)", + "imbued field plate visor (bertoxxulous)": "/Imbued_Field_Plate_Visor_(Bertoxxulous)", + "imbued field plate visor (erollisi marr)": "/Imbued_Field_Plate_Visor_(Erollisi_Marr)", "imbued field plate visor (innoruuk)": "/Imbued_Field_Plate_Visor_(Innoruuk)", "imbued field plate visor (karana)": "/Imbued_Field_Plate_Visor_(Karana)", - "imbued field plate visor (mithaniel marr)": - "/Imbued_Field_Plate_Visor_(Mithaniel_Marr)", - "imbued field plate visor (rallos zek)": - "/Imbued_Field_Plate_Visor_(Rallos_Zek)", - "imbued field plate visor (rodcet nife)": - "/Imbued_Field_Plate_Visor_(Rodcet_Nife)", + "imbued field plate visor (mithaniel marr)": "/Imbued_Field_Plate_Visor_(Mithaniel_Marr)", + "imbued field plate visor (rallos zek)": "/Imbued_Field_Plate_Visor_(Rallos_Zek)", + "imbued field plate visor (rodcet nife)": "/Imbued_Field_Plate_Visor_(Rodcet_Nife)", "imbued fighters staff": "/Imbued_Fighters_Staff", "imbued fire opal": "/Imbued_Fire_Opal", "imbued golden amber earring": "/Imbued_Golden_Amber_Earring", "imbued golden black pearl choker": "/Imbued_Golden_Black_Pearl_Choker", - "imbued golden black sapphire earring": - "/Imbued_Golden_Black_Sapphire_Earring", + "imbued golden black sapphire earring": "/Imbued_Golden_Black_Sapphire_Earring", "imbued golden diamond mask": "/Imbued_Golden_Diamond_Mask", "imbued golden emerald bracelet": "/Imbued_Golden_Emerald_Bracelet", "imbued golden fire ring": "/Imbued_Golden_Fire_Ring", @@ -4954,41 +4798,28 @@ export const itemsData = { "imbued northman ring sleeves": "/Imbued_Northman_Ring_Sleeves", "imbued ogre war boots (cazic thule)": "/Imbued_Ogre_War_Boots_(Cazic_Thule)", "imbued ogre war boots (rallos zek)": "/Imbued_Ogre_War_Boots_(Rallos_Zek)", - "imbued ogre war bracer (cazic thule)": - "/Imbued_Ogre_War_Bracer_(Cazic_Thule)", + "imbued ogre war bracer (cazic thule)": "/Imbued_Ogre_War_Bracer_(Cazic_Thule)", "imbued ogre war bracer (rallos zek)": "/Imbued_Ogre_War_Bracer_(Rallos_Zek)", - "imbued ogre war breastplate (cazic thule)": - "/Imbued_Ogre_War_Breastplate_(Cazic_Thule)", - "imbued ogre war breastplate (rallos zek)": - "/Imbued_Ogre_War_Breastplate_(Rallos_Zek)", + "imbued ogre war breastplate (cazic thule)": "/Imbued_Ogre_War_Breastplate_(Cazic_Thule)", + "imbued ogre war breastplate (rallos zek)": "/Imbued_Ogre_War_Breastplate_(Rallos_Zek)", "imbued ogre war cloak (cazic thule)": "/Imbued_Ogre_War_Cloak_(Cazic_Thule)", "imbued ogre war cloak (rallos zek)": "/Imbued_Ogre_War_Cloak_(Rallos_Zek)", - "imbued ogre war collar (cazic thule)": - "/Imbued_Ogre_War_Collar_(Cazic_Thule)", + "imbued ogre war collar (cazic thule)": "/Imbued_Ogre_War_Collar_(Cazic_Thule)", "imbued ogre war collar (rallos zek)": "/Imbued_Ogre_War_Collar_(Rallos_Zek)", - "imbued ogre war gauntlets (cazic thule)": - "/Imbued_Ogre_War_Gauntlets_(Cazic_Thule)", - "imbued ogre war gauntlets (rallos zek)": - "/Imbued_Ogre_War_Gauntlets_(Rallos_Zek)", - "imbued ogre war girdle (cazic thule)": - "/Imbued_Ogre_War_Girdle_(Cazic_Thule)", + "imbued ogre war gauntlets (cazic thule)": "/Imbued_Ogre_War_Gauntlets_(Cazic_Thule)", + "imbued ogre war gauntlets (rallos zek)": "/Imbued_Ogre_War_Gauntlets_(Rallos_Zek)", + "imbued ogre war girdle (cazic thule)": "/Imbued_Ogre_War_Girdle_(Cazic_Thule)", "imbued ogre war girdle (rallos zek)": "/Imbued_Ogre_War_Girdle_(Rallos_Zek)", - "imbued ogre war greaves (cazic thule)": - "/Imbued_Ogre_War_Greaves_(Cazic_Thule)", - "imbued ogre war greaves (rallos zek)": - "/Imbued_Ogre_War_Greaves_(Rallos_Zek)", + "imbued ogre war greaves (cazic thule)": "/Imbued_Ogre_War_Greaves_(Cazic_Thule)", + "imbued ogre war greaves (rallos zek)": "/Imbued_Ogre_War_Greaves_(Rallos_Zek)", "imbued ogre war hammer": "/Imbued_Ogre_War_Hammer", "imbued ogre war helm (cazic thule)": "/Imbued_Ogre_War_Helm_(Cazic_Thule)", "imbued ogre war helm (rallos zek)": "/Imbued_Ogre_War_Helm_(Rallos_Zek)", "imbued ogre war mace": "/Imbued_Ogre_War_Mace", - "imbued ogre war pauldron (cazic thule)": - "/Imbued_Ogre_War_Pauldron_(Cazic_Thule)", - "imbued ogre war pauldron (rallos zek)": - "/Imbued_Ogre_War_Pauldron_(Rallos_Zek)", - "imbued ogre war vambraces (cazic thule)": - "/Imbued_Ogre_War_Vambraces_(Cazic_Thule)", - "imbued ogre war vambraces (rallos zek)": - "/Imbued_Ogre_War_Vambraces_(Rallos_Zek)", + "imbued ogre war pauldron (cazic thule)": "/Imbued_Ogre_War_Pauldron_(Cazic_Thule)", + "imbued ogre war pauldron (rallos zek)": "/Imbued_Ogre_War_Pauldron_(Rallos_Zek)", + "imbued ogre war vambraces (cazic thule)": "/Imbued_Ogre_War_Vambraces_(Cazic_Thule)", + "imbued ogre war vambraces (rallos zek)": "/Imbued_Ogre_War_Vambraces_(Rallos_Zek)", "imbued ogre war visor (cazic thule)": "/Imbued_Ogre_War_Visor_(Cazic_Thule)", "imbued ogre war visor (rallos zek)": "/Imbued_Ogre_War_Visor_(Rallos_Zek)", "imbued opal": "/Imbued_Opal", @@ -5025,60 +4856,42 @@ export const itemsData = { "imbued skyiron fer`esh": "/Imbued_Skyiron_Fer%60Esh", "imbued skyiron shan`tok": "/Imbued_Skyiron_Shan%60Tok", "imbued skyiron sheer blade": "/Imbued_Skyiron_Sheer_Blade", - "imbued steelsilk boots (cazic thule)": - "/Imbued_Steelsilk_Boots_(Cazic_Thule)", + "imbued steelsilk boots (cazic thule)": "/Imbued_Steelsilk_Boots_(Cazic_Thule)", "imbued steelsilk boots (prexus)": "/Imbued_Steelsilk_Boots_(Prexus)", "imbued steelsilk boots (quellious)": "/Imbued_Steelsilk_Boots_(Quellious)", - "imbued steelsilk bracers (cazic thule)": - "/Imbued_Steelsilk_Bracers_(Cazic_Thule)", + "imbued steelsilk bracers (cazic thule)": "/Imbued_Steelsilk_Bracers_(Cazic_Thule)", "imbued steelsilk bracers (prexus)": "/Imbued_Steelsilk_Bracers_(Prexus)", - "imbued steelsilk bracers (quellious)": - "/Imbued_Steelsilk_Bracers_(Quellious)", - "imbued steelsilk breastplate (cazic thule)": - "/Imbued_Steelsilk_Breastplate_(Cazic_Thule)", - "imbued steelsilk breastplate (prexus)": - "/Imbued_Steelsilk_Breastplate_(Prexus)", - "imbued steelsilk breastplate (quellious)": - "/Imbued_Steelsilk_Breastplate_(Quellious)", - "imbued steelsilk cloak (cazic thule)": - "/Imbued_Steelsilk_Cloak_(Cazic_Thule)", + "imbued steelsilk bracers (quellious)": "/Imbued_Steelsilk_Bracers_(Quellious)", + "imbued steelsilk breastplate (cazic thule)": "/Imbued_Steelsilk_Breastplate_(Cazic_Thule)", + "imbued steelsilk breastplate (prexus)": "/Imbued_Steelsilk_Breastplate_(Prexus)", + "imbued steelsilk breastplate (quellious)": "/Imbued_Steelsilk_Breastplate_(Quellious)", + "imbued steelsilk cloak (cazic thule)": "/Imbued_Steelsilk_Cloak_(Cazic_Thule)", "imbued steelsilk cloak (prexus)": "/Imbued_Steelsilk_Cloak_(Prexus)", "imbued steelsilk cloak (quellious)": "/Imbued_Steelsilk_Cloak_(Quellious)", - "imbued steelsilk collar (cazic thule)": - "/Imbued_Steelsilk_Collar_(Cazic_Thule)", + "imbued steelsilk collar (cazic thule)": "/Imbued_Steelsilk_Collar_(Cazic_Thule)", "imbued steelsilk collar (prexus)": "/Imbued_Steelsilk_Collar_(Prexus)", "imbued steelsilk collar (quellious)": "/Imbued_Steelsilk_Collar_(Quellious)", - "imbued steelsilk gauntlets (cazic thule)": - "/Imbued_Steelsilk_Gauntlets_(Cazic_Thule)", + "imbued steelsilk gauntlets (cazic thule)": "/Imbued_Steelsilk_Gauntlets_(Cazic_Thule)", "imbued steelsilk gauntlets (prexus)": "/Imbued_Steelsilk_Gauntlets_(Prexus)", - "imbued steelsilk gauntlets (quellious)": - "/Imbued_Steelsilk_Gauntlets_(Quellious)", - "imbued steelsilk greaves (cazic thule)": - "/Imbued_Steelsilk_Greaves_(Cazic_Thule)", + "imbued steelsilk gauntlets (quellious)": "/Imbued_Steelsilk_Gauntlets_(Quellious)", + "imbued steelsilk greaves (cazic thule)": "/Imbued_Steelsilk_Greaves_(Cazic_Thule)", "imbued steelsilk greaves (prexus)": "/Imbued_Steelsilk_Greaves_(Prexus)", - "imbued steelsilk greaves (quellious)": - "/Imbued_Steelsilk_Greaves_(Quellious)", + "imbued steelsilk greaves (quellious)": "/Imbued_Steelsilk_Greaves_(Quellious)", "imbued steelsilk helm (cazic thule)": "/Imbued_Steelsilk_Helm_(Cazic_Thule)", "imbued steelsilk helm (prexus)": "/Imbued_Steelsilk_Helm_(Prexus)", "imbued steelsilk helm (quellious)": "/Imbued_Steelsilk_Helm_(Quellious)", "imbued steelsilk mask (cazic thule)": "/Imbued_Steelsilk_Mask_(Cazic_Thule)", "imbued steelsilk mask (prexus)": "/Imbued_Steelsilk_Mask_(Prexus)", "imbued steelsilk mask (quellious)": "/Imbued_Steelsilk_Mask_(Quellious)", - "imbued steelsilk pauldron (cazic thule)": - "/Imbued_Steelsilk_Pauldron_(Cazic_Thule)", + "imbued steelsilk pauldron (cazic thule)": "/Imbued_Steelsilk_Pauldron_(Cazic_Thule)", "imbued steelsilk pauldron (prexus)": "/Imbued_Steelsilk_Pauldron_(Prexus)", - "imbued steelsilk pauldron (quellious)": - "/Imbued_Steelsilk_Pauldron_(Quellious)", - "imbued steelsilk vambraces (cazic thule)": - "/Imbued_Steelsilk_Vambraces_(Cazic_Thule)", + "imbued steelsilk pauldron (quellious)": "/Imbued_Steelsilk_Pauldron_(Quellious)", + "imbued steelsilk vambraces (cazic thule)": "/Imbued_Steelsilk_Vambraces_(Cazic_Thule)", "imbued steelsilk vambraces (prexus)": "/Imbued_Steelsilk_Vambraces_(Prexus)", - "imbued steelsilk vambraces (quellious)": - "/Imbued_Steelsilk_Vambraces_(Quellious)", - "imbued steelsilk waistband (cazic thule)": - "/Imbued_Steelsilk_Waistband_(Cazic_Thule)", + "imbued steelsilk vambraces (quellious)": "/Imbued_Steelsilk_Vambraces_(Quellious)", + "imbued steelsilk waistband (cazic thule)": "/Imbued_Steelsilk_Waistband_(Cazic_Thule)", "imbued steelsilk waistband (prexus)": "/Imbued_Steelsilk_Waistband_(Prexus)", - "imbued steelsilk waistband (quellious)": - "/Imbued_Steelsilk_Waistband_(Quellious)", + "imbued steelsilk waistband (quellious)": "/Imbued_Steelsilk_Waistband_(Quellious)", "imbued teir`dal chain bracelet": "/Imbued_Teir%60Dal_Chain_Bracelet", "imbued teir`dal chain cape": "/Imbued_Teir%60Dal_Chain_Cape", "imbued teir`dal chain coif": "/Imbued_Teir%60Dal_Chain_Coif", @@ -6583,54 +6396,30 @@ export const itemsData = { "ogre butcher apron": "/Ogre_Butcher_Apron", "ogre butcher gloves": "/Ogre_Butcher_Gloves", "ogre head": "/Ogre_Head", - "ogre imbued splint belt (cazic thule)": - "/Ogre_Imbued_Splint_Belt_(Cazic_Thule)", - "ogre imbued splint belt (rallos zek)": - "/Ogre_Imbued_Splint_Belt_(Rallos_Zek)", - "ogre imbued splint boots (cazic thule)": - "/Ogre_Imbued_Splint_Boots_(Cazic_Thule)", - "ogre imbued splint boots (rallos zek)": - "/Ogre_Imbued_Splint_Boots_(Rallos_Zek)", - "ogre imbued splint bracer (cazic thule)": - "/Ogre_Imbued_Splint_Bracer_(Cazic_Thule)", - "ogre imbued splint bracer (rallos zek)": - "/Ogre_Imbued_Splint_Bracer_(Rallos_Zek)", - "ogre imbued splint cloak (cazic thule)": - "/Ogre_Imbued_Splint_Cloak_(Cazic_Thule)", - "ogre imbued splint cloak (rallos zek)": - "/Ogre_Imbued_Splint_Cloak_(Rallos_Zek)", - "ogre imbued splint gauntlets (cazic thule)": - "/Ogre_Imbued_Splint_Gauntlets_(Cazic_Thule)", - "ogre imbued splint gauntlets (rallos zek)": - "/Ogre_Imbued_Splint_Gauntlets_(Rallos_Zek)", - "ogre imbued splint gorget (cazic thule)": - "/Ogre_Imbued_Splint_Gorget_(Cazic_Thule)", - "ogre imbued splint gorget (rallos zek)": - "/Ogre_Imbued_Splint_Gorget_(Rallos_Zek)", - "ogre imbued splint helm (cazic thule)": - "/Ogre_Imbued_Splint_Helm_(Cazic_Thule)", - "ogre imbued splint helm (rallos zek)": - "/Ogre_Imbued_Splint_Helm_(Rallos_Zek)", - "ogre imbued splint leggings (cazic thule)": - "/Ogre_Imbued_Splint_Leggings_(Cazic_Thule)", - "ogre imbued splint leggings (rallos zek)": - "/Ogre_Imbued_Splint_Leggings_(Rallos_Zek)", - "ogre imbued splint mail (cazic thule)": - "/Ogre_Imbued_Splint_Mail_(Cazic_Thule)", - "ogre imbued splint mail (rallos zek)": - "/Ogre_Imbued_Splint_Mail_(Rallos_Zek)", - "ogre imbued splint mantle (cazic thule)": - "/Ogre_Imbued_Splint_Mantle_(Cazic_Thule)", - "ogre imbued splint mantle (rallos zek)": - "/Ogre_Imbued_Splint_Mantle_(Rallos_Zek)", - "ogre imbued splint mask (cazic thule)": - "/Ogre_Imbued_Splint_Mask_(Cazic_Thule)", - "ogre imbued splint mask (rallos zek)": - "/Ogre_Imbued_Splint_Mask_(Rallos_Zek)", - "ogre imbued splint sleeves (cazic thule)": - "/Ogre_Imbued_Splint_Sleeves_(Cazic_Thule)", - "ogre imbued splint sleeves (rallos zek)": - "/Ogre_Imbued_Splint_Sleeves_(Rallos_Zek)", + "ogre imbued splint belt (cazic thule)": "/Ogre_Imbued_Splint_Belt_(Cazic_Thule)", + "ogre imbued splint belt (rallos zek)": "/Ogre_Imbued_Splint_Belt_(Rallos_Zek)", + "ogre imbued splint boots (cazic thule)": "/Ogre_Imbued_Splint_Boots_(Cazic_Thule)", + "ogre imbued splint boots (rallos zek)": "/Ogre_Imbued_Splint_Boots_(Rallos_Zek)", + "ogre imbued splint bracer (cazic thule)": "/Ogre_Imbued_Splint_Bracer_(Cazic_Thule)", + "ogre imbued splint bracer (rallos zek)": "/Ogre_Imbued_Splint_Bracer_(Rallos_Zek)", + "ogre imbued splint cloak (cazic thule)": "/Ogre_Imbued_Splint_Cloak_(Cazic_Thule)", + "ogre imbued splint cloak (rallos zek)": "/Ogre_Imbued_Splint_Cloak_(Rallos_Zek)", + "ogre imbued splint gauntlets (cazic thule)": "/Ogre_Imbued_Splint_Gauntlets_(Cazic_Thule)", + "ogre imbued splint gauntlets (rallos zek)": "/Ogre_Imbued_Splint_Gauntlets_(Rallos_Zek)", + "ogre imbued splint gorget (cazic thule)": "/Ogre_Imbued_Splint_Gorget_(Cazic_Thule)", + "ogre imbued splint gorget (rallos zek)": "/Ogre_Imbued_Splint_Gorget_(Rallos_Zek)", + "ogre imbued splint helm (cazic thule)": "/Ogre_Imbued_Splint_Helm_(Cazic_Thule)", + "ogre imbued splint helm (rallos zek)": "/Ogre_Imbued_Splint_Helm_(Rallos_Zek)", + "ogre imbued splint leggings (cazic thule)": "/Ogre_Imbued_Splint_Leggings_(Cazic_Thule)", + "ogre imbued splint leggings (rallos zek)": "/Ogre_Imbued_Splint_Leggings_(Rallos_Zek)", + "ogre imbued splint mail (cazic thule)": "/Ogre_Imbued_Splint_Mail_(Cazic_Thule)", + "ogre imbued splint mail (rallos zek)": "/Ogre_Imbued_Splint_Mail_(Rallos_Zek)", + "ogre imbued splint mantle (cazic thule)": "/Ogre_Imbued_Splint_Mantle_(Cazic_Thule)", + "ogre imbued splint mantle (rallos zek)": "/Ogre_Imbued_Splint_Mantle_(Rallos_Zek)", + "ogre imbued splint mask (cazic thule)": "/Ogre_Imbued_Splint_Mask_(Cazic_Thule)", + "ogre imbued splint mask (rallos zek)": "/Ogre_Imbued_Splint_Mask_(Rallos_Zek)", + "ogre imbued splint sleeves (cazic thule)": "/Ogre_Imbued_Splint_Sleeves_(Cazic_Thule)", + "ogre imbued splint sleeves (rallos zek)": "/Ogre_Imbued_Splint_Sleeves_(Rallos_Zek)", "ogre meat cleaver": "/Ogre_Meat_Cleaver", "ogre splintmail belt": "/Ogre_Splintmail_Belt", "ogre splintmail boots": "/Ogre_Splintmail_Boots", @@ -6819,20 +6608,14 @@ export const itemsData = { "part of a large key": "/Part_of_a_Large_Key", "part of potion of marr": "/Part_of_Potion_of_Marr", "part of tasarin's grimoire pg. 23": "/Part_of_Tasarin%27s_Grimoire_Pg._23", - "part of tasarin's grimoire pg. 23 (left)": - "/Part_of_Tasarin%27s_Grimoire_Pg._23_(Left)", - "part of tasarin's grimoire pg. 23 (right)": - "/Part_of_Tasarin%27s_Grimoire_Pg._23_(Right)", + "part of tasarin's grimoire pg. 23 (left)": "/Part_of_Tasarin%27s_Grimoire_Pg._23_(Left)", + "part of tasarin's grimoire pg. 23 (right)": "/Part_of_Tasarin%27s_Grimoire_Pg._23_(Right)", "part of tasarin's grimoire pg. 24": "/Part_of_Tasarin%27s_Grimoire_Pg._24", - "part of tasarin's grimoire pg. 24 (left)": - "/Part_of_Tasarin%27s_Grimoire_Pg._24_(Left)", - "part of tasarin's grimoire pg. 24 (right)": - "/Part_of_Tasarin%27s_Grimoire_Pg._24_(Right)", + "part of tasarin's grimoire pg. 24 (left)": "/Part_of_Tasarin%27s_Grimoire_Pg._24_(Left)", + "part of tasarin's grimoire pg. 24 (right)": "/Part_of_Tasarin%27s_Grimoire_Pg._24_(Right)", "part of tasarin's grimoire pg. 26": "/Part_of_Tasarin%27s_Grimoire_Pg._26", - "part of tasarin's grimoire pg. 26 (left)": - "/Part_of_Tasarin%27s_Grimoire_Pg._26_(Left)", - "part of tasarin's grimoire pg. 26 (right)": - "/Part_of_Tasarin%27s_Grimoire_Pg._26_(Right)", + "part of tasarin's grimoire pg. 26 (left)": "/Part_of_Tasarin%27s_Grimoire_Pg._26_(Left)", + "part of tasarin's grimoire pg. 26 (right)": "/Part_of_Tasarin%27s_Grimoire_Pg._26_(Right)", "part of tasarin's grimoire pg. 30": "/Part_of_Tasarin%27s_Grimoire_Pg._30", "part of tasarin's grimoire pg. 312": "/Part_of_Tasarin%27s_Grimoire_Pg._312", "part of tasarin's grimoire pg. 375": "/Part_of_Tasarin%27s_Grimoire_Pg._375", @@ -8304,8 +8087,7 @@ export const itemsData = { "shaped darkwood 1-cam bow (linen)": "/Shaped_Darkwood_1-Cam_Bow_(Linen)", "shaped darkwood 1-cam bow (silk)": "/Shaped_Darkwood_1-Cam_Bow_(Silk)", "shaped darkwood compound bow (hemp)": "/Shaped_Darkwood_Compound_Bow_(Hemp)", - "shaped darkwood compound bow (linen)": - "/Shaped_Darkwood_Compound_Bow_(Linen)", + "shaped darkwood compound bow (linen)": "/Shaped_Darkwood_Compound_Bow_(Linen)", "shaped darkwood compound bow (silk)": "/Shaped_Darkwood_Compound_Bow_(Silk)", "shaped darkwood recurve bow (hemp)": "/Shaped_Darkwood_Recurve_Bow_(Hemp)", "shaped darkwood recurve bow (linen)": "/Shaped_Darkwood_Recurve_Bow_(Linen)", @@ -9560,62 +9342,41 @@ export const itemsData = { "tears of erollisi": "/Tears_of_Erollisi", "tears of prexus": "/Tears_of_Prexus", "teir`dal adamantite boots": "/Teir%60Dal_Adamantite_Boots", - "teir`dal adamantite boots (enchanted)": - "/Teir%60Dal_Adamantite_Boots_(Enchanted)", + "teir`dal adamantite boots (enchanted)": "/Teir%60Dal_Adamantite_Boots_(Enchanted)", "teir`dal adamantite boots (imbued)": "/Teir%60Dal_Adamantite_Boots_(Imbued)", "teir`dal adamantite bracers": "/Teir%60Dal_Adamantite_Bracers", - "teir`dal adamantite bracers (enchanted)": - "/Teir%60Dal_Adamantite_Bracers_(Enchanted)", - "teir`dal adamantite bracers (imbued)": - "/Teir%60Dal_Adamantite_Bracers_(Imbued)", + "teir`dal adamantite bracers (enchanted)": "/Teir%60Dal_Adamantite_Bracers_(Enchanted)", + "teir`dal adamantite bracers (imbued)": "/Teir%60Dal_Adamantite_Bracers_(Imbued)", "teir`dal adamantite breastplate": "/Teir%60Dal_Adamantite_Breastplate", - "teir`dal adamantite breastplate (enchanted)": - "/Teir%60Dal_Adamantite_Breastplate_(Enchanted)", - "teir`dal adamantite breastplate (imbued)": - "/Teir%60Dal_Adamantite_Breastplate_(Imbued)", + "teir`dal adamantite breastplate (enchanted)": "/Teir%60Dal_Adamantite_Breastplate_(Enchanted)", + "teir`dal adamantite breastplate (imbued)": "/Teir%60Dal_Adamantite_Breastplate_(Imbued)", "teir`dal adamantite cloak": "/Teir%60Dal_Adamantite_Cloak", - "teir`dal adamantite cloak (enchanted)": - "/Teir%60Dal_Adamantite_Cloak_(Enchanted)", + "teir`dal adamantite cloak (enchanted)": "/Teir%60Dal_Adamantite_Cloak_(Enchanted)", "teir`dal adamantite cloak (imbued)": "/Teir%60Dal_Adamantite_Cloak_(Imbued)", "teir`dal adamantite collar": "/Teir%60Dal_Adamantite_Collar", - "teir`dal adamantite collar (enchanted)": - "/Teir%60Dal_Adamantite_Collar_(Enchanted)", - "teir`dal adamantite collar (imbued)": - "/Teir%60Dal_Adamantite_Collar_(Imbued)", + "teir`dal adamantite collar (enchanted)": "/Teir%60Dal_Adamantite_Collar_(Enchanted)", + "teir`dal adamantite collar (imbued)": "/Teir%60Dal_Adamantite_Collar_(Imbued)", "teir`dal adamantite gauntlets": "/Teir%60Dal_Adamantite_Gauntlets", - "teir`dal adamantite gauntlets (enchanted)": - "/Teir%60Dal_Adamantite_Gauntlets_(Enchanted)", - "teir`dal adamantite gauntlets (imbued)": - "/Teir%60Dal_Adamantite_Gauntlets_(Imbued)", + "teir`dal adamantite gauntlets (enchanted)": "/Teir%60Dal_Adamantite_Gauntlets_(Enchanted)", + "teir`dal adamantite gauntlets (imbued)": "/Teir%60Dal_Adamantite_Gauntlets_(Imbued)", "teir`dal adamantite girdle": "/Teir%60Dal_Adamantite_Girdle", - "teir`dal adamantite girdle (enchanted)": - "/Teir%60Dal_Adamantite_Girdle_(Enchanted)", - "teir`dal adamantite girdle (imbued)": - "/Teir%60Dal_Adamantite_Girdle_(Imbued)", + "teir`dal adamantite girdle (enchanted)": "/Teir%60Dal_Adamantite_Girdle_(Enchanted)", + "teir`dal adamantite girdle (imbued)": "/Teir%60Dal_Adamantite_Girdle_(Imbued)", "teir`dal adamantite greaves": "/Teir%60Dal_Adamantite_Greaves", - "teir`dal adamantite greaves (dropped)": - "/Teir%60Dal_Adamantite_Greaves_(Dropped)", - "teir`dal adamantite greaves (enchanted)": - "/Teir%60Dal_Adamantite_Greaves_(Enchanted)", - "teir`dal adamantite greaves (imbued)": - "/Teir%60Dal_Adamantite_Greaves_(Imbued)", + "teir`dal adamantite greaves (dropped)": "/Teir%60Dal_Adamantite_Greaves_(Dropped)", + "teir`dal adamantite greaves (enchanted)": "/Teir%60Dal_Adamantite_Greaves_(Enchanted)", + "teir`dal adamantite greaves (imbued)": "/Teir%60Dal_Adamantite_Greaves_(Imbued)", "teir`dal adamantite helm": "/Teir%60Dal_Adamantite_Helm", - "teir`dal adamantite helm (enchanted)": - "/Teir%60Dal_Adamantite_Helm_(Enchanted)", + "teir`dal adamantite helm (enchanted)": "/Teir%60Dal_Adamantite_Helm_(Enchanted)", "teir`dal adamantite helm (imbued)": "/Teir%60Dal_Adamantite_Helm_(Imbued)", "teir`dal adamantite pauldron": "/Teir%60Dal_Adamantite_Pauldron", - "teir`dal adamantite pauldron (enchanted)": - "/Teir%60Dal_Adamantite_Pauldron_(Enchanted)", - "teir`dal adamantite pauldron (imbued)": - "/Teir%60Dal_Adamantite_Pauldron_(Imbued)", + "teir`dal adamantite pauldron (enchanted)": "/Teir%60Dal_Adamantite_Pauldron_(Enchanted)", + "teir`dal adamantite pauldron (imbued)": "/Teir%60Dal_Adamantite_Pauldron_(Imbued)", "teir`dal adamantite vambraces": "/Teir%60Dal_Adamantite_Vambraces", - "teir`dal adamantite vambraces (enchanted)": - "/Teir%60Dal_Adamantite_Vambraces_(Enchanted)", - "teir`dal adamantite vambraces (imbued)": - "/Teir%60Dal_Adamantite_Vambraces_(Imbued)", + "teir`dal adamantite vambraces (enchanted)": "/Teir%60Dal_Adamantite_Vambraces_(Enchanted)", + "teir`dal adamantite vambraces (imbued)": "/Teir%60Dal_Adamantite_Vambraces_(Imbued)", "teir`dal adamantite visor": "/Teir%60Dal_Adamantite_Visor", - "teir`dal adamantite visor (enchanted)": - "/Teir%60Dal_Adamantite_Visor_(Enchanted)", + "teir`dal adamantite visor (enchanted)": "/Teir%60Dal_Adamantite_Visor_(Enchanted)", "teir`dal adamantite visor (imbued)": "/Teir%60Dal_Adamantite_Visor_(Imbued)", "teir`dal blood pact": "/Teir%60Dal_Blood_Pact", "teir`dal chain coif": "/Teir%60Dal_Chain_Coif", diff --git a/src/shared/logger.ts b/src/shared/logger.ts index c5895e5..bdf2f91 100644 --- a/src/shared/logger.ts +++ b/src/shared/logger.ts @@ -1,5 +1,5 @@ export const log = (message: string) => { - const now = new Date(); - const utcString = now.toUTCString(); - console.log(`[${utcString}] ${message}`); -}; \ No newline at end of file + const now = new Date(); + const utcString = now.toUTCString(); + console.log(`[${utcString}] ${message}`); +}; diff --git a/src/test/app-test-config.ts b/src/test/app-test-config.ts new file mode 100644 index 0000000..f11bbdf --- /dev/null +++ b/src/test/app-test-config.ts @@ -0,0 +1,33 @@ +/** + * Application-specific test configuration + * This contains bot-specific defaults that should not be in the generic test infrastructure + */ + +import { + DiscordEnvironmentOptions, + createDiscordEnvironment, +} from "./discord-testing-library/create-discord-environment"; + +/** + * Default configuration for this Discord bot's tests + * Includes channels, users, and other bot-specific setup + */ +export const DEFAULT_BOT_TEST_CONFIG: DiscordEnvironmentOptions = { + guildName: "Castle Guild", + defaultUsers: ["testuser"], + defaultChannels: [ + { name: "general", type: "text" }, + { name: "request-dump", id: "111222333", type: "thread" }, // Bot-specific channel + ], +}; + +/** + * Creates a Discord environment with bot-specific defaults + * Use this instead of createDiscordEnvironment() directly in bot tests + */ +export function createBotTestEnvironment(overrides: DiscordEnvironmentOptions = {}) { + return createDiscordEnvironment({ + ...DEFAULT_BOT_TEST_CONFIG, + ...overrides, + }); +} diff --git a/src/test/discord-testing-library/README.md b/src/test/discord-testing-library/README.md new file mode 100644 index 0000000..35ea9de --- /dev/null +++ b/src/test/discord-testing-library/README.md @@ -0,0 +1,177 @@ +# Discord Testing Library + +A comprehensive testing framework for Discord bots that provides a Testing Library-style API for Discord bot testing. + +## Features + +- ✅ **Realistic Discord environment simulation** - Full Discord object hierarchies and relationships +- ✅ **User interaction simulation** - High-level methods like `user.clickButton()` +- ✅ **Real event flow** - Interactions go through your actual Discord listeners +- ✅ **Enhanced assertions** - Works with existing Jest matchers plus Discord-specific ones +- ✅ **Beautiful, readable tests** - Clean API that focuses on user workflows + +## Quick Start + +```typescript +import { createDiscordTest } from '../test/discord-testing-library'; + +describe('My Discord Feature', () => { + it('handles user interactions', async () => { + // Create test environment + const discord = createDiscordTest(); + const guild = discord.createGuild('Test Guild'); + const user = guild.createUser('testuser'); + const channel = guild.createChannel('general'); + + // Run bot setup + await discord.withClient(client => myBotSetup(client)); + + // Simulate user interaction + await user.clickButton('my-button', guild, discord.client); + + // Assert results + expect(user).toHaveSentDm(/success/); + expect(channel).toHaveSentMessage(/notification/); + }); +}); +``` + +## API Reference + +### `createDiscordTest()` + +Creates a new Discord test environment. + +```typescript +const discord = createDiscordTest(); +``` + +### `DiscordTestEnvironment` + +#### `createGuild(name: string, options?: { id?: string }): MockGuild` + +Creates a guild in the test environment. + +#### `withClient(fn: (client: Client) => T | Promise): Promise` + +Executes a function with the test environment's Discord client. + +### `MockGuild` + +#### `createUser(username: string, options?: { id?: string }): MockUser` + +Creates a user in this guild. + +#### `createChannel(name: string, options?: { id?: string; type?: 'text' | 'thread' }): MockChannel` + +Creates a channel in this guild. + +### `MockUser` + +#### `clickButton(customId: string, guild: MockGuild, client: Client): Promise` + +Simulates the user clicking a Discord button. This creates a realistic button interaction and routes it through your actual interaction listeners. + +#### `lastInteraction` + +Access to the most recent interaction mocks for testing error handling: + +```typescript +await user.clickButton('broken-button', guild, discord.client); +expect(user.lastInteraction?.editReply).toHaveBeenCalledWith({ + content: 'Error: Something went wrong' +}); +``` + +### `MockChannel` + +Channel mock with Discord.js-compatible interface plus testing enhancements. + +## Testing Patterns + +### Basic Workflow Testing + +```typescript +it('handles complete user workflow', async () => { + const discord = createDiscordTest(); + const guild = discord.createGuild('Test Guild'); + const user = guild.createUser('testuser'); + const channel = guild.createChannel('announcements'); + + // Bot setup + await discord.withClient(client => setupAnnouncements(client)); + + // User action + await user.clickButton('announce', guild, discord.client); + + // Verify results + expect(user).toHaveSentDm(/confirmation/); + expect(channel).toHaveSentMessage(/announcement/); +}); +``` + +### Error Handling Testing + +```typescript +it('handles errors gracefully', async () => { + const discord = createDiscordTest(); + const guild = discord.createGuild('Test Guild'); + const user = guild.createUser('testuser'); + // Don't create required channel + + await user.clickButton('needs-channel', guild, discord.client); + + expect(user.lastInteraction?.editReply).toHaveBeenCalledWith({ + content: 'Error: Channel not found' + }); +}); +``` + +### Bot Setup Testing + +```typescript +it('creates proper Discord components', async () => { + const discord = createDiscordTest(); + + await discord.withClient(client => setupMyFeature(client)); + + // Use existing assertion helpers + expectButtonCreated('my-button', 'Click Me'); + expectEmbedCreated('My Feature'); +}); +``` + +## Migration from Old Test System + +The Discord Testing Library replaces the old `when()` helper system with a more comprehensive and intuitive API: + +### Before (Old System) +```typescript +when("handling feature", ({ it }) => { + it("does something", async ({ user, guild }) => { + // Complex setup... + }); +}); +``` + +### After (Discord Testing Library) +```typescript +describe("handling feature", () => { + it("does something", async () => { + const discord = createDiscordTest(); + const guild = discord.createGuild('Test Guild'); + const user = guild.createUser('testuser'); + // Clean, explicit setup + }); +}); +``` + +## Architecture + +The Discord Testing Library provides enhanced versions of Discord mocks with testing convenience methods, isolated by import path from the original mock system. This allows for gradual migration and maintains compatibility with existing tests. + +- **`MockGuild`** - Enhanced guild mock with `createUser()`, `createChannel()` methods +- **`MockUser`** - Enhanced user mock with `clickButton()` and interaction tracking +- **`MockChannel`** - Enhanced channel mock with testing helpers +- **Event Flow** - Real Discord interactions flow through your actual listeners +- **Isolation** - Clean separation from old test infrastructure by import path \ No newline at end of file diff --git a/src/test/discord-testing-library/create-discord-environment.ts b/src/test/discord-testing-library/create-discord-environment.ts new file mode 100644 index 0000000..a288cb6 --- /dev/null +++ b/src/test/discord-testing-library/create-discord-environment.ts @@ -0,0 +1,146 @@ +/** + * Main factory for creating Discord test environments + */ + +import { Client } from "discord.js"; +import { createMockClient } from "./create-mock-client"; +import { createMockGuild, type MockGuild } from "./create-mock-guild"; +import { type MockUser } from "./create-mock-user"; +import { type MockChannel } from "./create-mock-channel"; +import { resetMockConfig } from "../setup/setup-test-config"; +import { discordComponentRegistry } from "./discord-component-registry"; + +export interface DiscordButton { + label: string; + customId?: string; // Only for interaction buttons, not URL buttons + style: number; + click(user: MockUser): Promise; +} + +export interface DiscordTestEnvironment { + client: Client; + guild: MockGuild; + channels: Record; + users: Record; + createGuild(name: string, options?: { id?: string }): MockGuild; + withClient(fn: (client: Client) => T | Promise): Promise; + channel(name: string): MockChannel; + getButton(label: string, options?: { style?: number }): DiscordButton; +} + +export interface DiscordEnvironmentOptions { + guildName?: string; + guildId?: string; + defaultUsers?: string[]; + channels?: Record; + defaultChannels?: Array<{ name: string; id?: string; type?: "text" | "thread" }>; + config?: Record; +} + +class DiscordTestEnvironmentImpl implements DiscordTestEnvironment { + public readonly client: Client; + public readonly guild: MockGuild; + public readonly channels: Record = {}; + public readonly users: Record = {}; + private guilds: Map = new Map(); + + constructor(options: DiscordEnvironmentOptions = {}) { + // Always set up global test config first + resetMockConfig(options.config); + + this.client = createMockClient(); + + // Create default guild + const guildName = options.guildName || "Test Guild"; + const guildOptions = options.guildId + ? { id: options.guildId, client: this.client } + : { client: this.client }; + this.guild = this.createGuild(guildName, guildOptions); + + // Set up default users + const defaultUsers = options.defaultUsers || ["testuser"]; + defaultUsers.forEach((username) => { + const user = this.guild.createUser(username); + this.users[username] = user; + }); + + // Set up channels - prefer simple channels config over defaultChannels + if (options.channels) { + Object.entries(options.channels).forEach(([name, type]) => { + // Use default channel ID if this is a known channel name (for config consistency) + const defaultChannel = options.defaultChannels?.find((dc) => dc.name === name); + const channelOptions = defaultChannel?.id ? { id: defaultChannel.id, type } : { type }; + + const channel = this.guild.createChannel(name, channelOptions); + this.channels[name] = channel; + }); + } else if (options.defaultChannels) { + // Use explicit defaultChannels if provided + options.defaultChannels.forEach(({ name, id, type }) => { + const channel = this.guild.createChannel(name, { id, type }); + this.channels[name] = channel; + }); + } + // No default channels in generic test infrastructure + } + + createGuild(name: string, options: { id?: string; client?: any } = {}): MockGuild { + const guildOptions = { client: this.client, ...options }; + const guild = createMockGuild(guildOptions); + + this.guilds.set(name, guild); + this.guilds.set(guild.id, guild); + + return guild; + } + + async withClient(fn: (client: Client) => T | Promise): Promise { + return await fn(this.client); + } + + channel(name: string): MockChannel { + const channel = this.channels[name]; + if (!channel) { + throw new Error( + `Channel "${name}" not found. Available channels: ${Object.keys(this.channels).join(", ")}` + ); + } + return channel; + } + + getButton(label: string, options?: { style?: number }): DiscordButton { + const button = discordComponentRegistry.findButton(label, options); + if (!button) { + const availableButtons = discordComponentRegistry + .getButtons() + .map((b) => `"${b.data.label}" (style ${b.data.style})`) + .join(", "); + throw new Error( + `Button with label "${label}" not found. Available buttons: ${availableButtons || "none"}` + ); + } + + // For interaction buttons, extract custom_id for click functionality + const customId = "custom_id" in button.data ? button.data.custom_id : undefined; + + return { + label: button.data.label || "Unknown", + customId, + style: button.data.style || 0, + click: async (user: MockUser) => { + if (!customId) { + throw new Error( + `Cannot click URL button "${label}" - it has no custom_id for interaction` + ); + } + await user.clickButton(customId); + }, + }; + } +} + +export function createDiscordEnvironment( + options: DiscordEnvironmentOptions = {} +): DiscordTestEnvironment { + return new DiscordTestEnvironmentImpl(options); +} diff --git a/src/test/discord-testing-library/create-mock-button-interaction.ts b/src/test/discord-testing-library/create-mock-button-interaction.ts new file mode 100644 index 0000000..05c1673 --- /dev/null +++ b/src/test/discord-testing-library/create-mock-button-interaction.ts @@ -0,0 +1,61 @@ +/** + * MockButtonInteraction for Discord Testing Library + */ + +import { ButtonInteraction, CacheType, InteractionType, ComponentType, Client } from "discord.js"; +import { createTypedMock } from "../utils/create-typed-mock"; +import { createMockClient } from "./create-mock-client"; + +// Create a partial ButtonInteraction that focuses on what we actually test +type TestableButtonInteraction = Pick< + ButtonInteraction, + "customId" | "type" | "componentType" | "id" | "token" | "version" | "applicationId" +> & { + user: any; // MockUser + guild: any; // MockGuild | null + client: Client; + editReply: jest.MockedFunction; + reply: jest.MockedFunction; + deferReply: jest.MockedFunction; + isAutocomplete: jest.MockedFunction<() => boolean>; + isButton: jest.MockedFunction<() => boolean>; + isChatInputCommand: jest.MockedFunction<() => boolean>; +}; + +export interface MockButtonInteractionOptions { + customId?: string; + user?: any; // MockUser + guild?: any; // MockGuild + client?: Client; +} + +export function createMockButtonInteraction({ + customId = "test-button", + user, + client = createMockClient(), + guild, +}: MockButtonInteractionOptions = {}): ButtonInteraction { + const mock: TestableButtonInteraction = { + customId, + user, + guild, + client, + type: InteractionType.MessageComponent, + componentType: ComponentType.Button, + id: "interaction-id", + token: "interaction-token", + version: 1, + applicationId: "app-id", + editReply: createTypedMock(), + reply: createTypedMock(), + deferReply: createTypedMock(), + isAutocomplete: jest.fn().mockReturnValue(false), + isButton: jest.fn().mockReturnValue(true), + isChatInputCommand: jest.fn().mockReturnValue(false), + }; + + // TypeScript magic: return as full ButtonInteraction + // This works because ButtonInteraction will have all the properties we need, + // and TypeScript structural typing means our mock is compatible + return mock as unknown as ButtonInteraction; +} diff --git a/src/test/discord-testing-library/create-mock-channel.ts b/src/test/discord-testing-library/create-mock-channel.ts new file mode 100644 index 0000000..e3161f1 --- /dev/null +++ b/src/test/discord-testing-library/create-mock-channel.ts @@ -0,0 +1,31 @@ +/** + * Enhanced MockChannel for Discord Testing Library + */ + +import { Message } from "discord.js"; +import { createTypedMock } from "../utils/create-typed-mock"; + +export type MockChannel = { + id: string; + type: number; + send: jest.MockedFunction<(content: string) => Promise>; + name: string; + channelType: "text" | "thread"; +}; + +export function createMockChannel( + name: string, + options: { id?: string; type?: "text" | "thread" } = {} +): MockChannel { + const channelId = + options.id || `channel-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; + const channelType = options.type || "thread"; + + return { + id: channelId, + type: channelType === "text" ? 0 : 11, // ChannelType values + send: createTypedMock<(content: string) => Promise>(), + name, + channelType, + }; +} diff --git a/src/test/discord-testing-library/create-mock-client.ts b/src/test/discord-testing-library/create-mock-client.ts new file mode 100644 index 0000000..3c0b7fc --- /dev/null +++ b/src/test/discord-testing-library/create-mock-client.ts @@ -0,0 +1,23 @@ +/** + * MockClient for Discord Testing Library + */ + +import { Client } from "discord.js"; + +export interface MockClientOptions { + id?: string; +} + +export function createMockClient({ id = "bot123456" }: MockClientOptions = {}): Client { + // Create a minimal Client mock that satisfies the interface + const mockClient = { + user: { + id, + }, + // Add other Client properties that might be needed + // Most Client properties are optional or have default values + }; + + // Return as proper Client type using TypeScript structural typing + return mockClient as unknown as Client; +} diff --git a/src/test/discord-testing-library/create-mock-guild.ts b/src/test/discord-testing-library/create-mock-guild.ts new file mode 100644 index 0000000..441f1e2 --- /dev/null +++ b/src/test/discord-testing-library/create-mock-guild.ts @@ -0,0 +1,57 @@ +/** + * Enhanced MockGuild for Discord Testing Library + */ + +import { TextChannel, PublicThreadChannel } from "discord.js"; +import { createTypedMock } from "../utils/create-typed-mock"; +import { createMockUser, type MockUser } from "./create-mock-user"; +import { createMockChannel, type MockChannel } from "./create-mock-channel"; + +export type MockGuild = { + id: string; + channels: { + fetch: jest.MockedFunction<(id: string) => Promise>; + }; + createUser(username: string, options?: { id?: string }): MockUser; + createChannel(name: string, options?: { id?: string; type?: "text" | "thread" }): MockChannel; +}; + +export function createMockGuild(options: { id?: string; client?: any } = {}): MockGuild { + const { id = `guild-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`, client } = options; + + const channels = new Map(); + + const guild: MockGuild = { + id, + channels: { + fetch: createTypedMock<(id: string) => Promise>(), + }, + createUser: (username: string, userOptions: { id?: string } = {}) => { + return createMockUser({ username, guild, client, ...userOptions }); + }, + createChannel: ( + name: string, + channelOptions: { id?: string; type?: "text" | "thread" } = {} + ) => { + const channel = createMockChannel(name, channelOptions); + + channels.set(channel.id, channel); + + // Update guild's fetch implementation to handle this channel + const currentImpl = guild.channels.fetch.getMockImplementation(); + guild.channels.fetch.mockImplementation((id: string) => { + if (channels.has(id)) { + return Promise.resolve(channels.get(id) as any); + } + if (currentImpl) { + return currentImpl(id); + } + return Promise.resolve(null); + }); + + return channel; + }, + }; + + return guild; +} diff --git a/src/test/discord-testing-library/create-mock-user.ts b/src/test/discord-testing-library/create-mock-user.ts new file mode 100644 index 0000000..64024ec --- /dev/null +++ b/src/test/discord-testing-library/create-mock-user.ts @@ -0,0 +1,68 @@ +/** + * Enhanced MockUser for Discord Testing Library + */ + +import { Client, Message, MessageCreateOptions } from "discord.js"; +import { createTypedMock } from "../utils/create-typed-mock"; +import { createMockButtonInteraction } from "./create-mock-button-interaction"; +import { interactionCreateListener } from "../../listeners/interaction-create-listener"; +// Forward declaration to avoid circular dependency +export interface MockGuild { + id: string; + channels: { + fetch: jest.MockedFunction; + }; +} + +export type MockUser = { + id: string; + username: string; + send: jest.MockedFunction<(options: MessageCreateOptions) => Promise>; + clickButton(customId: string): Promise; + lastInteraction?: { + editReply: jest.MockedFunction; + deferReply: jest.MockedFunction; + }; + _guild?: MockGuild; + _client?: Client; +}; + +export function createMockUser( + options: { id?: string; username: string; guild?: MockGuild; client?: Client } = { + username: "testuser", + } +): MockUser { + const { + id = `user-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`, + username, + guild, + client, + } = options; + + return { + id, + username, + send: createTypedMock<(options: MessageCreateOptions) => Promise>(), + _guild: guild, + _client: client, + clickButton: async function (customId: string) { + if (!this._guild || !this._client) { + throw new Error("MockUser must be created through discord environment to use clickButton"); + } + + const interaction = createMockButtonInteraction({ + customId, + user: this as any, + guild: this._guild as any, + client: this._client, + }); + + this.lastInteraction = { + editReply: interaction.editReply as jest.MockedFunction, + deferReply: interaction.deferReply as jest.MockedFunction, + }; + + await interactionCreateListener(interaction); + }, + }; +} diff --git a/src/test/discord-testing-library/discord-component-registry.ts b/src/test/discord-testing-library/discord-component-registry.ts new file mode 100644 index 0000000..d75e4b8 --- /dev/null +++ b/src/test/discord-testing-library/discord-component-registry.ts @@ -0,0 +1,64 @@ +/** + * Generic Discord component registry for test infrastructure + * This should not know about any bot-specific concepts like "instructions" + */ + +import { ButtonBuilder, EmbedBuilder } from "discord.js"; + +class DiscordComponentRegistry { + private buttons: ButtonBuilder[] = []; + private embeds: EmbedBuilder[] = []; + + registerButton(button: ButtonBuilder) { + this.buttons.push(button); + } + + registerEmbed(embed: EmbedBuilder) { + this.embeds.push(embed); + } + + findButton(label: string, options?: { style?: number }): ButtonBuilder | null { + const matchingButtons = this.buttons.filter((button) => { + if (button.data.label !== label) { + return false; + } + if (options?.style !== undefined && button.data.style !== options.style) { + return false; + } + return true; + }); + + if (matchingButtons.length === 0) { + return null; + } + + if (matchingButtons.length > 1) { + const styles = matchingButtons.map((b) => `style ${b.data.style}`).join(", "); + throw new Error( + `Found ${matchingButtons.length} buttons with label "${label}" (${styles}). ` + + `Please specify a style to narrow the selection: findButton("${label}", { style: ... })` + ); + } + + return matchingButtons[0]; + } + + findEmbed(title: string): EmbedBuilder | null { + return this.embeds.find((embed) => embed.data.title === title) || null; + } + + getButtons(): ButtonBuilder[] { + return [...this.buttons]; + } + + getEmbeds(): EmbedBuilder[] { + return [...this.embeds]; + } + + clear() { + this.buttons = []; + this.embeds = []; + } +} + +export const discordComponentRegistry = new DiscordComponentRegistry(); diff --git a/src/test/discord-testing-library/index.ts b/src/test/discord-testing-library/index.ts new file mode 100644 index 0000000..21325f6 --- /dev/null +++ b/src/test/discord-testing-library/index.ts @@ -0,0 +1,19 @@ +/** + * Discord Testing Library - A comprehensive testing framework for Discord bots + * + * Provides a Testing Library-style API for Discord bot testing with: + * - Realistic Discord environment simulation + * - User interaction simulation + * - Enhanced assertions + * - Smart defaults with automatic global config setup + * - Full integration with existing test patterns + */ + +export { createDiscordEnvironment } from "./create-discord-environment"; +export type { + DiscordTestEnvironment, + DiscordEnvironmentOptions, +} from "./create-discord-environment"; +export type { MockGuild } from "./create-mock-guild"; +export type { MockUser } from "./create-mock-user"; +export type { MockChannel } from "./create-mock-channel"; diff --git a/src/test/matchers/index.ts b/src/test/matchers/index.ts new file mode 100644 index 0000000..c27fbf5 --- /dev/null +++ b/src/test/matchers/index.ts @@ -0,0 +1,11 @@ +/** + * Discord matchers - centralized imports for all matcher modules + */ + +import "./to-have-sent-dm"; +import "./to-have-sent-message"; +import "./to-have-button-properties"; +import "./to-have-interaction-responses"; +import "./to-have-user-interactions"; +import "./to-match-embed-fixture"; +import "./to-have-created-discord-components"; diff --git a/src/test/matchers/to-have-button-properties.ts b/src/test/matchers/to-have-button-properties.ts new file mode 100644 index 0000000..8ba929a --- /dev/null +++ b/src/test/matchers/to-have-button-properties.ts @@ -0,0 +1,66 @@ +/** + * Matchers for checking button properties + */ + +import { expect } from "@jest/globals"; +import { ButtonBuilder } from "discord.js"; + +declare global { + // eslint-disable-next-line @typescript-eslint/no-namespace + namespace jest { + interface Matchers { + toHaveLabel(expectedLabel: string): R; + toHaveCustomId(expectedCustomId: string): R; + toHaveButtonStyle(expectedStyle: number): R; + } + } +} + +expect.extend({ + toHaveLabel(received: ButtonBuilder, expectedLabel: string) { + const actualLabel = received.data.label; + const labelMatches = actualLabel === expectedLabel; + + return { + message: () => + labelMatches + ? `Expected button to not have label "${expectedLabel}", but it did` + : `Expected button to have label "${expectedLabel}", but received: "${actualLabel}"`, + pass: labelMatches, + }; + }, + + toHaveCustomId( + received: ButtonBuilder | { customId: string } | { data: { custom_id: string } }, + expectedCustomId: string + ) { + const actualCustomId = + "customId" in received + ? received.customId + : "data" in received + ? (received.data as { custom_id?: string }).custom_id + : undefined; + const customIdMatches = actualCustomId === expectedCustomId; + + return { + message: () => + customIdMatches + ? `Expected to not have custom ID "${expectedCustomId}", but it did` + : `Expected to have custom ID "${expectedCustomId}", but received: "${actualCustomId}"`, + pass: customIdMatches, + }; + }, + + toHaveButtonStyle(received: ButtonBuilder, expectedStyle: number) { + const actualStyle = received.data.style; + const styleMatches = actualStyle === expectedStyle; + + return { + message: () => + styleMatches + ? `Expected button to not have style "${expectedStyle}", but it did` + : `Expected button to have style "${expectedStyle}", but received: "${actualStyle}"`, + pass: styleMatches, + }; + }, +}); diff --git a/src/test/matchers/to-have-created-discord-components.ts b/src/test/matchers/to-have-created-discord-components.ts new file mode 100644 index 0000000..dbbf73b --- /dev/null +++ b/src/test/matchers/to-have-created-discord-components.ts @@ -0,0 +1,108 @@ +/** + * Matchers for Discord component creation + */ + +import { expect } from "@jest/globals"; +import { ButtonStyle } from "discord.js"; +import { globalDiscordMocks } from "../setup/setup-discord-actions"; +import type { DiscordTestEnvironment } from "../discord-testing-library"; + +declare global { + // eslint-disable-next-line @typescript-eslint/no-namespace + namespace jest { + interface Matchers { + toHaveCreatedButton(label: string, options?: { customId?: string; style?: ButtonStyle }): R; + toHaveCreatedEmbed(title: string, description?: string): R; + toHaveCreatedInstructions(instructionKey: string): R; + } + } +} + +expect.extend({ + toHaveCreatedButton( + received: DiscordTestEnvironment, + label: string, + options?: { customId?: string; style?: ButtonStyle } + ) { + const buttonMatcher = expect.objectContaining({ + components: expect.arrayContaining([ + expect.objectContaining({ + components: expect.arrayContaining([ + expect.objectContaining({ + data: expect.objectContaining({ + label, + ...(options?.customId && { custom_id: options.customId }), + ...(options?.style !== undefined && { style: options.style }), + }), + }), + ]), + }), + ]), + }); + + const wasCalled = globalDiscordMocks.createOrUpdateInstructions.mock.calls.some((call) => { + try { + expect(call[0]).toEqual(buttonMatcher); + return true; + } catch { + return false; + } + }); + + return { + message: () => + wasCalled + ? `Expected not to have created button "${label}"` + : `Expected to have created button "${label}"${ + options?.customId ? ` with customId "${options.customId}"` : "" + }${options?.style !== undefined ? ` with style ${options.style}` : ""}`, + pass: wasCalled, + }; + }, + + toHaveCreatedEmbed(received: DiscordTestEnvironment, title: string, description?: string) { + const embedMatcher = expect.objectContaining({ + embeds: expect.arrayContaining([ + expect.objectContaining({ + data: expect.objectContaining({ + title, + ...(description && { description }), + }), + }), + ]), + }); + + const wasCalled = globalDiscordMocks.createOrUpdateInstructions.mock.calls.some((call) => { + try { + expect(call[0]).toEqual(embedMatcher); + return true; + } catch { + return false; + } + }); + + return { + message: () => + wasCalled + ? `Expected not to have created embed "${title}"` + : `Expected to have created embed "${title}"${ + description ? ` with description "${description}"` : "" + }`, + pass: wasCalled, + }; + }, + + toHaveCreatedInstructions(received: DiscordTestEnvironment, instructionKey: string) { + const wasCalled = globalDiscordMocks.createOrUpdateInstructions.mock.calls.some( + (call) => call[1] === instructionKey + ); + + return { + message: () => + wasCalled + ? `Expected not to have created instructions "${instructionKey}"` + : `Expected to have created instructions "${instructionKey}"`, + pass: wasCalled, + }; + }, +}); diff --git a/src/test/matchers/to-have-interaction-responses.ts b/src/test/matchers/to-have-interaction-responses.ts new file mode 100644 index 0000000..389c327 --- /dev/null +++ b/src/test/matchers/to-have-interaction-responses.ts @@ -0,0 +1,82 @@ +/** + * Matchers for checking interaction responses + */ + +import { expect } from "@jest/globals"; +import { InteractionResponse, Message } from "discord.js"; + +declare global { + // eslint-disable-next-line @typescript-eslint/no-namespace + namespace jest { + interface Matchers { + toHaveRepliedWith(expectedContent: string | RegExp): R; + toHaveEditedReplyWith(expectedContent: string | RegExp): R; + } + } +} + +expect.extend({ + toHaveRepliedWith( + received: { + reply: jest.MockedFunction<(options: { content: string }) => Promise>; + }, + expectedContent: string | RegExp + ) { + const mockReply = received.reply; + + if (!mockReply.mock.calls.length) { + return { + message: () => `Expected interaction to have replied, but no reply was sent`, + pass: false, + }; + } + + const lastCall = mockReply.mock.calls[mockReply.mock.calls.length - 1]; + const actualContent = lastCall[0]?.content || lastCall[0]; + + const contentMatches = + typeof expectedContent === "string" + ? actualContent === expectedContent + : expectedContent.test(String(actualContent)); + + return { + message: () => + contentMatches + ? `Expected interaction to not have replied with content matching ${expectedContent}, but it did` + : `Expected interaction to have replied with content matching ${expectedContent}, but received: ${actualContent}`, + pass: contentMatches, + }; + }, + + toHaveEditedReplyWith( + received: { + editReply: jest.MockedFunction<(options: { content: string }) => Promise>; + }, + expectedContent: string | RegExp + ) { + const mockEditReply = received.editReply; + + if (!mockEditReply.mock.calls.length) { + return { + message: () => `Expected interaction to have edited a reply, but no edit-reply was sent`, + pass: false, + }; + } + + const lastCall = mockEditReply.mock.calls[mockEditReply.mock.calls.length - 1]; + const actualContent = lastCall[0]?.content || lastCall[0]; + + const contentMatches = + typeof expectedContent === "string" + ? actualContent === expectedContent + : expectedContent.test(String(actualContent)); + + return { + message: () => + contentMatches + ? `Expected interaction to not have edited a reply with content matching ${expectedContent}, but it did` + : `Expected interaction to have edited a reply with content matching ${expectedContent}, but received: ${actualContent}`, + pass: contentMatches, + }; + }, +}); diff --git a/src/test/matchers/to-have-sent-dm.ts b/src/test/matchers/to-have-sent-dm.ts new file mode 100644 index 0000000..f066ab4 --- /dev/null +++ b/src/test/matchers/to-have-sent-dm.ts @@ -0,0 +1,67 @@ +/** + * Matcher for checking if a user sent a DM + */ + +import { expect } from "@jest/globals"; +import { MessageCreateOptions, Message } from "discord.js"; + +declare global { + // eslint-disable-next-line @typescript-eslint/no-namespace + namespace jest { + interface Matchers { + toHaveSentDm(expectedContent?: string | RegExp): R; + } + } +} + +expect.extend({ + toHaveSentDm( + received: { + send: jest.MockedFunction<(options: MessageCreateOptions) => Promise>; + }, + expectedContent?: string | RegExp + ) { + const mockSend = received.send; + + if (!mockSend.mock.calls.length) { + return { + message: () => `Expected user to have sent a DM, but no DM was sent`, + pass: false, + }; + } + + if (!expectedContent) { + return { + message: () => `Expected user to have sent a DM`, + pass: true, + }; + } + + const lastCall = mockSend.mock.calls[mockSend.mock.calls.length - 1]; + const messageOptions = lastCall[0]; + const actualContent = + typeof messageOptions === "string" + ? messageOptions + : (messageOptions as { content?: string })?.content; + + if (!actualContent) { + return { + message: () => `Expected user to have sent a DM with content, but no content found`, + pass: false, + }; + } + + const contentMatches = + typeof expectedContent === "string" + ? actualContent === expectedContent + : expectedContent.test(actualContent); + + return { + message: () => + contentMatches + ? `Expected user to not have sent a DM with content matching ${expectedContent}, but it did` + : `Expected user to have sent a DM with content matching ${expectedContent}, but received: ${actualContent}`, + pass: contentMatches, + }; + }, +}); diff --git a/src/test/matchers/to-have-sent-message.ts b/src/test/matchers/to-have-sent-message.ts new file mode 100644 index 0000000..f6fd3c2 --- /dev/null +++ b/src/test/matchers/to-have-sent-message.ts @@ -0,0 +1,67 @@ +/** + * Matcher for checking if a channel sent a message + */ + +import { expect } from "@jest/globals"; +import { Message } from "discord.js"; + +declare global { + // eslint-disable-next-line @typescript-eslint/no-namespace + namespace jest { + interface Matchers { + toHaveSentMessage(expectedContent?: string | RegExp): R; + } + } +} + +expect.extend({ + toHaveSentMessage( + received: { + send: jest.MockedFunction<(content: string) => Promise>; + }, + expectedContent?: string | RegExp + ) { + const mockSend = received.send; + + if (!mockSend.mock.calls.length) { + return { + message: () => `Expected channel to have sent a message, but no message was sent`, + pass: false, + }; + } + + if (!expectedContent) { + return { + message: () => `Expected channel to have sent a message`, + pass: true, + }; + } + + const lastCall = mockSend.mock.calls[mockSend.mock.calls.length - 1]; + const messageOptions = lastCall[0]; + const actualContent = + typeof messageOptions === "string" + ? messageOptions + : (messageOptions as { content?: string })?.content; + + if (!actualContent) { + return { + message: () => `Expected channel to have sent a message with content, but no content found`, + pass: false, + }; + } + + const contentMatches = + typeof expectedContent === "string" + ? actualContent === expectedContent + : expectedContent.test(actualContent); + + return { + message: () => + contentMatches + ? `Expected channel to not have sent a message with content matching ${expectedContent}, but it did` + : `Expected channel to have sent a message with content matching ${expectedContent}, but received: ${actualContent}`, + pass: contentMatches, + }; + }, +}); diff --git a/src/test/matchers/to-have-user-interactions.ts b/src/test/matchers/to-have-user-interactions.ts new file mode 100644 index 0000000..1734b21 --- /dev/null +++ b/src/test/matchers/to-have-user-interactions.ts @@ -0,0 +1,57 @@ +/** + * Matchers for checking user interactions + */ + +import { expect } from "@jest/globals"; + +declare global { + // eslint-disable-next-line @typescript-eslint/no-namespace + namespace jest { + interface Matchers { + toHaveEditedReplyWith(expectedContent: string | RegExp): R; + } + } +} + +expect.extend({ + toHaveEditedReplyWith( + received: { + lastInteraction?: { + editReply: jest.MockedFunction; + }; + }, + expectedContent: string | RegExp + ) { + const mockEditReply = received.lastInteraction?.editReply; + + if (!mockEditReply) { + return { + message: () => `Expected user to have had an interaction, but no interaction found`, + pass: false, + }; + } + + if (!mockEditReply.mock.calls.length) { + return { + message: () => `Expected user to have edited a reply, but no edit-reply was called`, + pass: false, + }; + } + + const lastCall = mockEditReply.mock.calls[mockEditReply.mock.calls.length - 1]; + const actualContent = lastCall[0]?.content || lastCall[0]; + + const contentMatches = + typeof expectedContent === "string" + ? actualContent === expectedContent + : expectedContent.test(String(actualContent)); + + return { + message: () => + contentMatches + ? `Expected user to not have edited a reply with content matching ${expectedContent}, but it did` + : `Expected user to have edited a reply with content matching ${expectedContent}, but received: ${actualContent}`, + pass: contentMatches, + }; + }, +}); diff --git a/src/test/matchers/to-match-embed-fixture.ts b/src/test/matchers/to-match-embed-fixture.ts new file mode 100644 index 0000000..dd835d3 --- /dev/null +++ b/src/test/matchers/to-match-embed-fixture.ts @@ -0,0 +1,34 @@ +/** + * Matcher for checking embed fixtures + */ + +import { expect } from "@jest/globals"; +import { EmbedBuilder } from "discord.js"; + +declare global { + // eslint-disable-next-line @typescript-eslint/no-namespace + namespace jest { + interface Matchers { + toMatchEmbedFixture(expectedEmbed: object): R; + } + } +} + +expect.extend({ + toMatchEmbedFixture(received: EmbedBuilder, expectedEmbed: object) { + const actualEmbed = received.toJSON(); + const embedsMatch = JSON.stringify(expectedEmbed) === JSON.stringify(actualEmbed); + + return { + message: () => + embedsMatch + ? `Expected embed to not match fixture, but it did` + : `Expected embed to match fixture\n\nExpected:\n${JSON.stringify( + expectedEmbed, + null, + 2 + )}\n\nReceived:\n${JSON.stringify(actualEmbed, null, 2)}`, + pass: embedsMatch, + }; + }, +}); diff --git a/src/test/setup.ts b/src/test/setup.ts new file mode 100644 index 0000000..53773e4 --- /dev/null +++ b/src/test/setup.ts @@ -0,0 +1,20 @@ +// Side-effect: Jest mocks for database +import "./setup/setup-database"; +// Side-effect: Jest mocks for Redis +import "./setup/setup-redis"; +// Side-effect: Jest mocks for bot accounts service +import "./setup/setup-service-bot-accounts"; +// Side-effect: Jest mocks for DKP service +import "./setup/setup-service-dkp"; +// Side-effect: Extends Jest expect with custom matchers +import "./matchers"; // Side-effect: Extends Jest expect with custom matchers +import { resetMockConfig } from "./setup/setup-test-config"; +import { resetDiscordMocks } from "./setup/setup-discord-actions"; +import { discordComponentRegistry } from "./discord-testing-library/discord-component-registry"; + +beforeEach(() => { + jest.clearAllMocks(); + resetDiscordMocks(); + discordComponentRegistry.clear(); + resetMockConfig(); +}); diff --git a/src/test/setup/setup-database.ts b/src/test/setup/setup-database.ts new file mode 100644 index 0000000..69f9327 --- /dev/null +++ b/src/test/setup/setup-database.ts @@ -0,0 +1,17 @@ +/** + * Database mocking utilities for tests + */ + +// Mock the database to prevent initialization errors during tests +jest.mock("../../db/data-source", () => ({ + dataSource: { + initialize: jest.fn().mockResolvedValue({ + driver: { + postgres: { + defaults: { parseInputDatesAsUTC: true }, + types: { setTypeParser: jest.fn() }, + }, + }, + }), + }, +})); diff --git a/src/test/setup/setup-discord-actions.ts b/src/test/setup/setup-discord-actions.ts new file mode 100644 index 0000000..e701746 --- /dev/null +++ b/src/test/setup/setup-discord-actions.ts @@ -0,0 +1,71 @@ +/** + * Discord action mocking utilities for tests + */ + +import { discordComponentRegistry } from "../discord-testing-library/discord-component-registry"; + +// Create global Discord mocks with better defaults +const mockCreateOrUpdateInstructions = jest.fn().mockImplementation((instructions) => { + // Register components in the generic registry when instructions are created + if (instructions?.components) { + for (const component of instructions.components) { + if (component?.components) { + for (const item of component.components) { + if (item?.data?.custom_id) { + discordComponentRegistry.registerButton(item); + } + } + } + } + } + if (instructions?.embeds) { + for (const embed of instructions.embeds) { + discordComponentRegistry.registerEmbed(embed); + } + } + return Promise.resolve(undefined); +}); + +const mockGetChannel = jest.fn().mockResolvedValue({ + id: "111222333", + type: 11, // ChannelType.PublicThread + send: jest.fn().mockResolvedValue(undefined), +}); +const mockReadyActionExecutor = jest.fn((action) => action.execute()); + +export const globalDiscordMocks = { + createOrUpdateInstructions: mockCreateOrUpdateInstructions, + getChannel: mockGetChannel, + readyActionExecutor: mockReadyActionExecutor, +}; + +// Set up global Discord mocks using jest.mock (hoisted!) +jest.mock("../../shared/action/instructions-ready-action", () => ({ + InstructionsReadyAction: class { + createOrUpdateInstructions = mockCreateOrUpdateInstructions; + getChannel = mockGetChannel; + }, +})); + +jest.mock("../../shared/action/ready-action", () => ({ + readyActionExecutor: mockReadyActionExecutor, +})); + +// Mock the main index file to prevent event listener setup during tests +jest.mock("../../index", () => ({ + // Mock the main bot client setup +})); + +export function resetDiscordMocks() { + // Clear call history but preserve our custom implementations + globalDiscordMocks.createOrUpdateInstructions.mockClear(); + + globalDiscordMocks.getChannel.mockReset().mockResolvedValue({ + id: "111222333", + type: 11, // ChannelType.PublicThread + send: jest.fn().mockResolvedValue(undefined), + }); + globalDiscordMocks.readyActionExecutor + .mockReset() + .mockImplementation((action) => action.execute()); +} diff --git a/src/test/setup/setup-redis.ts b/src/test/setup/setup-redis.ts new file mode 100644 index 0000000..6070136 --- /dev/null +++ b/src/test/setup/setup-redis.ts @@ -0,0 +1,15 @@ +/** + * Redis mocking utilities for tests + */ + +// Mock Redis to prevent connection errors during tests +jest.mock("../../redis/client", () => ({ + redisClient: { + connect: jest.fn().mockResolvedValue(undefined), + disconnect: jest.fn().mockResolvedValue(undefined), + get: jest.fn().mockResolvedValue(null), + set: jest.fn().mockResolvedValue(undefined), + hGet: jest.fn().mockResolvedValue(null), + hSet: jest.fn().mockResolvedValue(undefined), + }, +})); diff --git a/src/test/setup/setup-service-bot-accounts.ts b/src/test/setup/setup-service-bot-accounts.ts new file mode 100644 index 0000000..91b260c --- /dev/null +++ b/src/test/setup/setup-service-bot-accounts.ts @@ -0,0 +1,25 @@ +/** + * Bot accounts service mocking utilities for tests + */ + +jest.mock("../../services/bot/public-accounts-sheet", () => ({ + SheetPublicAccountService: class { + static getInstance() { + return { + getBots: jest.fn().mockResolvedValue([]), + getBotsByClass: jest.fn().mockResolvedValue([]), + }; + } + }, +})); + +jest.mock("../../services/bot/bot-factory", () => ({ + PublicAccountsFactory: { + getService: jest.fn().mockReturnValue({ + getBots: jest.fn().mockResolvedValue([]), + getBotsByClass: jest.fn().mockResolvedValue([]), + doBotCheckout: jest.fn().mockResolvedValue(undefined), + updateBotRowDetails: jest.fn().mockResolvedValue(undefined), + }), + }, +})); diff --git a/src/test/setup/setup-service-dkp.ts b/src/test/setup/setup-service-dkp.ts new file mode 100644 index 0000000..41a275f --- /dev/null +++ b/src/test/setup/setup-service-dkp.ts @@ -0,0 +1,25 @@ +/** + * DKP service mocking utilities for tests + */ + +jest.mock("../../services/castledkp", () => ({ + CastleDkpService: class { + async getDkp() { + return []; + } + async getDkpForPlayer() { + return []; + } + }, +})); + +jest.mock("../../services/betaDkpService", () => ({ + BetaDkpService: class { + async getDkp() { + return []; + } + async getDkpForPlayer() { + return []; + } + }, +})); diff --git a/src/test/setup/setup-test-config.ts b/src/test/setup/setup-test-config.ts new file mode 100644 index 0000000..be13882 --- /dev/null +++ b/src/test/setup/setup-test-config.ts @@ -0,0 +1,36 @@ +/** + * Config testing utilities + * Provides easy config mocking with automatic cleanup + */ + +import { jest } from "@jest/globals"; + +// Default test config values +export const defaultTestConfig = { + // Top-level exports to match the real config structure + applicationsChannelId: "999888777", + requestDumpThreadId: "111222333", + bankChannelId: "bank-123", + vaultChannelId: "vault-456", + auctionChannelId: "auction-789", +} as const; + +// Create a mutable config object that we can modify +const mockConfigState = { ...defaultTestConfig }; + +// Mock the config module at the top level (this gets hoisted) +jest.mock("../../config", () => mockConfigState); + +/** + * Reset config to defaults and apply any overrides + * Called once per test in beforeEach + */ +export function resetMockConfig(configOverrides: Record = {}) { + // Reset to defaults first + Object.assign(mockConfigState, defaultTestConfig); + + // Apply any overrides + Object.assign(mockConfigState, configOverrides); + + return mockConfigState; +} diff --git a/src/test/utils/create-typed-mock.ts b/src/test/utils/create-typed-mock.ts new file mode 100644 index 0000000..276a622 --- /dev/null +++ b/src/test/utils/create-typed-mock.ts @@ -0,0 +1,8 @@ +import { jest } from "@jest/globals"; + +export function createTypedMock< + // eslint-disable-next-line @typescript-eslint/no-explicit-any + T extends (...args: any[]) => any +>(): jest.MockedFunction { + return jest.fn() as unknown as jest.MockedFunction; +} diff --git a/yarn.lock b/yarn.lock index e5cb647..b61c3b0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -27,7 +27,7 @@ resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.6.tgz" integrity sha512-29tfsWTq2Ftu7MXmimyC0C5FDZv5DYxOZkh3XD3+QW4V/BYuv/LyEsjj3c0hqedEaDt6DBfDvexMKU8YevdqFg== -"@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.7.2", "@babel/core@^7.8.0": +"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.7.2", "@babel/core@^7.8.0", "@babel/core@>=7.0.0-beta.0 <8": version "7.22.8" resolved "https://registry.npmjs.org/@babel/core/-/core-7.22.8.tgz" integrity sha512-75+KxFB4CZqYRXjx4NlR4J7yGvKumBuZTmV4NV6v09dVXXkuYVYLT68N6HCzLvfJ+fWCxQsntNzKwwIXL4bHnw== @@ -313,7 +313,7 @@ "@derhuerst/http-basic@^8.2.0": version "8.2.4" - resolved "https://registry.yarnpkg.com/@derhuerst/http-basic/-/http-basic-8.2.4.tgz#d021ebb8f65d54bea681ae6f4a8733ce89e7f59b" + resolved "https://registry.npmjs.org/@derhuerst/http-basic/-/http-basic-8.2.4.tgz" integrity sha512-F9rL9k9Xjf5blCz8HsJRO4diy111cayL2vkY2XE4r4t3n0yPXVYy3KD3nJ1qbrSn9743UWSXH4IwuCa/HWlGFw== dependencies: caseless "^0.12.0" @@ -401,7 +401,7 @@ "@discordjs/voice@^0.17.0": version "0.17.0" - resolved "https://registry.yarnpkg.com/@discordjs/voice/-/voice-0.17.0.tgz#37be97c20dc4144c4c4d27d8ad02f29373da7ea6" + resolved "https://registry.npmjs.org/@discordjs/voice/-/voice-0.17.0.tgz" integrity sha512-hArn9FF5ZYi1IkxdJEVnJi+OxlwLV0NJYWpKXsmNOojtGtAZHxmsELA+MZlu2KW1F/K1/nt7lFOfcMXNYweq9w== dependencies: "@types/ws" "^8.5.10" @@ -695,14 +695,6 @@ resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== -"@jridgewell/trace-mapping@0.3.9": - version "0.3.9" - resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz" - integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== - dependencies: - "@jridgewell/resolve-uri" "^3.0.3" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": version "0.3.19" resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz" @@ -711,6 +703,14 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@messageformat/core@^3.0.1": version "3.2.0" resolved "https://registry.npmjs.org/@messageformat/core/-/core-3.2.0.tgz" @@ -760,7 +760,7 @@ "@nodelib/fs.stat" "2.0.5" run-parallel "^1.1.9" -"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": +"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": version "2.0.5" resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== @@ -815,7 +815,7 @@ resolved "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz" integrity sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg== -"@redis/client@1.5.8": +"@redis/client@^1.0.0", "@redis/client@1.5.8": version "1.5.8" resolved "https://registry.npmjs.org/@redis/client/-/client-1.5.8.tgz" integrity sha512-xzElwHIO6rBAqzPeVnCzgvrnBEcFL1P0w8P65VNLRkdVW8rOE58f52hdj0BDgmsdOm4f1EoXPZtH4Fh7M/qUpw== @@ -993,7 +993,7 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@^27.4.1": +"@types/jest@^27.0.0", "@types/jest@^27.4.1": version "27.5.2" resolved "https://registry.npmjs.org/@types/jest/-/jest-27.5.2.tgz" integrity sha512-mpT8LJJ4CMeeahobofYWIjFo0xonRS/HfxnVEPMPFSQdGUt1uHCnoPT7Zhb+sjDU2wz0oKV0OLUR0WzrHNgfeA== @@ -1038,7 +1038,7 @@ "@types/node@^10.0.3": version "10.17.60" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b" + resolved "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz" integrity sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw== "@types/pg@^8.6.5": @@ -1067,7 +1067,7 @@ "@types/ws@^8.5.10": version "8.5.10" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.10.tgz#4acfb517970853fa6574a3a6886791d04a396787" + resolved "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz" integrity sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A== dependencies: "@types/node" "*" @@ -1107,7 +1107,7 @@ semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/parser@^5.10.0", "@typescript-eslint/parser@^5.19.0": +"@typescript-eslint/parser@^5.0.0", "@typescript-eslint/parser@^5.10.0", "@typescript-eslint/parser@^5.19.0": version "5.62.0" resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz" integrity sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA== @@ -1220,16 +1220,16 @@ acorn-walk@^8.1.1: resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz" integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== +"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.2.4, acorn@^8.4.1, acorn@^8.9.0: + version "8.10.0" + resolved "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz" + integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== + acorn@^7.1.1: version "7.4.1" resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^8.2.4, acorn@^8.4.1, acorn@^8.9.0: - version "8.10.0" - resolved "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz" - integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== - adler-32@~1.3.0: version "1.3.1" resolved "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz" @@ -1291,7 +1291,14 @@ ansi-styles@^3.2.0, ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" -ansi-styles@^4.0.0, ansi-styles@^4.1.0: +ansi-styles@^4.0.0: + version "4.3.0" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== @@ -1428,7 +1435,7 @@ axios@^1.3.4: form-data "^4.0.0" proxy-from-env "^1.1.0" -babel-jest@^27.5.1: +babel-jest@^27.5.1, "babel-jest@>=27.0.0 <28": version "27.5.1" resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz" integrity sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg== @@ -1541,7 +1548,7 @@ browser-process-hrtime@^1.0.0: resolved "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz" integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== -browserslist@^4.21.9: +browserslist@^4.21.9, "browserslist@>= 4.21.0": version "4.21.9" resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz" integrity sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg== @@ -1623,7 +1630,12 @@ camelcase@^5.0.0, camelcase@^5.3.1: resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== -camelcase@^6.2.0, camelcase@^6.3.0: +camelcase@^6.2.0: + version "6.3.0" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +camelcase@^6.3.0: version "6.3.0" resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== @@ -1635,7 +1647,7 @@ caniuse-lite@^1.0.30001503: caseless@^0.12.0: version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz" integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw== cfb@~1.2.1: @@ -1777,16 +1789,16 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - color-name@~1.1.4: version "1.1.4" resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" @@ -1806,7 +1818,7 @@ concat-map@0.0.1: concat-stream@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-2.0.0.tgz#414cf5af790a48c60ab9be4527d56d5e41133cb1" + resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz" integrity sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A== dependencies: buffer-from "^1.0.0" @@ -1876,13 +1888,6 @@ date-fns@^2.29.3: dependencies: "@babel/runtime" "^7.21.0" -debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: - version "4.3.4" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - debug@^3.2.7: version "3.2.7" resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz" @@ -1890,6 +1895,13 @@ debug@^3.2.7: dependencies: ms "^2.1.1" +debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4, debug@4: + version "4.3.4" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + decamelize@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" @@ -1950,11 +1962,6 @@ dir-glob@^3.0.1: dependencies: path-type "^4.0.0" -discord-api-types@0.37.83: - version "0.37.83" - resolved "https://registry.yarnpkg.com/discord-api-types/-/discord-api-types-0.37.83.tgz#a22a799729ceded8176ea747157837ddf4708b1f" - integrity sha512-urGGYeWtWNYMKnYlZnOnDHm8fVRffQs3U0SpE8RHeiuLKb/u92APS8HoQnPTFbnXmY1vVnXjXO4dOxcAn3J+DA== - discord-api-types@^0.26.1: version "0.26.1" resolved "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.26.1.tgz" @@ -1975,6 +1982,11 @@ discord-api-types@^0.37.50: resolved "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.52.tgz" integrity sha512-TP99aMgY6rHuDIy056GDm1j2nGOcaLbFpjVbvAmv6N6vhkjHNqHXCHVqKtGisaQ8D15slbxTHNl/SSkPdx2syg== +discord-api-types@0.37.83: + version "0.37.83" + resolved "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.83.tgz" + integrity sha512-urGGYeWtWNYMKnYlZnOnDHm8fVRffQs3U0SpE8RHeiuLKb/u92APS8HoQnPTFbnXmY1vVnXjXO4dOxcAn3J+DA== + discord.js@^14: version "14.11.0" resolved "https://registry.npmjs.org/discord.js/-/discord.js-14.11.0.tgz" @@ -2026,7 +2038,7 @@ dotenv@^16.0.3: resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz" integrity sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ== -ecdsa-sig-formatter@1.0.11, ecdsa-sig-formatter@^1.0.11: +ecdsa-sig-formatter@^1.0.11, ecdsa-sig-formatter@1.0.11: version "1.0.11" resolved "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz" integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== @@ -2055,7 +2067,7 @@ emoji-regex@^8.0.0: env-paths@^2.2.0: version "2.2.1" - resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" + resolved "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz" integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== error-ex@^1.3.1: @@ -2231,7 +2243,7 @@ eslint-visitor-keys@^3.1.0, eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4 resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz" integrity sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA== -eslint@^8.13.0, eslint@^8.21.0, eslint@^8.7.0: +eslint@*, "eslint@^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8", "eslint@^6.0.0 || ^7.0.0 || ^8.0.0", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", eslint@^8.13.0, eslint@^8.21.0, eslint@^8.7.0, eslint@>=6.0.0, eslint@>=7.0.0, eslint@>=7.28.0: version "8.44.0" resolved "https://registry.npmjs.org/eslint/-/eslint-8.44.0.tgz" integrity sha512-0wpHoUbDUHgNCyvFB5aXLiQVfK9B0at6gUvzy83k4kAsQ/u769TQDX6iKC+aO4upIHO9WSaA3QoXYQDHbNwf1A== @@ -2380,7 +2392,7 @@ fast-glob@^3.2.9: merge2 "^1.3.0" micromatch "^4.0.4" -fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: +fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@2.x: version "2.1.0" resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -2409,9 +2421,9 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" -ffmpeg-static@^5.2.0: +"ffmpeg-static@^5.0.2 || ^4.2.7 || ^3.0.0 || ^2.4.0", ffmpeg-static@^5.2.0: version "5.2.0" - resolved "https://registry.yarnpkg.com/ffmpeg-static/-/ffmpeg-static-5.2.0.tgz#6ca64a5ed6e69ec4896d175c1f69dd575db7c5ef" + resolved "https://registry.npmjs.org/ffmpeg-static/-/ffmpeg-static-5.2.0.tgz" integrity sha512-WrM7kLW+do9HLr+H6tk7LzQ7kPqbAgLjdzNE32+u3Ff11gXt9Kkkd2nusGFrlWMIe+XaA97t+I8JS7sZIrvRgA== dependencies: "@derhuerst/http-basic" "^8.2.0" @@ -2520,7 +2532,7 @@ fs.realpath@^1.0.0: fsevents@^2.3.2, fsevents@~2.3.2: version "2.3.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== function-bind@^1.1.1: @@ -2885,7 +2897,7 @@ http-proxy-agent@^4.0.1: http-response-object@^3.0.1: version "3.0.2" - resolved "https://registry.yarnpkg.com/http-response-object/-/http-response-object-3.0.2.tgz#7f435bb210454e4360d074ef1f989d5ea8aa9810" + resolved "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz" integrity sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA== dependencies: "@types/node" "^10.0.3" @@ -2959,7 +2971,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.1, inherits@^2.0.3: +inherits@^2.0.1, inherits@^2.0.3, inherits@2: version "2.0.4" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -3446,7 +3458,7 @@ jest-resolve-dependencies@^27.5.1: jest-regex-util "^27.5.1" jest-snapshot "^27.5.1" -jest-resolve@^27.5.1: +jest-resolve@*, jest-resolve@^27.5.1: version "27.5.1" resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz" integrity sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw== @@ -3599,7 +3611,7 @@ jest-worker@^27.5.1: merge-stream "^2.0.0" supports-color "^8.0.0" -jest@^27.5.1: +jest@^27.0.0, jest@^27.5.1: version "27.5.1" resolved "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz" integrity sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ== @@ -3688,11 +3700,6 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= -json5@2.x, json5@^2.2.2: - version "2.2.3" - resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz" - integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== - json5@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz" @@ -3700,6 +3707,11 @@ json5@^1.0.2: dependencies: minimist "^1.2.0" +json5@^2.2.2, json5@2.x: + version "2.2.3" + resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + jwa@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz" @@ -3737,14 +3749,14 @@ levn@^0.4.1: libsodium-wrappers@^0.7.13: version "0.7.13" - resolved "https://registry.yarnpkg.com/libsodium-wrappers/-/libsodium-wrappers-0.7.13.tgz#83299e06ee1466057ba0e64e532777d2929b90d3" + resolved "https://registry.npmjs.org/libsodium-wrappers/-/libsodium-wrappers-0.7.13.tgz" integrity sha512-kasvDsEi/r1fMzKouIDv7B8I6vNmknXwGiYodErGuESoFTohGSKZplFtVxZqHaoQ217AynyIFgnOVRitpHs0Qw== dependencies: libsodium "^0.7.13" libsodium@^0.7.13: version "0.7.13" - resolved "https://registry.yarnpkg.com/libsodium/-/libsodium-0.7.13.tgz#230712ec0b7447c57b39489c48a4af01985fb393" + resolved "https://registry.npmjs.org/libsodium/-/libsodium-0.7.13.tgz" integrity sha512-mK8ju0fnrKXXfleL53vtp9xiPq5hKM0zbDQtcxQIsSmxNgSxqCj6R7Hl9PkrNe2j29T4yoDaF7DJLK9/i5iWUw== lines-and-columns@^1.1.6: @@ -3774,7 +3786,7 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" -lodash.memoize@4.x, lodash.memoize@^4.1.2: +lodash.memoize@^4.1.2, lodash.memoize@4.x: version "4.1.2" resolved "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz" integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= @@ -3828,7 +3840,7 @@ lru-cache@^7.17.0: m3u8stream@^0.8.6: version "0.8.6" - resolved "https://registry.yarnpkg.com/m3u8stream/-/m3u8stream-0.8.6.tgz#0d6de4ce8ee69731734e6b616e7b05dd9d9a55b1" + resolved "https://registry.npmjs.org/m3u8stream/-/m3u8stream-0.8.6.tgz" integrity sha512-LZj8kIVf9KCphiHmH7sbFQTVe4tOemb202fWwvJwR9W5ENW/1hxJN6ksAWGhQgSBSa3jyWhnjKU1Fw1GaOdbyA== dependencies: miniget "^4.2.2" @@ -3841,7 +3853,7 @@ make-dir@^3.0.0: dependencies: semver "^6.0.0" -make-error@1.x, make-error@^1.1.1: +make-error@^1.1.1, make-error@1.x: version "1.3.6" resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== @@ -3900,7 +3912,7 @@ mimic-fn@^2.1.0: miniget@^4.2.2: version "4.2.3" - resolved "https://registry.yarnpkg.com/miniget/-/miniget-4.2.3.tgz#3707a24c7c11c25d359473291638ab28aab349bd" + resolved "https://registry.npmjs.org/miniget/-/miniget-4.2.3.tgz" integrity sha512-SjbDPDICJ1zT+ZvQwK0hUcRY4wxlhhNpHL9nJOB2MEAXRGagTljsO8MEDzQMTFf0Q8g4QNi8P9lEm/g7e+qgzA== minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: @@ -3944,16 +3956,16 @@ moo@^0.5.1: resolved "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz" integrity sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q== -ms@2.1.2: - version "2.1.2" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - ms@^2.1.1: version "2.1.3" resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== +ms@2.1.2: + version "2.1.2" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + mz@^2.4.0: version "2.7.0" resolved "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz" @@ -4108,7 +4120,14 @@ optionator@^0.9.3: prelude-ls "^1.2.1" type-check "^0.4.0" -p-limit@^2.0.0, p-limit@^2.2.0: +p-limit@^2.0.0: + version "2.3.0" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^2.2.0: version "2.3.0" resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== @@ -4162,7 +4181,7 @@ parent-module@^1.0.0: parse-cache-control@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/parse-cache-control/-/parse-cache-control-1.0.1.tgz#8eeab3e54fa56920fe16ba38f77fa21aacc2d74e" + resolved "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz" integrity sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg== parse-json@^5.2.0: @@ -4182,16 +4201,16 @@ parse5-htmlparser2-tree-adapter@^6.0.0: dependencies: parse5 "^6.0.1" -parse5@6.0.1, parse5@^6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz" - integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== - parse5@^5.1.1: version "5.1.1" resolved "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz" integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== +parse5@^6.0.1, parse5@6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz" + integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== + path-exists@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz" @@ -4281,7 +4300,7 @@ pg-types@^4.0.1: postgres-interval "^3.0.0" postgres-range "^1.1.1" -pg@^8.7.3: +pg@^8.5.1, pg@^8.7.3, pg@>=8.0: version "8.11.1" resolved "https://registry.npmjs.org/pg/-/pg-8.11.1.tgz" integrity sha512-utdq2obft07MxaDg0zBJI+l/M3mBRfIpEN3iSemsz0G5F2/VXx+XzqF4oxrbIZXQxt2AZzIUzyVg/YM6xOP/WQ== @@ -4304,9 +4323,9 @@ pgpass@1.x: split2 "^4.1.0" picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + version "1.1.1" + resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" @@ -4403,7 +4422,7 @@ prettier-eslint-cli@^7.1.0: rxjs "^7.5.6" yargs "^13.1.1" -prettier-eslint@^15.0.1: +prettier-eslint@*, prettier-eslint@^15.0.1: version "15.0.1" resolved "https://registry.npmjs.org/prettier-eslint/-/prettier-eslint-15.0.1.tgz" integrity sha512-mGOWVHixSvpZWARqSDXbdtTL54mMBxc5oQYQ6RAqy8jecuNJBgN3t9E5a81G66F8x8fsKNiR1HWaBV66MJDOpg== @@ -4430,7 +4449,7 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" -prettier@^2.5.1, prettier@^2.6.2: +prettier@^2.5.1, prettier@^2.6.2, prettier@>=2.0.0: version "2.8.8" resolved "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz" integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== @@ -4454,10 +4473,10 @@ pretty-format@^27.0.0, pretty-format@^27.5.1: prism-media@^1.3.5: version "1.3.5" - resolved "https://registry.yarnpkg.com/prism-media/-/prism-media-1.3.5.tgz#ea1533229f304a1b774b158de40e98c765db0aa6" + resolved "https://registry.npmjs.org/prism-media/-/prism-media-1.3.5.tgz" integrity sha512-IQdl0Q01m4LrkN1EGIE9lphov5Hy7WWlH6ulf5QdGePLlPas9p2mhgddTEHrlaXYjjFToM1/rWuwF37VF4taaA== -prisma@^5.2.0: +prisma@*, prisma@^5.2.0: version "5.2.0" resolved "https://registry.npmjs.org/prisma/-/prisma-5.2.0.tgz" integrity sha512-FfFlpjVCkZwrqxDnP4smlNYSH1so+CbfjgdpioFzGGqlQAEm6VHAYSzV7jJgC3ebtY9dNOhDMS2+4/1DDSM7bQ== @@ -4466,7 +4485,7 @@ prisma@^5.2.0: progress@^2.0.3: version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== prompts@^2.0.1: @@ -4547,7 +4566,7 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" -redis@^4.6.5: +"redis@^3.1.1 || ^4.0.0", redis@^4.6.5: version "4.6.7" resolved "https://registry.npmjs.org/redis/-/redis-4.6.7.tgz" integrity sha512-KrkuNJNpCwRm5vFJh0tteMxW8SaUzkm5fBH7eL5hd/D0fAkzvapxbfGPP/r+4JAXdQuX7nebsBkBqA2RHB7Usw== @@ -4566,7 +4585,7 @@ reflect-metadata@^0.1.13: reflect-metadata@^0.2.2: version "0.2.2" - resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.2.2.tgz#400c845b6cba87a21f2c65c4aeb158f4fa4d9c5b" + resolved "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz" integrity sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q== regenerator-runtime@^0.13.11: @@ -4686,7 +4705,7 @@ safe-regex-test@^1.0.0: sax@^1.1.3, sax@^1.2.4: version "1.4.1" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f" + resolved "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz" integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg== saxes@^5.0.1: @@ -4696,23 +4715,28 @@ saxes@^5.0.1: dependencies: xmlchars "^2.2.0" -semver@7.x, semver@^7.3.2, semver@^7.3.5, semver@^7.3.7: - version "7.5.4" - resolved "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz" - integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== - dependencies: - lru-cache "^6.0.0" - semver@^5.7.1: version "5.7.2" resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz" integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== -semver@^6.0.0, semver@^6.3.0: +semver@^6.0.0: version "6.3.1" resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== +semver@^6.3.0: + version "6.3.1" + resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.3.2, semver@^7.3.5, semver@^7.3.7, semver@7.x: + version "7.5.4" + resolved "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + dependencies: + lru-cache "^6.0.0" + semver@~7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz" @@ -4826,6 +4850,13 @@ streamsearch@^1.1.0: resolved "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz" integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + string-length@^4.0.1: version "4.0.2" resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz" @@ -4879,13 +4910,6 @@ string.prototype.trimstart@^1.0.6: define-properties "^1.1.4" es-abstract "^1.20.4" -string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - strip-ansi@^3.0.0: version "3.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz" @@ -4940,7 +4964,14 @@ supports-color@^2.0.0: resolved "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz" integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= -supports-color@^5.3.0, supports-color@^5.5.0: +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^5.5.0: version "5.5.0" resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== @@ -5053,9 +5084,9 @@ touch@^3.1.0: nopt "~1.0.10" tough-cookie@^4.0.0: - version "4.1.3" - resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz" - integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw== + version "4.1.4" + resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz" + integrity sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag== dependencies: psl "^1.1.33" punycode "^2.1.1" @@ -5093,7 +5124,7 @@ ts-mixer@^6.0.0, ts-mixer@^6.0.3: resolved "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.3.tgz" integrity sha512-k43M7uCG1AkTyxgnmI5MPwKoUvS/bRvLvUb7+Pgpdlmok8AoqmUaZxUUw8zKM5B1lqZrt41GjYgnvAi0fppqgQ== -ts-node@^10.7.0: +ts-node@^10.7.0, ts-node@>=9.0.0: version "10.9.1" resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz" integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== @@ -5122,7 +5153,12 @@ tsconfig-paths@^3.14.1: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@^1.8.1, tslib@^1.9.3: +tslib@^1.8.1: + version "1.14.1" + resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tslib@^1.9.3: version "1.14.1" resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== @@ -5139,7 +5175,7 @@ tslib@^2.6.1: tslib@^2.6.2: version "2.6.3" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz" integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ== tsutils@^3.21.0: @@ -5151,7 +5187,7 @@ tsutils@^3.21.0: tsyringe@^4.8.0: version "4.8.0" - resolved "https://registry.yarnpkg.com/tsyringe/-/tsyringe-4.8.0.tgz#d599651b36793ba872870fee4f845bd484a5cac1" + resolved "https://registry.npmjs.org/tsyringe/-/tsyringe-4.8.0.tgz" integrity sha512-YB1FG+axdxADa3ncEtRnQCFq/M0lALGLxSZeVNbTU8NqhOVc51nnv2CISTcvc1kyv6EGPtXVr0v6lWeDxiijOA== dependencies: tslib "^1.9.3" @@ -5201,7 +5237,7 @@ typedarray-to-buffer@^3.1.5: typedarray@^0.0.6: version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz" integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== typeorm@^0.3.6: @@ -5225,7 +5261,7 @@ typeorm@^0.3.6: uuid "^9.0.0" yargs "^17.6.2" -typescript@^4.5.4, typescript@^4.6.3: +typescript@^4.5.4, typescript@^4.6.3, typescript@>=2.7, "typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta", "typescript@>=3.8 <5.0": version "4.9.5" resolved "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz" integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== @@ -5477,7 +5513,7 @@ ws@^8.13.0: ws@^8.16.0: version "8.17.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" + resolved "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz" integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== xlsx@^0.18.5: @@ -5518,20 +5554,15 @@ y18n@^5.0.5: resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== -yallist@4.0.0, yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - yallist@^3.0.2: version "3.1.1" resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== -yargs-parser@20.x, yargs-parser@^20.2.2: - version "20.2.9" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz" - integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== +yallist@^4.0.0, yallist@4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== yargs-parser@^13.1.2: version "13.1.2" @@ -5541,6 +5572,11 @@ yargs-parser@^13.1.2: camelcase "^5.0.0" decamelize "^1.2.0" +yargs-parser@^20.2.2, yargs-parser@20.x: + version "20.2.9" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" @@ -5600,7 +5636,7 @@ yocto-queue@^0.1.0: ytdl-core@^4.11.5: version "4.11.5" - resolved "https://registry.yarnpkg.com/ytdl-core/-/ytdl-core-4.11.5.tgz#8cc3dc9e4884e24e8251250cfb56313a300811f0" + resolved "https://registry.npmjs.org/ytdl-core/-/ytdl-core-4.11.5.tgz" integrity sha512-27LwsW4n4nyNviRCO1hmr8Wr5J1wLLMawHCQvH8Fk0hiRqrxuIu028WzbJetiYH28K8XDbeinYW4/wcHQD1EXA== dependencies: m3u8stream "^0.8.6"