From 7b41fe9208a8a5c262bd5913f52945f20d80ed40 Mon Sep 17 00:00:00 2001 From: hjdhjd Date: Wed, 10 Jul 2024 17:15:25 -0500 Subject: [PATCH 1/4] Address all open deprecations and HAP-NodeJS deprecations. (#3648) --- src/api.ts | 4 -- src/bridgeService.ts | 87 +++++++++++++++------------------------ src/childBridgeService.ts | 1 - src/index.ts | 45 -------------------- src/logger.spec.ts | 64 +--------------------------- src/logger.ts | 39 ------------------ src/platformAccessory.ts | 34 --------------- src/plugin.ts | 7 ++-- src/server.ts | 5 --- 9 files changed, 39 insertions(+), 247 deletions(-) diff --git a/src/api.ts b/src/api.ts index 5c4f3587d..c93da90f5 100644 --- a/src/api.ts +++ b/src/api.ts @@ -203,10 +203,6 @@ export interface API { updatePlatformAccessories(accessories: PlatformAccessory[]): void; unregisterPlatformAccessories(pluginIdentifier: PluginIdentifier, platformName: PlatformName, accessories: PlatformAccessory[]): void; - /** - * @deprecated use {@link publishExternalAccessories} directly to publish a standalone Accessory - */ - publishCameraAccessories(pluginIdentifier: PluginIdentifier, accessories: PlatformAccessory[]): void; publishExternalAccessories(pluginIdentifier: PluginIdentifier, accessories: PlatformAccessory[]): void; on(event: "didFinishLaunching", listener: () => void): this; diff --git a/src/bridgeService.ts b/src/bridgeService.ts index aa00ed394..74886f6bf 100644 --- a/src/bridgeService.ts +++ b/src/bridgeService.ts @@ -1,7 +1,6 @@ import { Accessory, AccessoryEventTypes, - AccessoryLoader, Bridge, Categories, Characteristic, @@ -79,12 +78,6 @@ export interface PlatformConfig extends Record { export interface HomebridgeConfig { bridge: BridgeConfiguration; - /** - * @deprecated - */ - // eslint-disable-next-line @typescript-eslint/no-explicit-any - mdns?: any; // this is deprecated and not used anymore - accessories: AccessoryConfig[]; platforms: PlatformConfig[]; @@ -203,7 +196,6 @@ export class BridgeService { pincode: bridgeConfig.pin, category: Categories.BRIDGE, bind: bridgeConfig.bind, - mdns: this.config.mdns, // this is deprecated now addIdentifyingMaterial: true, advertiser: bridgeConfig.advertiser, }; @@ -446,7 +438,6 @@ export class BridgeService { category: accessory.category, port: accessoryPort, bind: this.bridgeConfig.bind, - mdns: this.config.mdns, // this is deprecated and not used anymore addIdentifyingMaterial: true, advertiser: this.bridgeConfig.advertiser, }; @@ -466,55 +457,45 @@ export class BridgeService { return undefined; } - if (!(services[0] instanceof Service)) { - // The returned "services" for this accessory is assumed to be the old style: a big array - // of JSON-style objects that will need to be parsed by HAP-NodeJS's AccessoryLoader. - - return AccessoryLoader.parseAccessoryJSON({ // Create the actual HAP-NodeJS "Accessory" instance - displayName: displayName, - services: services, + // The returned "services" for this accessory are simply an array of new-API-style + // Service instances which we can add to a created HAP-NodeJS Accessory directly. + const accessoryUUID = uuid.generate(accessoryType + ":" + (uuidBase || displayName)); + const accessory = new Accessory(displayName, accessoryUUID); + + // listen for the identify event if the accessory instance has defined an identify() method + if (accessoryInstance.identify) { + accessory.on(AccessoryEventTypes.IDENTIFY, (paired: boolean, callback: VoidCallback) => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + // eslint-disable-next-line @typescript-eslint/no-empty-function + accessoryInstance.identify!(() => { }); // empty callback for backwards compatibility + callback(); }); - } else { - // The returned "services" for this accessory are simply an array of new-API-style - // Service instances which we can add to a created HAP-NodeJS Accessory directly. - const accessoryUUID = uuid.generate(accessoryType + ":" + (uuidBase || displayName)); - const accessory = new Accessory(displayName, accessoryUUID); - - // listen for the identify event if the accessory instance has defined an identify() method - if (accessoryInstance.identify) { - accessory.on(AccessoryEventTypes.IDENTIFY, (paired: boolean, callback: VoidCallback) => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - // eslint-disable-next-line @typescript-eslint/no-empty-function - accessoryInstance.identify!(() => { }); // empty callback for backwards compatibility - callback(); - }); - } + } - const informationService = accessory.getService(Service.AccessoryInformation)!; - services.forEach(service => { - // if you returned an AccessoryInformation service, merge its values with ours - if (service instanceof Service.AccessoryInformation) { - service.setCharacteristic(Characteristic.Name, displayName); // ensure display name is set - // ensure the plugin has not hooked already some listeners (some weird ones do). - // Otherwise, they would override our identify listener registered by the HAP-NodeJS accessory - service.getCharacteristic(Characteristic.Identify).removeAllListeners(CharacteristicEventTypes.SET); - - // pull out any values and listeners (get and set) you may have defined - informationService.replaceCharacteristicsFromService(service); - } else { - accessory.addService(service); - } - }); + const informationService = accessory.getService(Service.AccessoryInformation)!; + services.forEach(service => { + // if you returned an AccessoryInformation service, merge its values with ours + if (service instanceof Service.AccessoryInformation) { + service.setCharacteristic(Characteristic.Name, displayName); // ensure display name is set + // ensure the plugin has not hooked already some listeners (some weird ones do). + // Otherwise, they would override our identify listener registered by the HAP-NodeJS accessory + service.getCharacteristic(Characteristic.Identify).removeAllListeners(CharacteristicEventTypes.SET); + + // pull out any values and listeners (get and set) you may have defined + informationService.replaceCharacteristicsFromService(service); + } else { + accessory.addService(service); + } + }); - accessory.on(AccessoryEventTypes.CHARACTERISTIC_WARNING, BridgeService.printCharacteristicWriteWarning.bind(this, plugin, accessory, {})); + accessory.on(AccessoryEventTypes.CHARACTERISTIC_WARNING, BridgeService.printCharacteristicWriteWarning.bind(this, plugin, accessory, {})); - controllers.forEach(controller => { - accessory.configureController(controller); - }); + controllers.forEach(controller => { + accessory.configureController(controller); + }); - return accessory; - } + return accessory; } public async loadPlatformAccessories(plugin: Plugin, platformInstance: StaticPlatformPlugin, platformType: PlatformName | PlatformIdentifier, logger: Logging): Promise { diff --git a/src/childBridgeService.ts b/src/childBridgeService.ts index 9ce7c7d9e..bb7492767 100644 --- a/src/childBridgeService.ts +++ b/src/childBridgeService.ts @@ -380,7 +380,6 @@ export class ChildBridgeService { bridgeOptions, homebridgeConfig: { // need to break this out to avoid a circular structure to JSON from other plugins modifying their config at runtime. bridge: this.homebridgeConfig.bridge, - mdns: this.homebridgeConfig.mdns, ports: this.homebridgeConfig.ports, disabledPlugins: [], // not used by child bridges accessories: [], // not used by child bridges diff --git a/src/index.ts b/src/index.ts index ba4616172..97995ba10 100644 --- a/src/index.ts +++ b/src/index.ts @@ -122,7 +122,6 @@ export { Categories, ChangeReason, CharacteristicEventTypes, - // CharacteristicWarningType, DataFormatTags, DataStreamConnectionEvent, DataStreamServerEvent, @@ -132,8 +131,6 @@ export { Formats, H264Level, H264Profile, - // HAPHTTPCode, - // HAPPairingHTTPCode, HAPServerEventTypes, HAPStatus, HDSProtocolSpecificErrorReason, @@ -166,9 +163,7 @@ export type { */ export type { AccessControlManagement, - // Accessory, AdaptiveLightingController, - // Bridge, CameraController, Characteristic, ColorUtils, @@ -178,27 +173,15 @@ export type { DataStreamServer, DataStreamWriter, DoorbellController, - // Float32, - // Float64, HAPServer, HAPStorage, HapStatusError, - HomeKitRemoteController, - // Int16, - // Int32, - // Int64, - // Int8, HDSProtocolError, - LegacyCameraSourceAdapter, RecordingManagement, RemoteController, RTPStreamManagement, - // SecondsSince2001, Service, SiriAudioSession, - StreamController, - // UUID, - // ValueWrapper, } from "hap-nodejs"; /** @@ -222,7 +205,6 @@ export type { DataStreamProtocolHandler, DoorbellOptions, H264CodecParameters, - LegacyCameraSource, MediaContainerConfiguration, ProxiedSourceResponse, PublishInfo, @@ -247,8 +229,6 @@ export type { AccessoryCharacteristicChange, AddPairingCallback, AdditionalAuthorizationHandler, - Address, - AudioCodec, AudioCodecConfiguration, AudioCodecParameters, AudioFrame, @@ -258,7 +238,6 @@ export type { AudioStreamingCodec, AudioStreamingOptions, ButtonConfiguration, - Camera, CameraRecordingOptions, CameraStreamingOptions, CharacteristicChange, @@ -269,7 +248,6 @@ export type { CharacteristicValue, ConstructorArgs, ControllerType, - DataSendCloseReason, ErrorHandler, EventHandler, FrameHandler, @@ -294,8 +272,6 @@ export type { PrepareStreamRequest, PrepareStreamResponse, PreparedDataStreamSession, - PreparedStreamRequestCallback, - PreparedStreamResponse, PrimitiveTypes, RTPTime, ReadCharacteristicsCallback, @@ -316,18 +292,13 @@ export type { StartStreamRequest, StateChangeDelegate, StopStreamRequest, - StreamAudioParams, - StreamControllerOptions, - StreamRequest, StreamRequestCallback, StreamSessionIdentifier, - StreamVideoParams, StreamingRequest, SupportedButtonConfiguration, SupportedConfiguration, TLVEncodable, TargetConfiguration, - VideoCodec, VideoInfo, VideoStreamingOptions, VoidCallback, @@ -339,10 +310,7 @@ export type { * Export HAP-NodeJS variables as type only */ export type { - // AccessoryLoader, - Codes, LegacyTypes, - Status, uuid, } from "hap-nodejs"; @@ -357,18 +325,5 @@ export type { encode, epochMillisFromMillisSince2001_01_01, epochMillisFromMillisSince2001_01_01Buffer, - // init, - // isSerializableController, - // loadDirectory, once, - // parseAccessoryJSON, - // parseCharacteristicJSON, - // parseServiceJSON, - // readUInt16, - // readUInt32, - // readUInt64, - // readUInt64BE, - // writeUInt16, - // writeUInt32, - // writeUInt64, } from "hap-nodejs"; diff --git a/src/logger.spec.ts b/src/logger.spec.ts index 4cb5eca7b..63137cd8e 100644 --- a/src/logger.spec.ts +++ b/src/logger.spec.ts @@ -1,11 +1,5 @@ import chalk from "chalk"; -import { - forceColor, - Logger, - setDebugEnabled, - setTimestampEnabled, - withPrefix, -} from "./logger"; +import { Logger } from "./logger"; describe("Logger", () => { let consoleLogSpy: jest.SpyInstance; @@ -56,13 +50,6 @@ describe("Logger", () => { expect(consoleLogSpy).not.toHaveBeenCalled(); }); - it("should not log debug level messages when debug is disabled (via func)", () => { - setDebugEnabled(false); - const logger = Logger.withPrefix("test"); - logger.debug("test message"); - expect(consoleLogSpy).not.toHaveBeenCalled(); - }); - it("should log debug level messages when debug is enabled (via method, no param)", () => { Logger.setDebugEnabled(); const logger = Logger.withPrefix("test"); @@ -79,22 +66,6 @@ describe("Logger", () => { Logger.setDebugEnabled(false); // reset debug setting }); - it("should log debug level messages when debug is enabled (via func, no param)", () => { - setDebugEnabled(); - const logger = Logger.withPrefix("test"); - logger.debug("test message"); - expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining("test message")); - setDebugEnabled(false); // reset debug setting - }); - - it("should log debug level messages when debug is enabled (via func, with param)", () => { - setDebugEnabled(true); - const logger = Logger.withPrefix("test"); - logger.debug("test message"); - expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining("test message")); - setDebugEnabled(false); // reset debug setting - }); - it("should not include timestamps in log messages when timestamp is disabled (via method)", () => { Logger.setTimestampEnabled(false); const logger = Logger.withPrefix("test"); @@ -102,13 +73,6 @@ describe("Logger", () => { expect(consoleLogSpy).not.toHaveBeenCalledWith(expect.stringMatching(/\[\d{1,2}\/\d{1,2}\/\d{4}, \d{1,2}:\d{2}:\d{2} (AM|PM)].*/)); }); - it("should not include timestamps in log messages when timestamp is disabled (via func)", () => { - setTimestampEnabled(false); - const logger = Logger.withPrefix("test"); - logger.info("test message"); - expect(consoleLogSpy).not.toHaveBeenCalledWith(expect.stringMatching(/\[\d{1,2}\/\d{1,2}\/\d{4}, \d{1,2}:\d{2}:\d{2} (AM|PM)].*/)); - }); - it("should include timestamps in log messages when timestamp is enabled (via method, no param)", () => { Logger.setTimestampEnabled(); const logger = Logger.withPrefix("test"); @@ -125,37 +89,11 @@ describe("Logger", () => { Logger.setTimestampEnabled(false); // reset timestamp setting }); - it("should include timestamps in log messages when timestamp is enabled (via func, no param)", () => { - setTimestampEnabled(); - const logger = Logger.withPrefix("test"); - logger.info("test message"); - expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringMatching(/\[\d{1,2}\/\d{1,2}\/\d{4}, \d{1,2}:\d{2}:\d{2} (AM|PM)].*/)); - setTimestampEnabled(false); // reset timestamp setting - }); - - it("should include timestamps in log messages when timestamp is enabled (via func, with param)", () => { - setTimestampEnabled(true); - const logger = Logger.withPrefix("test"); - logger.info("test message"); - expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringMatching(/\[\d{1,2}\/\d{1,2}\/\d{4}, \d{1,2}:\d{2}:\d{2} (AM|PM)].*/)); - setTimestampEnabled(false); // reset timestamp setting - }); - it("should set chalk level to 1 when forceColor is enabled (via method)", () => { Logger.forceColor(); expect(chalk.level).toBe(1); }); - it("should set chalk level to 1 when forceColor is enabled (via func)", () => { - forceColor(); - expect(chalk.level).toBe(1); - }); - - it("should create a new logger with a prefix when withPrefix is called", () => { - const logger = withPrefix("test"); - expect(logger.prefix).toBe("test"); - }); - it("should return the same logger when called with the same prefix", () => { const logger1 = Logger.withPrefix("test"); const logger2 = Logger.withPrefix("test"); diff --git a/src/logger.ts b/src/logger.ts index a67accf69..fc61cc5bb 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -191,16 +191,6 @@ export class Logger { } -/** - * Creates a new Logging device with a specified prefix. - * - * @param prefix {string} - the prefix of the logger - * @deprecated please use {@link Logger.withPrefix} directly - */ -export function withPrefix(prefix: string): Logging { - return Logger.withPrefix(prefix); -} - /** * Gets the prefix * @param prefix @@ -208,32 +198,3 @@ export function withPrefix(prefix: string): Logging { export function getLogPrefix(prefix: string): string { return chalk.cyan(`[${prefix}]`); } - -/** - * Turns on debug level logging. Off by default. - * - * @param enabled {boolean} - * @deprecated please use {@link Logger.setDebugEnabled} directly - */ -export function setDebugEnabled(enabled: boolean = true): void { - Logger.setDebugEnabled(enabled); -} - -/** - * Turns on inclusion of timestamps in log messages. On by default. - * - * @param enabled {boolean} - * @deprecated please use {@link Logger.setTimestampEnabled} directly - */ -export function setTimestampEnabled(enabled: boolean = true): void { - Logger.setTimestampEnabled(enabled); -} - -/** - * Forces color in logging output, even if it seems like color is unsupported. - * - * @deprecated please use {@link Logger.forceColor} directly - */ -export function forceColor(): void { - chalk.level = 1; // `1` - Basic 16 colors support. -} diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index 18c6b8f0a..43417cc43 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -2,11 +2,9 @@ import { EventEmitter } from "events"; import { Accessory, AccessoryEventTypes, - CameraController, Categories, Controller, ControllerConstructor, - LegacyCameraSource, SerializedAccessory, Service, VoidCallback, @@ -54,10 +52,6 @@ export class PlatformAccessory exten UUID: string; category: Categories; services: Service[] = []; - /** - * @deprecated reachability has no effect and isn't supported anymore - */ - reachable = false; // ------------------------------------------------------ /** @@ -114,38 +108,10 @@ export class PlatformAccessory exten return this._associatedHAPAccessory.getService(name); } - /** - * - * @param uuid - * @param subType - * @deprecated use {@link getServiceById} directly - */ - public getServiceByUUIDAndSubType>(uuid: string | T, subType: string): Service | undefined { - return this.getServiceById(uuid, subType); - } - public getServiceById>(uuid: string | T, subType: string): Service | undefined { return this._associatedHAPAccessory.getServiceById(uuid, subType); } - /** - * - * @param reachable - * @deprecated reachability has no effect and isn't supported anymore - */ - public updateReachability(reachable: boolean): void { - this.reachable = reachable; - } - - /** - * - * @param cameraSource - * @deprecated see {@link https://developers.homebridge.io/HAP-NodeJS/classes/accessory.html#configurecamerasource | Accessory.configureCameraSource} - */ - public configureCameraSource(cameraSource: LegacyCameraSource): CameraController { - return this._associatedHAPAccessory.configureCameraSource(cameraSource); - } - /** * Configures a new controller for the given accessory. * See {@link https://developers.homebridge.io/HAP-NodeJS/classes/accessory.html#configurecontroller | Accessory.configureController}. diff --git a/src/plugin.ts b/src/plugin.ts index 77af8938b..6bba89b59 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -154,9 +154,10 @@ export class Plugin { throw new Error(`The requested platform '${name}' was not registered by the plugin '${this.getPluginIdentifier()}'.`); } - if (this.activeDynamicPlatforms.has(name)) { // if it's a dynamic platform check that it is not enabled multiple times - log.error("The dynamic platform " + name + " from the plugin " + this.getPluginIdentifier() + " seems to be configured " + - "multiple times in your config.json. This behaviour was deprecated in homebridge v1.0.0 and will be removed in v2.0.0!"); + // If it's a dynamic platform plugin, ensure it's not enabled multiple times. + if (this.activeDynamicPlatforms.has(name)) { + throw new Error("The dynamic platform " + name + " from the plugin " + this.getPluginIdentifier() + " is configured " + + "times in your config.json."); } return constructor; diff --git a/src/server.ts b/src/server.ts index 56f101e04..e35f2e507 100644 --- a/src/server.ts +++ b/src/server.ts @@ -281,11 +281,6 @@ export class Server { config.bridge.advertiser = undefined; } - // Warn existing Homebridge 1.3.0 beta users they need to swap to bridge.advertiser - if (config.mdns && config.mdns.legacyAdvertiser === false && config.bridge.advertiser === MDNSAdvertiser.BONJOUR) { - log.error(`The "mdns"."legacyAdvertiser" = false option has been removed. Please use "bridge"."advertiser" = "${MDNSAdvertiser.CIAO}" to enable the Ciao mDNS advertiser. You should remove the "mdns"."legacyAdvertiser" section from your config.json.`); - } - return config as HomebridgeConfig; } From 34990a01381653d8b26ccedbdc2a4e08b005abca Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Sun, 8 Jun 2025 01:04:22 +0100 Subject: [PATCH 2/4] general code modernisation (#3681) --- .eslintrc | 38 - .github/homebridge-reddit.svg | 2 +- .github/labeler.yml | 6 +- .github/workflows/alpha-release.yml | 12 +- .github/workflows/beta-release.yml | 14 +- .github/workflows/codeql-analysis.yml | 6 +- .github/workflows/labeler.yml | 2 +- .github/workflows/release.yml | 8 +- .../workflows/wiki-change-notification.yml | 2 +- .gitignore | 2 +- .vscode/settings.json | 4 +- CHANGELOG.md | 26 + README.md | 33 +- bin/homebridge | 17 - bin/homebridge.js | 22 + config-sample.json | 6 +- docs/index.html | 2 +- eslint.config.js | 54 + jest.config.js | 9 - nodemon.json | 4 +- package-lock.json | 8578 +++++++++-------- package.json | 81 +- src/api.spec.ts | 91 +- src/api.ts | 261 +- src/bridgeService.ts | 480 +- src/childBridgeFork.ts | 271 +- src/childBridgeService.ts | 386 +- src/cli.ts | 153 +- src/externalPortService.ts | 48 +- src/index.ts | 141 +- src/ipcService.ts | 41 +- src/logger.spec.ts | 214 +- src/logger.ts | 164 +- src/platformAccessory.spec.ts | 301 +- src/platformAccessory.ts | 130 +- src/plugin.ts | 205 +- src/pluginManager.spec.ts | 115 +- src/pluginManager.ts | 426 +- src/server.spec.ts | 92 +- src/server.ts | 502 +- src/storageService.ts | 33 +- src/types/qrcode-terminal.d.ts | 14 +- src/user.spec.ts | 59 +- src/user.ts | 24 +- src/util/mac.spec.ts | 64 +- src/util/mac.ts | 21 +- src/version.spec.ts | 83 +- src/version.ts | 17 +- tsconfig.json | 25 +- vitest.config.js | 11 + 50 files changed, 6852 insertions(+), 6448 deletions(-) delete mode 100644 .eslintrc delete mode 100755 bin/homebridge create mode 100755 bin/homebridge.js create mode 100644 eslint.config.js delete mode 100644 jest.config.js create mode 100644 vitest.config.js diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index f58d32a16..000000000 --- a/.eslintrc +++ /dev/null @@ -1,38 +0,0 @@ -{ - "parser": "@typescript-eslint/parser", - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/eslint-recommended", - "plugin:@typescript-eslint/recommended", // uses the recommended rules from the @typescript-eslint/eslint-plugin - "plugin:jest/recommended" // enables eslint-plugin-jest - ], - "plugins": ["import", "import-newlines"], - "parserOptions": { - "ecmaVersion": 2018, - "sourceType": "module" - }, - "ignorePatterns": [ - "bin/", - "lib/" - ], - "rules": { - "quotes": ["error", "double"], - "indent": ["error", 2, { "SwitchCase": 1 }], - "linebreak-style": ["error", "unix"], - "semi": ["error", "always"], - - "comma-dangle": ["error", "always-multiline"], - "dot-notation": "error", - "eqeqeq": ["error", "always", {"null": "ignore"}], - "curly": ["error", "all"], - "brace-style": ["error"], - - "import/order": ["warn", { "alphabetize": { "order": "asc" }, "newlines-between": "never" }], - "import/prefer-default-export": "off", - "import-newlines/enforce": ["error", 3], - - "@typescript-eslint/no-unsafe-declaration-merging": "off", - "@typescript-eslint/no-non-null-assertion": "off", // currently disabled, hap-nodejs has some bad typing (like getCharacteristic) for this to be enabled - "@typescript-eslint/no-unused-vars": ["error", { "caughtErrors": "none" }], - } -} diff --git a/.github/homebridge-reddit.svg b/.github/homebridge-reddit.svg index 854cc1df7..95967a257 100644 --- a/.github/homebridge-reddit.svg +++ b/.github/homebridge-reddit.svg @@ -176,4 +176,4 @@ - \ No newline at end of file + diff --git a/.github/labeler.yml b/.github/labeler.yml index 98f259891..8ef4615df 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -1,11 +1,11 @@ # Add 'beta' label to any PR where the head branch name starts with `beta` or has a `beta` section in the name beta: - - base-branch: ['^beta', 'beta', 'beta*'] + - base-branch: [^beta, beta, 'beta*'] # Add 'alpha' label to any PR where the head branch name starts with `alpha` or has an `alpha` section in the name alpha: - - base-branch: ['^alpha', 'alpha', 'alpha*'] + - base-branch: [^alpha, alpha, 'alpha*'] # Add 'latest' label to any PR where the head branch name starts with `latest` or has a `latest` section in the name latest: - - base-branch: ['^latest', 'latest', 'latest*'] + - base-branch: [^latest, latest, 'latest*'] diff --git a/.github/workflows/alpha-release.yml b/.github/workflows/alpha-release.yml index c828339cb..9a4273715 100644 --- a/.github/workflows/alpha-release.yml +++ b/.github/workflows/alpha-release.yml @@ -8,12 +8,12 @@ on: jobs: publish: if: ${{ github.repository == 'homebridge/homebridge' }} - uses: homebridge/.github/.github/workflows/npm-publish.yml@latest + uses: homebridge/.github/.github/workflows/npm-publish-esm.yml@latest with: - tag: 'alpha' + tag: alpha dynamically_adjust_version: true - npm_version_command: 'pre' - pre_id: 'alpha' + npm_version_command: pre + pre_id: alpha secrets: npm_auth_token: ${{ secrets.npm_token }} @@ -22,9 +22,9 @@ jobs: needs: [publish] uses: homebridge/.github/.github/workflows/discord-webhooks.yml@latest with: - title: "Homebridge Alpha Release" + title: Homebridge Alpha Release description: | Version `v${{ needs.publish.outputs.NPM_VERSION }}` - url: "https://github.com/homebridge/homebridge/releases/tag/v${{ needs.publish.outputs.NPM_VERSION }}" + url: 'https://github.com/homebridge/homebridge/releases/tag/v${{ needs.publish.outputs.NPM_VERSION }}' secrets: DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK_URL_BETA }} diff --git a/.github/workflows/beta-release.yml b/.github/workflows/beta-release.yml index 4aca52288..1c309a417 100644 --- a/.github/workflows/beta-release.yml +++ b/.github/workflows/beta-release.yml @@ -21,23 +21,23 @@ jobs: if: ${{ github.repository == 'homebridge/homebridge' }} - uses: homebridge/.github/.github/workflows/npm-publish.yml@latest + uses: homebridge/.github/.github/workflows/npm-publish-esm.yml@latest with: - tag: 'beta' + tag: beta dynamically_adjust_version: true - npm_version_command: 'pre' - pre_id: 'beta' + npm_version_command: pre + pre_id: beta secrets: npm_auth_token: ${{ secrets.npm_token }} github-releases-to-discord: name: Discord Webhooks - needs: [build_and_test,publish] + needs: [build_and_test, publish] uses: homebridge/.github/.github/workflows/discord-webhooks.yml@latest with: - title: "Homebridge Beta Release" + title: Homebridge Beta Release description: | Version `v${{ needs.publish.outputs.NPM_VERSION }}` - url: "https://github.com/homebridge/homebridge/releases/tag/v${{ needs.publish.outputs.NPM_VERSION }}" + url: 'https://github.com/homebridge/homebridge/releases/tag/v${{ needs.publish.outputs.NPM_VERSION }}' secrets: DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK_URL_BETA }} diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index a3faf80d9..ca3f3f004 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -1,10 +1,10 @@ -name: "CodeQL" +name: CodeQL on: push: - branches: [ latest, beta* ] + branches: [latest, beta*] pull_request: - branches: [ latest, beta* ] + branches: [latest, beta*] schedule: - cron: '17 9 * * 2' diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index c35bc3ef5..e20474eb8 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -9,4 +9,4 @@ jobs: stale: uses: homebridge/.github/.github/workflows/labeler.yml@latest secrets: - token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 698c2b986..1046cb435 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,18 +19,18 @@ jobs: if: ${{ github.repository == 'homebridge/homebridge' }} - uses: homebridge/.github/.github/workflows/npm-publish.yml@latest + uses: homebridge/.github/.github/workflows/npm-publish-esm.yml@latest secrets: npm_auth_token: ${{ secrets.npm_token }} github-releases-to-discord: name: Discord Webhooks - needs: [build_and_test,publish] + needs: [build_and_test, publish] uses: homebridge/.github/.github/workflows/discord-webhooks.yml@latest with: - title: "Homebridge Release" + title: Homebridge Release description: | Version `v${{ needs.publish.outputs.NPM_VERSION }}` - url: "https://github.com/homebridge/homebridge/releases/tag/v${{ needs.publish.outputs.NPM_VERSION }}" + url: 'https://github.com/homebridge/homebridge/releases/tag/v${{ needs.publish.outputs.NPM_VERSION }}' secrets: DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK_URL_LATEST }} diff --git a/.github/workflows/wiki-change-notification.yml b/.github/workflows/wiki-change-notification.yml index 1089f163b..aaf9b8d70 100644 --- a/.github/workflows/wiki-change-notification.yml +++ b/.github/workflows/wiki-change-notification.yml @@ -7,7 +7,7 @@ jobs: notify: runs-on: ubuntu-latest steps: - - uses: 'oznu/gh-wiki-edit-discord-notification@main' + - uses: oznu/gh-wiki-edit-discord-notification@main with: discord-webhook-url: ${{ secrets.DISCORD_WEBHOOK_WIKI_EDIT }} ignore-collaborators: true diff --git a/.gitignore b/.gitignore index 0dcf9fad0..7d85ca2bb 100644 --- a/.gitignore +++ b/.gitignore @@ -13,7 +13,7 @@ coverage/ # Ignore any extra plugins in the example directory that aren't in Git already # (this is a sandbox for the user) example-plugins -lib +dist .idea diff --git a/.vscode/settings.json b/.vscode/settings.json index db348fbda..3aa491f03 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,3 @@ { - "codeQL.githubDatabase.download": "never" -} \ No newline at end of file + "codeQL.githubDatabase.download": "never" +} diff --git a/CHANGELOG.md b/CHANGELOG.md index b83ef873b..d201fb190 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,32 @@ All notable changes to `homebridge` will be documented in this file. This project tries to adhere to [Semantic Versioning](http://semver.org/). +## v2.0.0 (Unreleased) + +### ⚠️ Breaking Changes + +- **For Users:** + - Before upgrading, you will want to ensure that the plugin(s) you are using are compatible with this new version of Homebridge. If you are unsure, see the link below or open an issue with the developer of your plugin(s) in question. + +- **For Plugin Developers:** + - The new version of Homebridge includes a major version update to HAP-Nodejs. Some old deprecated functions have been removed. See the link below for a list of changes that you may need to make to your plugin(s). + +- Please visit the following link to learn more about the changes and how to prepare: + - [Updating-To-Homebridge-v2.0](https://github.com/homebridge/homebridge/wiki/Updating-To-Homebridge-v2.0) + +### Changed + +- Address legacy deprecation cleanup (#3648) (@hjdhjd) +- general code modernisation: + - move from `commonjs` to `esm` modules + - use lint rules from `@antfu/eslint-config` + - migrate from `jest` to `vitest` for testing + - ⚠️ drop support for node `v18` + +### Homebridge Dependencies + +- `hap-nodejs` @ `v2.0.0-beta` + ## v1.10.0 (2025-06-07) ### Changed diff --git a/README.md b/README.md index 3509fd089..6f490bf72 100644 --- a/README.md +++ b/README.md @@ -16,19 +16,19 @@ Unlocking Door -**Homebridge** is a lightweight Node.js server you can run on your home network that emulates the iOS HomeKit API. It supports Plugins, which are community-contributed modules that provide a basic bridge from HomeKit to various 3rd-party APIs provided by manufacturers of "smart home" devices. +**Homebridge** is a lightweight Node.js server you can run on your home network to emulate the HomeKit Accessory Protocol (HAP). It supports plugins, which are community-contributed modules that provide a basic bridge from HomeKit to various 3rd-party APIs provided by manufacturers of "smart home" devices. Since Siri supports devices added through HomeKit, this means that with Homebridge you can ask Siri to control devices that don't have any support for HomeKit at all. For instance, using just some of the available plugins, you can say: - * _Siri, unlock the back door._ [pictured to the right] - * _Siri, open the garage door._ - * _Siri, turn on the coffee maker._ - * _Siri, turn on the living room lights._ - * _Siri, good morning!_ +- _Siri, unlock the back door._ [pictured to the right] +- _Siri, open the garage door._ +- _Siri, turn on the coffee maker._ +- _Siri, turn on the living room lights._ +- _Siri, good morning!_ You can explore all available plugins at the NPM website by [searching for the keyword `homebridge-plugin`](https://www.npmjs.com/search?q=homebridge-plugin). -## Community +## Community The official Homebridge Discord server and Reddit community are where users can discuss Homebridge and ask for help. @@ -79,7 +79,7 @@ HomeKit communities can also be found on both [Discord](https://discord.gg/RcV7f ### Docker -[Install Homebridge on Docker](https://github.com/homebridge/homebridge/wiki/Install-Homebridge-on-Docker)
[Synology](https://github.com/homebridge/docker-homebridge/wiki/Homebridge-on-Synology) | [Unraid](https://github.com/homebridge/docker-homebridge/wiki/Homebridge-on-Unraid) | [QNAP](https://github.com/homebridge/docker-homebridge/wiki/Homebridge-on-QNAP) | [TrueNAS Scale](https://github.com/homebridge/docker-homebridge/wiki/Homebridge-on-TrueNAS-Scale) +[Install Homebridge on Docker](https://github.com/homebridge/homebridge/wiki/Install-Homebridge-on-Docker)
[Synology](https://github.com/homebridge/docker-homebridge/wiki/Homebridge-on-Synology) | [Unraid](https://github.com/homebridge/docker-homebridge/wiki/Homebridge-on-Unraid) | [QNAP](https://github.com/homebridge/docker-homebridge/wiki/Homebridge-on-QNAP) | [TrueNAS Scale](https://github.com/homebridge/docker-homebridge/wiki/Homebridge-on-TrueNAS-Scale) --- @@ -97,9 +97,9 @@ HomeKit communities can also be found on both [Discord](https://discord.gg/RcV7f 1. Open the Home app on your device. 2. Tap the Home tab, then tap . -3. Tap *Add Accessory*, then scan the QR code shown in the Homebridge UI or your Homebridge logs. +3. Tap _Add Accessory_, then scan the QR code shown in the Homebridge UI or your Homebridge logs. -If the bridge does not have any accessories yet, you may receive a message saying *Additional Set-up Required*, this is ok, as you add plugins they will show up in the Home app without the need to pair again (except for Cameras and TVs). +If the bridge does not have any accessories yet, you may receive a message saying _Additional Set-up Required_, this is ok, as you add plugins they will show up in the Home app without the need to pair again (except for Cameras and TVs). Cameras and most TV devices are exposed as separate accessories and each needs to be paired separately. See [this wiki article](https://github.com/homebridge/homebridge/wiki/Connecting-Homebridge-To-HomeKit#how-to-add-homebridge-cameras--tvs) for instructions. @@ -113,18 +113,17 @@ One final thing to remember is that Siri will almost always prefer its default p The https://developers.homebridge.io website contains the Homebridge API reference, available service and characteristic types, and plugin examples. -The [Homebridge Plugin Template](https://github.com/homebridge/homebridge-plugin-template) project provides a base you can use to create your own *platform* plugin. +The [Homebridge Plugin Template](https://github.com/homebridge/homebridge-plugin-template) project provides a base you can use to create your own _platform_ plugin. There are many existing plugins you can study; you might start with the [Homebridge Example Plugins](https://github.com/homebridge/homebridge-examples) or a plugin that already implements the device type you need. When writing your plugin, you'll want Homebridge to load it from your development directory instead of publishing it to `npm` each time. Run this command inside your plugin project folder so your global installation of Homebridge can discover it: - ```shell npm link ``` -*You can undo this using the `npm unlink` command.* +_You can undo this using the `npm unlink` command._ Then start Homebridge in debug mode: @@ -150,13 +149,13 @@ To fix this, [Reset Homebridge](https://github.com/homebridge/homebridge/wiki/Co Try the following: - 1. Swap between the `Bonjour HAP` and `Ciao` mDNS Advertiser options. See [the wiki](https://github.com/homebridge/homebridge/wiki/mDNS-Options) for more details. - 2. iOS DNS cache has gone stale or gotten misconfigured. To fix this, turn airplane mode on and back off to flush the DNS cache. +1. Swap between the `Bonjour HAP` and `Ciao` mDNS Advertiser options. See [the wiki](https://github.com/homebridge/homebridge/wiki/mDNS-Options) for more details. +2. iOS DNS cache has gone stale or gotten misconfigured. To fix this, turn airplane mode on and back off to flush the DNS cache. ### Limitations - * One bridge can only expose 150 accessories due to a HomeKit limit. You can however run your plugins as a [Child Bridge](https://github.com/homebridge/homebridge/wiki/Child-Bridges) or run [Multiple Homebridge Instances](https://github.com/homebridge/homebridge-config-ui-x/wiki/Homebridge-Service-Command#multiple-instances) to get around this limitation. - * Once an accessory has been added to the Home app, changing its name via Homebridge won't be automatically reflected in iOS. You must change it via the Home app as well. +- One bridge can only expose 150 accessories due to a HomeKit limit. You can however run your plugins as a [Child Bridge](https://github.com/homebridge/homebridge/wiki/Child-Bridges) or run [Multiple Homebridge Instances](https://github.com/homebridge/homebridge-config-ui-x/wiki/Homebridge-Service-Command#multiple-instances) to get around this limitation. +- Once an accessory has been added to the Home app, changing its name via Homebridge won't be automatically reflected in iOS. You must change it via the Home app as well. ## Why Homebridge? diff --git a/bin/homebridge b/bin/homebridge deleted file mode 100755 index 56dbbaecc..000000000 --- a/bin/homebridge +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env node - -// -// This executable sets up the environment and runs the HomeBridge CLI. -// - -"use strict"; - -process.title = "homebridge"; - -// Find the HomeBridge lib -const path = require("path"); -const fs = require("fs"); -const lib = path.join(path.dirname(fs.realpathSync(__filename)), "../lib"); - -// Run HomeBridge -require(lib + '/cli')(); diff --git a/bin/homebridge.js b/bin/homebridge.js new file mode 100755 index 000000000..f71106dac --- /dev/null +++ b/bin/homebridge.js @@ -0,0 +1,22 @@ +#!/usr/bin/env node + +// +// This executable sets up the environment and runs the Homebridge CLI. +// + +import { realpathSync } from 'node:fs' +import { dirname, join } from 'node:path' +import process from 'node:process' +import { fileURLToPath, pathToFileURL } from 'node:url' + +process.title = 'homebridge' + +// Find the Homebridge lib +const __filename = fileURLToPath(import.meta.url) +const lib = join(dirname(realpathSync(__filename)), '../dist') + +// Convert the path to a file URL +const libUrl = pathToFileURL(join(lib, 'cli.js')).href + +// Run Homebridge +import(libUrl).then(({ default: run }) => run()) diff --git a/config-sample.json b/config-sample.json index a2ac12638..390ae32e3 100644 --- a/config-sample.json +++ b/config-sample.json @@ -7,7 +7,7 @@ "port": 51826, "pin": "031-45-154" }, - + "description": "This is an example configuration file with one fake accessory and one fake platform. You can use this as a template for creating your own configuration file containing devices you actually own.", "ports": { "start": 52100, @@ -23,8 +23,8 @@ "platforms": [ { - "platform" : "PhilipsHue", - "name" : "Hue" + "platform": "PhilipsHue", + "name": "Hue" } ] } diff --git a/docs/index.html b/docs/index.html index 75fb17843..842ea0d21 100644 --- a/docs/index.html +++ b/docs/index.html @@ -9,7 +9,7 @@

Homebridge

Unlocking Door -

Homebridge is a lightweight Node.js server you can run on your home network that emulates the iOS HomeKit API. It supports Plugins, which are community-contributed modules that provide a basic bridge from HomeKit to various 3rd-party APIs provided by manufacturers of "smart home" devices.

+

Homebridge is a lightweight Node.js server you can run on your home network to emulate the HomeKit Accessory Protocol (HAP). It supports plugins, which are community-contributed modules that provide a basic bridge from HomeKit to various 3rd-party APIs provided by manufacturers of "smart home" devices.

Since Siri supports devices added through HomeKit, this means that with Homebridge you can ask Siri to control devices that don't have any support for HomeKit at all. For instance, using just some of the available plugins, you can say:

  • Siri, unlock the back door. [pictured to the right]
  • diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 000000000..f88a29e9c --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,54 @@ +import antfu from '@antfu/eslint-config' + +export default antfu({ + ignores: ['dist', 'docs'], + rules: { + 'curly': ['error'], + 'format/prettier': 'off', + 'import/extensions': 'off', + 'import/order': 'off', + 'jsdoc/check-alignment': 'error', + 'jsdoc/check-line-alignment': 'error', + 'new-cap': 'off', + 'no-undef': 'error', + 'perfectionist/sort-exports': 'error', + 'perfectionist/sort-imports': [ + 'error', + { + groups: [ + 'type', + 'internal-type', + ['parent-type', 'sibling-type', 'index-type'], + 'builtin', + 'external', + 'internal', + ['parent', 'sibling', 'index'], + 'side-effect', + 'object', + 'unknown', + ], + internalPattern: ['^@/.*'], + order: 'asc', + type: 'natural', + newlinesBetween: 'always', + }, + ], + 'perfectionist/sort-named-exports': 'error', + 'perfectionist/sort-named-imports': 'error', + 'quotes': ['error', 'single'], + 'sort-imports': 'off', + 'style/brace-style': ['error', '1tbs'], + 'style/quote-props': ['error', 'consistent-as-needed'], + 'test/no-only-tests': 'error', + 'ts/consistent-type-imports': 'off', + 'unicorn/no-useless-spread': 'error', + 'unused-imports/no-unused-vars': ['error', { caughtErrors: 'none' }], + }, + typescript: true, + formatters: { + css: true, + html: true, + markdown: true, + svg: true, + }, +}) diff --git a/jest.config.js b/jest.config.js deleted file mode 100644 index c631b9dbc..000000000 --- a/jest.config.js +++ /dev/null @@ -1,9 +0,0 @@ -/* eslint-disable */ -module.exports = { - preset: "ts-jest", - testEnvironment: "node", - coverageReporters: ["lcov"], - collectCoverageFrom: [ - "src/**" - ], -}; diff --git a/nodemon.json b/nodemon.json index 172392abc..8ba3144a5 100644 --- a/nodemon.json +++ b/nodemon.json @@ -6,6 +6,6 @@ "ignore": [ "src/**/*.spec.ts" ], - "exec": "tsc && bin/homebridge -I -C", + "exec": "tsc && bin/homebridge.js -I -C", "signal": "SIGTERM" -} \ No newline at end of file +} diff --git a/package-lock.json b/package-lock.json index 7210cdb4f..273a50f1f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,40 +9,36 @@ "version": "1.10.0", "license": "Apache-2.0", "dependencies": { - "chalk": "4.1.2", - "commander": "13.1.0", + "chalk": "5.4.1", + "commander": "14.0.0", "fs-extra": "11.3.0", - "hap-nodejs": "0.13.1", + "hap-nodejs": "2.0.0-beta.0", "qrcode-terminal": "0.12.0", "semver": "7.7.2", "source-map-support": "0.5.21" }, "bin": { - "homebridge": "bin/homebridge" + "homebridge": "bin/homebridge.js" }, "devDependencies": { + "@antfu/eslint-config": "^4.14.1", + "@prettier/plugin-xml": "^3.4.1", "@types/debug": "^4.1.12", "@types/fs-extra": "^11.0.4", - "@types/jest": "^29.5.14", "@types/node": "^22.15.30", "@types/semver": "^7.7.0", "@types/source-map-support": "^0.5.10", - "@typescript-eslint/eslint-plugin": "^8.33.1", - "@typescript-eslint/parser": "^8.33.1", - "eslint": "^8.57.1", - "eslint-plugin-import": "^2.31.0", - "eslint-plugin-import-newlines": "^1.4.0", - "eslint-plugin-jest": "^28.13.0", - "jest": "^29.7.0", + "@vitest/coverage-v8": "^3.2.2", + "eslint-plugin-format": "^1.0.1", "nodemon": "^3.1.10", "rimraf": "^6.0.1", - "ts-jest": "^29.3.4", "ts-node": "^10.9.2", "typedoc": "^0.28.5", - "typescript": "^5.8.3" + "typescript": "^5.8.3", + "vitest": "^3.2.2" }, "engines": { - "node": "^18.15.0 || ^20.7.0 || ^22" + "node": "^20.7.0 || ^22" } }, "node_modules/@ampproject/remapping": { @@ -59,156 +55,129 @@ "node": ">=6.0.0" } }, - "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.27.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.5.tgz", - "integrity": "sha512-KiRAp/VoJaWkkte84TvUd9qjdbZAdiqyvMxrGl1N6vzFogKmaLgoM3L1kgtLicp2HP5fBJS8JrZKLVIZGVJAVg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.27.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.4.tgz", - "integrity": "sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g==", + "node_modules/@antfu/eslint-config": { + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/@antfu/eslint-config/-/eslint-config-4.14.1.tgz", + "integrity": "sha512-SVGR33/jSUwMWvC8q3NGF/XEHWFJVfMg8yaQJDtRSGISXm23DVA/ANTADpRKhXpk7IjfnjzPpbT/+T6wFzOmUA==", "dev": true, "license": "MIT", "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.27.3", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.27.3", - "@babel/helpers": "^7.27.4", - "@babel/parser": "^7.27.4", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.27.4", - "@babel/types": "^7.27.3", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" + "@antfu/install-pkg": "^1.1.0", + "@clack/prompts": "^0.11.0", + "@eslint-community/eslint-plugin-eslint-comments": "^4.5.0", + "@eslint/markdown": "^6.5.0", + "@stylistic/eslint-plugin": "^5.0.0-beta.1", + "@typescript-eslint/eslint-plugin": "^8.33.1", + "@typescript-eslint/parser": "^8.33.1", + "@vitest/eslint-plugin": "^1.2.1", + "ansis": "^4.1.0", + "cac": "^6.7.14", + "eslint-config-flat-gitignore": "^2.1.0", + "eslint-flat-config-utils": "^2.1.0", + "eslint-merge-processors": "^2.0.0", + "eslint-plugin-antfu": "^3.1.1", + "eslint-plugin-command": "^3.2.1", + "eslint-plugin-jsdoc": "^50.7.1", + "eslint-plugin-jsonc": "^2.20.1", + "eslint-plugin-n": "^17.19.0", + "eslint-plugin-no-only-tests": "^3.3.0", + "eslint-plugin-perfectionist": "^4.14.0", + "eslint-plugin-pnpm": "^0.3.1", + "eslint-plugin-regexp": "^2.8.0", + "eslint-plugin-toml": "^0.12.0", + "eslint-plugin-unicorn": "^59.0.1", + "eslint-plugin-unused-imports": "^4.1.4", + "eslint-plugin-vue": "^10.2.0", + "eslint-plugin-yml": "^1.18.0", + "eslint-processor-vue-blocks": "^2.0.0", + "globals": "^16.2.0", + "jsonc-eslint-parser": "^2.4.0", + "local-pkg": "^1.1.1", + "parse-gitignore": "^2.0.0", + "toml-eslint-parser": "^0.10.0", + "vue-eslint-parser": "^10.1.3", + "yaml-eslint-parser": "^1.3.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/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/@babel/generator": { - "version": "7.27.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.5.tgz", - "integrity": "sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.27.5", - "@babel/types": "^7.27.3", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^3.0.2" + "eslint-config": "bin/index.js" }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", - "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.27.2", - "@babel/helper-validator-option": "^7.27.1", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" + "funding": { + "url": "https://github.com/sponsors/antfu" }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets/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/@babel/helper-module-imports": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "peerDependencies": { + "@eslint-react/eslint-plugin": "^1.38.4", + "@prettier/plugin-xml": "^3.4.1", + "@unocss/eslint-plugin": ">=0.50.0", + "astro-eslint-parser": "^1.0.2", + "eslint": "^9.10.0", + "eslint-plugin-astro": "^1.2.0", + "eslint-plugin-format": ">=0.1.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.19", + "eslint-plugin-solid": "^0.14.3", + "eslint-plugin-svelte": ">=2.35.1", + "eslint-plugin-vuejs-accessibility": "^2.4.1", + "prettier-plugin-astro": "^0.14.0", + "prettier-plugin-slidev": "^1.0.5", + "svelte-eslint-parser": ">=0.37.0" }, - "engines": { - "node": ">=6.9.0" + "peerDependenciesMeta": { + "@eslint-react/eslint-plugin": { + "optional": true + }, + "@prettier/plugin-xml": { + "optional": true + }, + "@unocss/eslint-plugin": { + "optional": true + }, + "astro-eslint-parser": { + "optional": true + }, + "eslint-plugin-astro": { + "optional": true + }, + "eslint-plugin-format": { + "optional": true + }, + "eslint-plugin-react-hooks": { + "optional": true + }, + "eslint-plugin-react-refresh": { + "optional": true + }, + "eslint-plugin-solid": { + "optional": true + }, + "eslint-plugin-svelte": { + "optional": true + }, + "eslint-plugin-vuejs-accessibility": { + "optional": true + }, + "prettier-plugin-astro": { + "optional": true + }, + "prettier-plugin-slidev": { + "optional": true + }, + "svelte-eslint-parser": { + "optional": true + } } }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz", - "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==", + "node_modules/@antfu/install-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-1.1.0.tgz", + "integrity": "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.27.3" - }, - "engines": { - "node": ">=6.9.0" + "package-manager-detector": "^1.3.0", + "tinyexec": "^1.0.1" }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", - "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" + "funding": { + "url": "https://github.com/sponsors/antfu" } }, "node_modules/@babel/helper-string-parser": { @@ -231,30 +200,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.27.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.6.tgz", - "integrity": "sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.27.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/parser": { "version": "7.27.5", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.5.tgz", @@ -271,1068 +216,955 @@ "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==", + "node_modules/@babel/types": { + "version": "7.27.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.6.tgz", + "integrity": "sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=6.9.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==", + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=18" } }, - "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==", + "node_modules/@clack/core": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@clack/core/-/core-0.5.0.tgz", + "integrity": "sha512-p3y0FIOwaYRUPRcMO7+dlmLh8PSRcrjuTndsiA0WAFbWES0mLZlrjVoBRZ9DzkPFJZG6KGkJmoEAY0ZcVWTkow==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "picocolors": "^1.0.0", + "sisteransi": "^1.0.5" } }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "node_modules/@clack/prompts": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-0.11.0.tgz", + "integrity": "sha512-pMN5FcrEw9hUkZA4f+zLlzivQSeQf5dRGJjSUbvVYDLvpKCdQx5OaknvKzgbtXOizhP+SJJJjqEbOe55uKKfAw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@clack/core": "0.5.0", + "picocolors": "^1.0.0", + "sisteransi": "^1.0.5" } }, - "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", - "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "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==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@jridgewell/trace-mapping": "0.3.9" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=12" } }, - "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==", + "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==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "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==", + "node_modules/@dprint/formatter": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@dprint/formatter/-/formatter-0.3.0.tgz", + "integrity": "sha512-N9fxCxbaBOrDkteSOzaCqwWjso5iAe+WJPsHC021JfHNj2ThInPNEF13ORDKta3llq5D1TlclODCvOvipH7bWQ==", "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } + "license": "MIT" }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", - "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "node_modules/@dprint/markdown": { + "version": "0.17.8", + "resolved": "https://registry.npmjs.org/@dprint/markdown/-/markdown-0.17.8.tgz", + "integrity": "sha512-ukHFOg+RpG284aPdIg7iPrCYmMs3Dqy43S1ejybnwlJoFiW02b+6Bbr5cfZKFRYNP3dKGM86BqHEnMzBOyLvvA==", "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } + "license": "MIT" + }, + "node_modules/@dprint/toml": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@dprint/toml/-/toml-0.6.4.tgz", + "integrity": "sha512-bZXIUjxr0LIuHWshZr/5mtUkOrnh0NKVZEF6ACojW5z7zkJu7s9sV2mMXm8XQDqN4cJzdHYUYzUyEGdfciaLJA==", + "dev": true, + "license": "MIT" }, - "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==", + "node_modules/@es-joy/jsdoccomment": { + "version": "0.50.2", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.50.2.tgz", + "integrity": "sha512-YAdE/IJSpwbOTiaURNCKECdAwqrJuFiZhylmesBcIRawtYKnBR2wxPhoIewMg+Yu+QuYvHfJNReWpoxGBKOChA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@types/estree": "^1.0.6", + "@typescript-eslint/types": "^8.11.0", + "comment-parser": "1.4.1", + "esquery": "^1.6.0", + "jsdoc-type-pratt-parser": "~4.1.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=18" } }, - "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==", + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz", + "integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==", + "cpu": [ + "ppc64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" } }, - "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==", + "node_modules/@esbuild/android-arm": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz", + "integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" } }, - "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==", + "node_modules/@esbuild/android-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz", + "integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" } }, - "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==", + "node_modules/@esbuild/android-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz", + "integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" } }, - "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==", + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz", + "integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz", + "integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "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==", + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz", + "integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", - "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz", + "integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=18" } }, - "node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "node_modules/@esbuild/linux-arm": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz", + "integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "node_modules/@babel/traverse": { - "version": "7.27.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.4.tgz", - "integrity": "sha512-oNcu2QbHqts9BtOWJosOVJapWjBDSxGCpFvikNR5TGDYDQf3JwpIoMzIKrvfoti93cLfPJEG4tH9SPVeyCGgdA==", + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz", + "integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.27.3", - "@babel/parser": "^7.27.4", - "@babel/template": "^7.27.2", - "@babel/types": "^7.27.3", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "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==", + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz", + "integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=4" + "node": ">=18" } }, - "node_modules/@babel/types": { - "version": "7.27.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.6.tgz", - "integrity": "sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==", + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz", + "integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==", + "cpu": [ + "loong64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" + "node": ">=18" } }, - "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==", - "dev": true, - "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==", + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz", + "integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==", + "cpu": [ + "mips64el" + ], "dev": true, "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=12" + "node": ">=18" } }, - "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==", + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz", + "integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==", + "cpu": [ + "ppc64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", - "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz", + "integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==", + "cpu": [ + "riscv64" + ], "dev": true, "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + "node": ">=18" } }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz", + "integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==", + "cpu": [ + "s390x" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + "node": ">=18" } }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "node_modules/@esbuild/linux-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz", + "integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==", + "cpu": [ + "x64" + ], "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" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=18" } }, - "node_modules/@eslint/eslintrc/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==", + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz", + "integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@eslint/eslintrc/node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz", + "integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": ">= 4" + "node": ">=18" } }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz", + "integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": "*" + "node": ">=18" } }, - "node_modules/@eslint/js": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz", + "integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=18" } }, - "node_modules/@gerrit0/mini-shiki": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-3.6.0.tgz", - "integrity": "sha512-KaeJvPNofTEZR9EzVNp/GQzbQqkGfjiu6k3CXKvhVTX+8OoAKSX/k7qxLKOX3B0yh2XqVAc93rsOu48CGt2Qug==", + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz", + "integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@shikijs/engine-oniguruma": "^3.6.0", - "@shikijs/langs": "^3.6.0", - "@shikijs/themes": "^3.6.0", - "@shikijs/types": "^3.6.0", - "@shikijs/vscode-textmate": "^10.0.2" - } - }, - "node_modules/@homebridge/ciao": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@homebridge/ciao/-/ciao-1.3.1.tgz", - "integrity": "sha512-87tQCBNNnTymlbg8pKlQjRsk7a5uuqhWBpCbUriVYUebz3voJkLbbTmp0TQg7Sa6Jnpk/Uo6LA8zAOy2sbK9bw==", - "license": "MIT", - "dependencies": { - "debug": "^4.3.6", - "fast-deep-equal": "^3.1.3", - "source-map-support": "^0.5.21", - "tslib": "^2.6.3" - }, - "bin": { - "ciao-bcs": "lib/bonjour-conformance-testing.js" - }, + "optional": true, + "os": [ + "sunos" + ], "engines": { - "node": "^18 || ^20 || ^22" + "node": ">=18" } }, - "node_modules/@homebridge/dbus-native": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@homebridge/dbus-native/-/dbus-native-0.6.0.tgz", - "integrity": "sha512-xObqQeYHTXmt6wsfj10+krTo4xbzR9BgUfX2aQ+edDC9nc4ojfzLScfXCh3zluAm6UCowKw+AFfXn6WLWUOPkg==", + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz", + "integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "@homebridge/long": "^5.2.1", - "@homebridge/put": "^0.0.8", - "event-stream": "^4.0.1", - "hexy": "^0.3.5", - "minimist": "^1.2.6", - "safe-buffer": "^5.1.2", - "xml2js": "^0.6.2" - }, - "bin": { - "dbus2js": "bin/dbus2js.js" - } - }, - "node_modules/@homebridge/long": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@homebridge/long/-/long-5.2.1.tgz", - "integrity": "sha512-i5Df8R63XNPCn+Nj1OgAoRdw9e+jHUQb3CNUbvJneI2iu3j4+OtzQj+5PA1Ce+747NR1SPqZSvyvD483dOT3AA==", - "license": "Apache-2.0" - }, - "node_modules/@homebridge/put": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/@homebridge/put/-/put-0.0.8.tgz", - "integrity": "sha512-mwxLHHqKebOmOSU0tsPEWQSBHGApPhuaqtNpCe7U+AMdsduweANiu64E9SXXUtdpyTjsOpgSMLhD1+kbLHD2gA==", - "license": "MIT/X11", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=0.3.0" + "node": ">=18" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "deprecated": "Use @eslint/config-array instead", + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz", + "integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==", + "cpu": [ + "ia32" + ], "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=10.10.0" + "node": ">=18" } }, - "node_modules/@humanwhocodes/config-array/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==", + "node_modules/@esbuild/win32-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz", + "integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/@eslint-community/eslint-plugin-eslint-comments": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-4.5.0.tgz", + "integrity": "sha512-MAhuTKlr4y/CE3WYX26raZjy+I/kS2PLKSzvfmDCGrBLTFHOYwqROZdr4XwPgXwX3K9rjzMr4pSmUWGnzsUyMg==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "brace-expansion": "^1.1.7" + "escape-string-regexp": "^4.0.0", + "ignore": "^5.2.4" }, "engines": { - "node": "*" - } - }, - "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" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + "url": "https://opencollective.com/eslint" }, - "engines": { - "node": ">=12" + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "node_modules/@eslint-community/eslint-utils": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", "dev": true, "license": "MIT", - "engines": { - "node": ">=12" + "dependencies": { + "eslint-visitor-keys": "^3.4.3" }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "license": "MIT", "engines": { - "node": ">=12" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, + "license": "Apache-2.0", "engines": { - "node": ">=12" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/eslint" } }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "node_modules/@eslint/compat": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.2.9.tgz", + "integrity": "sha512-gCdSY54n7k+driCadyMNv8JSPzYLeDVM/ikZRtvtROBpRdFSkS8W9A82MqsaY7lZuwL0wiapgD0NT1xT0hyJsA==", "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, + "license": "Apache-2.0", "engines": { - "node": ">=12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "peerDependencies": { + "eslint": "^9.10.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } } }, - "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==", + "node_modules/@eslint/config-array": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz", + "integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==", "dev": true, - "license": "ISC", + "license": "Apache-2.0", + "peer": true, "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" + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "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==", + "node_modules/@eslint/config-array/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==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "sprintf-js": "~1.0.2" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/@istanbuljs/load-nyc-config/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==", + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "MIT", + "license": "ISC", + "peer": true, "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=8" + "node": "*" } }, - "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==", + "node_modules/@eslint/config-helpers": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.2.tgz", + "integrity": "sha512-+GPzk8PlG0sPpzdU5ZvIRMPidzAnZDl/s9L+y13iodqvb8leL53bTannOrQ/Im7UkpsmFU5Ily5U60LWixnmLg==", "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@istanbuljs/load-nyc-config/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==", + "node_modules/@eslint/core": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.14.0.tgz", + "integrity": "sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "p-locate": "^4.1.0" + "@types/json-schema": "^7.0.15" }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@istanbuljs/load-nyc-config/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==", + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "p-try": "^2.0.0" + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.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": ">=6" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/eslint" } }, - "node_modules/@istanbuljs/load-nyc-config/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==", + "node_modules/@eslint/eslintrc/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==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "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==", + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@jest/console": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", - "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "MIT", + "license": "ISC", + "peer": true, "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "slash": "^3.0.0" + "brace-expansion": "^1.1.7" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "*" } }, - "node_modules/@jest/core": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", - "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "node_modules/@eslint/js": { + "version": "9.28.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.28.0.tgz", + "integrity": "sha512-fnqSjGWd/CoIp4EXIxWVK/sHA6DOHN4+8Ix2cX5ycOY7LG0UY8nHCU5pIp2eaE1Mc7Qd8kHspYNzYXT2ojPLzg==", "dev": true, "license": "MIT", - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/reporters": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.7.0", - "jest-config": "^29.7.0", - "jest-haste-map": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-resolve-dependencies": "^29.7.0", - "jest-runner": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "jest-watcher": "^29.7.0", - "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, + "peer": true, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" } }, - "node_modules/@jest/environment": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", - "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "node_modules/@eslint/markdown": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@eslint/markdown/-/markdown-6.5.0.tgz", + "integrity": "sha512-oSkF0p8X21vKEEAGTZASi7q3tbdTvlGduQ02Xz2A1AFncUP4RLVcNz27XurxVW4fs1JXuh0xBtvokXdtp/nN+Q==", "dev": true, "license": "MIT", "dependencies": { - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-mock": "^29.7.0" + "@eslint/core": "^0.14.0", + "@eslint/plugin-kit": "^0.3.1", + "mdast-util-from-markdown": "^2.0.2", + "mdast-util-frontmatter": "^2.0.1", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-frontmatter": "^2.0.0", + "micromark-extension-gfm": "^3.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@jest/expect": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", - "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", "dev": true, - "license": "MIT", - "dependencies": { - "expect": "^29.7.0", - "jest-snapshot": "^29.7.0" - }, + "license": "Apache-2.0", + "peer": true, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@jest/expect-utils": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", - "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "node_modules/@eslint/plugin-kit": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.1.tgz", + "integrity": "sha512-0J+zgWxHN+xXONWIyPWKFMgVuJoZuGiIFu8yxk7RJjxkzpGmyja5wRFqZIVtjDVOQpV+Rw0iOAjYPE2eQyjr0w==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "jest-get-type": "^29.6.3" + "@eslint/core": "^0.14.0", + "levn": "^0.4.1" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@jest/fake-timers": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", - "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "node_modules/@gerrit0/mini-shiki": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-3.6.0.tgz", + "integrity": "sha512-KaeJvPNofTEZR9EzVNp/GQzbQqkGfjiu6k3CXKvhVTX+8OoAKSX/k7qxLKOX3B0yh2XqVAc93rsOu48CGt2Qug==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "^29.6.3", - "@sinonjs/fake-timers": "^10.0.2", - "@types/node": "*", - "jest-message-util": "^29.7.0", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "@shikijs/engine-oniguruma": "^3.6.0", + "@shikijs/langs": "^3.6.0", + "@shikijs/themes": "^3.6.0", + "@shikijs/types": "^3.6.0", + "@shikijs/vscode-textmate": "^10.0.2" } }, - "node_modules/@jest/globals": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", - "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", - "dev": true, + "node_modules/@homebridge/ciao": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@homebridge/ciao/-/ciao-1.3.2.tgz", + "integrity": "sha512-RBQaEM5/9UPznhWL/QgJYgbVU84v3eOSdMbr827PQtvnpQBp5iJW7vBSH4YzWh/GKB0yS0mPf0wgOiCcLiOI1A==", "license": "MIT", "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/expect": "^29.7.0", - "@jest/types": "^29.6.3", - "jest-mock": "^29.7.0" + "debug": "^4.4.1", + "fast-deep-equal": "^3.1.3", + "source-map-support": "^0.5.21", + "tslib": "^2.8.1" + }, + "bin": { + "ciao-bcs": "lib/bonjour-conformance-testing.js" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^18 || ^20 || ^22" } }, - "node_modules/@jest/reporters": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", - "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", - "dev": true, + "node_modules/@homebridge/dbus-native": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@homebridge/dbus-native/-/dbus-native-0.7.1.tgz", + "integrity": "sha512-ZywUbf0vy+DSN4gCCMERRpSh/nywPjRk/fMq5GGM58Cqm8/dg6/C5aFJPmgVLNUD4Etcamq2d0Jb9qiDSZktcA==", "license": "MIT", "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@jridgewell/trace-mapping": "^0.3.18", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^6.0.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "jest-worker": "^29.7.0", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "v8-to-istanbul": "^9.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + "event-stream": "^4.0.1", + "hexy": "^0.3.5", + "long": "^5.3.2", + "minimist": "^1.2.8", + "safe-buffer": "^5.1.2", + "xml2js": "^0.6.2" }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "bin": { + "dbus2js": "bin/dbus2js.js" } }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", "dev": true, - "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, + "license": "Apache-2.0", + "peer": true, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=18.18.0" } }, - "node_modules/@jest/source-map": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", - "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", + "peer": true, "dependencies": { - "@jridgewell/trace-mapping": "^0.3.18", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=18.18.0" } }, - "node_modules/@jest/test-result": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", - "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", "dev": true, - "license": "MIT", - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, + "license": "Apache-2.0", + "peer": true, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@jest/test-sequencer": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", - "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "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": "MIT", - "dependencies": { - "@jest/test-result": "^29.7.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "slash": "^3.0.0" + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": ">=12.22" }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "peer": true, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@jest/transform": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", - "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.6.3", - "@jridgewell/trace-mapping": "^0.3.18", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-util": "^29.7.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=12" } }, - "node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "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==", "dev": true, "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=8" } }, "node_modules/@jridgewell/gen-mapping": { @@ -1383,61 +1215,371 @@ "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@leichtgewicht/ip-codec": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", - "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", - "license": "MIT" - }, - "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==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "license": "MIT" + }, + "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/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pkgr/core": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.2.tgz", + "integrity": "sha512-fdDH1LSGfZdTH2sxdpVMw31BanV28K/Gry0cVFxaNP77neJSkd82mM8ErPNYs9e+0O7SdHBLTDzDgwUuy18RnQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@prettier/plugin-xml": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@prettier/plugin-xml/-/plugin-xml-3.4.1.tgz", + "integrity": "sha512-Uf/6/+9ez6z/IvZErgobZ2G9n1ybxF5BhCd7eMcKqfoWuOzzNUxBipNo3QAP8kRC1VD18TIo84no7LhqtyDcTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@xml-tools/parser": "^1.0.11" + }, + "peerDependencies": { + "prettier": "^3.0.0" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.42.0.tgz", + "integrity": "sha512-gldmAyS9hpj+H6LpRNlcjQWbuKUtb94lodB9uCz71Jm+7BxK1VIOo7y62tZZwxhA7j1ylv/yQz080L5WkS+LoQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.42.0.tgz", + "integrity": "sha512-bpRipfTgmGFdCZDFLRvIkSNO1/3RGS74aWkJJTFJBH7h3MRV4UijkaEUeOMbi9wxtxYmtAbVcnMtHTPBhLEkaw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.42.0.tgz", + "integrity": "sha512-JxHtA081izPBVCHLKnl6GEA0w3920mlJPLh89NojpU2GsBSB6ypu4erFg/Wx1qbpUbepn0jY4dVWMGZM8gplgA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.42.0.tgz", + "integrity": "sha512-rv5UZaWVIJTDMyQ3dCEK+m0SAn6G7H3PRc2AZmExvbDvtaDc+qXkei0knQWcI3+c9tEs7iL/4I4pTQoPbNL2SA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.42.0.tgz", + "integrity": "sha512-fJcN4uSGPWdpVmvLuMtALUFwCHgb2XiQjuECkHT3lWLZhSQ3MBQ9pq+WoWeJq2PrNxr9rPM1Qx+IjyGj8/c6zQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.42.0.tgz", + "integrity": "sha512-CziHfyzpp8hJpCVE/ZdTizw58gr+m7Y2Xq5VOuCSrZR++th2xWAz4Nqk52MoIIrV3JHtVBhbBsJcAxs6NammOQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.42.0.tgz", + "integrity": "sha512-UsQD5fyLWm2Fe5CDM7VPYAo+UC7+2Px4Y+N3AcPh/LdZu23YcuGPegQly++XEVaC8XUTFVPscl5y5Cl1twEI4A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.42.0.tgz", + "integrity": "sha512-/i8NIrlgc/+4n1lnoWl1zgH7Uo0XK5xK3EDqVTf38KvyYgCU/Rm04+o1VvvzJZnVS5/cWSd07owkzcVasgfIkQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.42.0.tgz", + "integrity": "sha512-eoujJFOvoIBjZEi9hJnXAbWg+Vo1Ov8n/0IKZZcPZ7JhBzxh2A+2NFyeMZIRkY9iwBvSjloKgcvnjTbGKHE44Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.42.0.tgz", + "integrity": "sha512-/3NrcOWFSR7RQUQIuZQChLND36aTU9IYE4j+TB40VU78S+RA0IiqHR30oSh6P1S9f9/wVOenHQnacs/Byb824g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.42.0.tgz", + "integrity": "sha512-O8AplvIeavK5ABmZlKBq9/STdZlnQo7Sle0LLhVA7QT+CiGpNVe197/t8Aph9bhJqbDVGCHpY2i7QyfEDDStDg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.42.0.tgz", + "integrity": "sha512-6Qb66tbKVN7VyQrekhEzbHRxXXFFD8QKiFAwX5v9Xt6FiJ3BnCVBuyBxa2fkFGqxOCSGGYNejxd8ht+q5SnmtA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.42.0.tgz", + "integrity": "sha512-KQETDSEBamQFvg/d8jajtRwLNBlGc3aKpaGiP/LvEbnmVUKlFta1vqJqTrvPtsYsfbE/DLg5CC9zyXRX3fnBiA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.42.0.tgz", + "integrity": "sha512-qMvnyjcU37sCo/tuC+JqeDKSuukGAd+pVlRl/oyDbkvPJ3awk6G6ua7tyum02O3lI+fio+eM5wsVd66X0jQtxw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.42.0.tgz", + "integrity": "sha512-I2Y1ZUgTgU2RLddUHXTIgyrdOwljjkmcZ/VilvaEumtS3Fkuhbw4p4hgHc39Ypwvo2o7sBFNl2MquNvGCa55Iw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.42.0.tgz", + "integrity": "sha512-Gfm6cV6mj3hCUY8TqWa63DB8Mx3NADoFwiJrMpoZ1uESbK8FQV3LXkhfry+8bOniq9pqY1OdsjFWNsSbfjPugw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.42.0.tgz", + "integrity": "sha512-g86PF8YZ9GRqkdi0VoGlcDUb4rYtQKyTD1IVtxxN4Hpe7YqLBShA7oHMKU6oKTCi3uxwW4VkIGnOaH/El8de3w==", + "cpu": [ + "x64" + ], "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==", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.42.0.tgz", + "integrity": "sha512-+axkdyDGSp6hjyzQ5m1pgcvQScfHnMCcsXkx8pTgy/6qBmWVhtRVlgxjWwDp67wEXXUr0x+vD6tp5W4x6V7u1A==", + "cpu": [ + "arm64" + ], "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==", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.42.0.tgz", + "integrity": "sha512-F+5J9pelstXKwRSDq92J0TEBXn2nfUrQGg+HK1+Tk7VOL09e0gBqUHugZv7SW4MGrYj41oNCUe3IKCDGVlis2g==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@rtsao/scc": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", - "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.42.0.tgz", + "integrity": "sha512-LpHiJRwkaVz/LqjHjK8LCi8osq7elmpwujwbXKNW88bM8eeGxavJIKKjkjpMHAh/2xfnrt1ZSnhTv41WYUHYmA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, "node_modules/@shikijs/engine-oniguruma": { "version": "3.6.0", @@ -1488,31 +1630,24 @@ "dev": true, "license": "MIT" }, - "node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", - "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "node_modules/@stylistic/eslint-plugin": { + "version": "5.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-5.0.0-beta.3.tgz", + "integrity": "sha512-ItDjyhRyc5hx4W/IBy4/EhgPLbTrjeVPgcYG65pZApTg8Prf1nsWz0j7AY/nYd7OqzBAuRSmzrYFlab86ybePw==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "dependencies": { - "@sinonjs/commons": "^3.0.0" + "@typescript-eslint/utils": "^8.32.1", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "estraverse": "^5.3.0", + "picomatch": "^4.0.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": ">=9.0.0" } }, "node_modules/@tsconfig/node10": { @@ -1543,49 +1678,14 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "node_modules/@types/chai": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.2.tgz", + "integrity": "sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==", "dev": true, "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.27.0", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", - "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.7.tgz", - "integrity": "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.20.7" + "@types/deep-eql": "*" } }, "node_modules/@types/debug": { @@ -1598,6 +1698,20 @@ "@types/ms": "*" } }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/fs-extra": { "version": "11.0.4", "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.4.tgz", @@ -1609,16 +1723,6 @@ "@types/node": "*" } }, - "node_modules/@types/graceful-fs": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", - "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/hast": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", @@ -1629,48 +1733,10 @@ "@types/unist": "*" } }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", - "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", - "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", - "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/jest": { - "version": "29.5.14", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz", - "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "expect": "^29.0.0", - "pretty-format": "^29.0.0" - } - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true, "license": "MIT" }, @@ -1684,6 +1750,16 @@ "@types/node": "*" } }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, "node_modules/@types/ms": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", @@ -1718,13 +1794,6 @@ "source-map": "^0.6.0" } }, - "node_modules/@types/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/unist": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", @@ -1732,23 +1801,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/yargs": { - "version": "17.0.33", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", - "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", - "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true, - "license": "MIT" - }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.33.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.33.1.tgz", @@ -1779,6 +1831,16 @@ "typescript": ">=4.8.4 <5.9.0" } }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/@typescript-eslint/parser": { "version": "8.33.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.33.1.tgz", @@ -1944,51 +2006,288 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.33.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.33.1.tgz", + "integrity": "sha512-3i8NrFcZeeDHJ+7ZUuDkGT+UHq+XoFGsymNK2jZCOHcfEzRQ0BdpRtdpSx/Iyf3MHLWIcLS0COuOPibKQboIiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.33.1", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vitest/coverage-v8": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-3.2.2.tgz", + "integrity": "sha512-RVAi5xnqedSKvaoQyCTWvncMk8eYZcTTOsLK7XmnfOEvdGP/O/upA0/MA8Ss+Qs++mj0GcSRi/whR0S5iBPpTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.3.0", + "@bcoe/v8-coverage": "^1.0.2", + "ast-v8-to-istanbul": "^0.3.3", + "debug": "^4.4.1", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-lib-source-maps": "^5.0.6", + "istanbul-reports": "^3.1.7", + "magic-string": "^0.30.17", + "magicast": "^0.3.5", + "std-env": "^3.9.0", + "test-exclude": "^7.0.1", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "3.2.2", + "vitest": "3.2.2" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } + } + }, + "node_modules/@vitest/eslint-plugin": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@vitest/eslint-plugin/-/eslint-plugin-1.2.1.tgz", + "integrity": "sha512-JQr1jdVcrsoS7Sdzn83h9sq4DvREf9Q/onTZbJCqTVlv/76qb+TZrLv/9VhjnjSMHweQH5FdpMDeCR6aDe2fgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "^8.24.0" + }, + "peerDependencies": { + "eslint": ">= 8.57.0", + "typescript": ">= 5.0.0", + "vitest": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + }, + "vitest": { + "optional": true + } + } + }, + "node_modules/@vitest/expect": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.2.tgz", + "integrity": "sha512-ipHw0z669vEMjzz3xQE8nJX1s0rQIb7oEl4jjl35qWTwm/KIHERIg/p/zORrjAaZKXfsv7IybcNGHwhOOAPMwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/spy": "3.2.2", + "@vitest/utils": "3.2.2", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.2.tgz", + "integrity": "sha512-jKojcaRyIYpDEf+s7/dD3LJt53c0dPfp5zCPXz9H/kcGrSlovU/t1yEaNzM9oFME3dcd4ULwRI/x0Po1Zf+LTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "3.2.2", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/mocker/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/@vitest/pretty-format": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.2.tgz", + "integrity": "sha512-FY4o4U1UDhO9KMd2Wee5vumwcaHw7Vg4V7yR4Oq6uK34nhEJOmdRYrk3ClburPRUA09lXD/oXWZ8y/Sdma0aUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.2.tgz", + "integrity": "sha512-GYcHcaS3ejGRZYed2GAkvsjBeXIEerDKdX3orQrBJqLRiea4NSS9qvn9Nxmuy1IwIB+EjFOaxXnX79l8HFaBwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "3.2.2", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.33.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.33.1.tgz", - "integrity": "sha512-3i8NrFcZeeDHJ+7ZUuDkGT+UHq+XoFGsymNK2jZCOHcfEzRQ0BdpRtdpSx/Iyf3MHLWIcLS0COuOPibKQboIiQ==", + "node_modules/@vitest/snapshot": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.2.tgz", + "integrity": "sha512-aMEI2XFlR1aNECbBs5C5IZopfi5Lb8QJZGGpzS8ZUHML5La5wCbrbhLOVSME68qwpT05ROEEOAZPRXFpxZV2wA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.33.1", - "eslint-visitor-keys": "^4.2.0" + "@vitest/pretty-format": "3.2.2", + "magic-string": "^0.30.17", + "pathe": "^2.0.3" }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.2.tgz", + "integrity": "sha512-6Utxlx3o7pcTxvp0u8kUiXtRFScMrUg28KjB3R2hon7w4YqOFAEA9QwzPVVS1QNL3smo4xRNOpNZClRVfpMcYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^4.0.3" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://opencollective.com/vitest" } }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "node_modules/@vitest/utils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.2.tgz", + "integrity": "sha512-qJYMllrWpF/OYfWHP32T31QCaLa3BAzT/n/8mNGhPdVcjY+JYazQFO1nsJvXU12Kp1xMpNY4AGuljPTNjQve6A==", "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.2", + "loupe": "^3.1.3", + "tinyrainbow": "^2.0.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://opencollective.com/vitest" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "node_modules/@vue/compiler-core": { + "version": "3.5.16", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.16.tgz", + "integrity": "sha512-AOQS2eaQOaaZQoL1u+2rCJIKDruNXVBZSiUD3chnUrsoX5ZTQMaCvXlWNIfxBJuU15r1o7+mpo5223KVtIhAgQ==", "dev": true, - "license": "ISC" + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/parser": "^7.27.2", + "@vue/shared": "3.5.16", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.16", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.16.tgz", + "integrity": "sha512-SSJIhBr/teipXiXjmWOVWLnxjNGo65Oj/8wTEQz0nqwQeP75jWZ0n4sF24Zxoht1cuJoWopwj0J0exYwCJ0dCQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@vue/compiler-core": "3.5.16", + "@vue/shared": "3.5.16" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.16", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.16.tgz", + "integrity": "sha512-rQR6VSFNpiinDy/DVUE0vHoIDUF++6p910cgcZoaAUm3POxgNOOdS/xgoll3rNdKYTYPnnbARDCZOyZ+QSe6Pw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/parser": "^7.27.2", + "@vue/compiler-core": "3.5.16", + "@vue/compiler-dom": "3.5.16", + "@vue/compiler-ssr": "3.5.16", + "@vue/shared": "3.5.16", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.17", + "postcss": "^8.5.3", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.16", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.16.tgz", + "integrity": "sha512-d2V7kfxbdsjrDSGlJE7my1ZzCXViEcqN6w14DOsDrUCHEA6vbnVCpRFfrc4ryCP/lCKzX2eS1YtnLE/BuC9f/A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@vue/compiler-dom": "3.5.16", + "@vue/shared": "3.5.16" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.16", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.16.tgz", + "integrity": "sha512-c/0fWy3Jw6Z8L9FmTyYfkpM5zklnqqa9+a6dz3DvONRKW2NEbh46BP0FHuLFSWi2TnQEtp91Z6zOWNrU6QiyPg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@xml-tools/parser": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@xml-tools/parser/-/parser-1.0.11.tgz", + "integrity": "sha512-aKqQ077XnR+oQtHJlrAflaZaL7qZsulWc/i/ZEooar5JiWj1eLt0+Wg28cpa+XLney107wXqneC+oG1IZvxkTA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "chevrotain": "7.1.1" + } }, "node_modules/acorn": { "version": "8.14.1", @@ -2032,6 +2331,7 @@ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -2043,58 +2343,40 @@ "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==", + "node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, "license": "MIT", - "dependencies": { - "type-fest": "^0.21.3" - }, "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "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==", + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, - "license": "(MIT OR CC0-1.0)", + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "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==", + "node_modules/ansis": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.1.0.tgz", + "integrity": "sha512-BGcItUBWSMRgOCe+SVZJ+S7yTRG0eGt9cXAHev72yuGcY23hnLA7Bky5L/xLyPINoSN95geovfBkqoTlNZYa7w==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "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" - }, + "license": "ISC", "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=14" } }, "node_modules/anymatch": { @@ -2111,303 +2393,110 @@ "node": ">= 8" } }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": 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.2", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", - "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "is-array-buffer": "^3.0.5" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-flatten": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-3.0.0.tgz", - "integrity": "sha512-zPMVc3ZYlGLNk4mpK1NzP2wg0ml9t7fUgDsayR5Y5rSzxQilzR9FGu/EH2jQOcKSAeAfWeylyW8juy3OkWRvNA==", - "license": "MIT" - }, - "node_modules/array-includes": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", - "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.24.0", - "es-object-atoms": "^1.1.1", - "get-intrinsic": "^1.3.0", - "is-string": "^1.1.1", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.findlastindex": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", - "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.9", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "es-shim-unscopables": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", - "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", - "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-shim-unscopables": "^1.0.2" - }, "engines": { - "node": ">= 0.4" + "node": ">=8.6" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", - "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "node_modules/are-docs-informative": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", + "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", "dev": true, "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "is-array-buffer": "^3.0.4" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=14" } }, - "node_modules/async": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", - "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", "dev": true, "license": "MIT" }, - "node_modules/async-function": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", - "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "license": "MIT", - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/babel-jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", - "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "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": "MIT", - "dependencies": { - "@jest/transform": "^29.7.0", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.6.3", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" - } + "license": "Python-2.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==", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "license": "MIT", "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" + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/babel-plugin-istanbul/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==", + "node_modules/array-flatten": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-3.0.0.tgz", + "integrity": "sha512-zPMVc3ZYlGLNk4mpK1NzP2wg0ml9t7fUgDsayR5Y5rSzxQilzR9FGu/EH2jQOcKSAeAfWeylyW8juy3OkWRvNA==", + "license": "MIT" + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", "dev": true, - "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" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/babel-plugin-istanbul/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "node_modules/ast-v8-to-istanbul": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.3.tgz", + "integrity": "sha512-MuXMrSLVVoA6sYN/6Hke18vMzrT4TZNbZIj/hvh0fnYFpO+/kFXcLIaiPwXXWaQUPg4yJD8fj+lfJ7/1EBconw==", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "estree-walker": "^3.0.3", + "js-tokens": "^9.0.1" } }, - "node_modules/babel-plugin-jest-hoist": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", - "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "node_modules/ast-v8-to-istanbul/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz", - "integrity": "sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-import-attributes": "^7.24.7", - "@babel/plugin-syntax-import-meta": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@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-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "@types/estree": "^1.0.0" } }, - "node_modules/babel-preset-jest": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", - "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", - "dev": true, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "license": "MIT", "dependencies": { - "babel-plugin-jest-hoist": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0" + "possible-typed-array-names": "^1.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 0.4" }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/balanced-match": { @@ -2442,6 +2531,13 @@ "multicast-dns-service-types": "^1.1.0" } }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true, + "license": "ISC" + }, "node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -2498,35 +2594,35 @@ "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==", + "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/builtin-modules": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-5.0.0.tgz", + "integrity": "sha512-bkXY9WsVpY7CvMhKSR6pZilZu9Ln5WDrKVBUXf2S443etkmEO4V58heTecXcUIsNsi4Rx8JUO4NfX1IcQl4deg==", "dev": true, "license": "MIT", - "dependencies": { - "fast-json-stable-stringify": "2.x" - }, "engines": { - "node": ">= 6" + "node": ">=18.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "node-int64": "^0.4.0" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "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/call-bind": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", @@ -2580,16 +2676,7 @@ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, "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==", - "dev": true, - "license": "MIT", + "peer": true, "engines": { "node": ">=6" } @@ -2615,30 +2702,75 @@ ], "license": "CC-BY-4.0" }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chai": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.0.tgz", + "integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==", + "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" }, "engines": { - "node": ">=10" + "node": ">=12" + } + }, + "node_modules/chalk": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", + "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, "funding": { "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "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==", + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/check-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", "dev": true, "license": "MIT", "engines": { - "node": ">=10" + "node": ">= 16" + } + }, + "node_modules/chevrotain": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-7.1.1.tgz", + "integrity": "sha512-wy3mC1x4ye+O+QkEinVJkPf5u2vsrDIYW9G7ZuwFl6v/Yu0LwUuT2POsb+NUWApebyxfkQq6+yDfRExbnI5rcw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "regexp-to-ast": "0.5.0" } }, "node_modules/chokidar": { @@ -2680,9 +2812,9 @@ } }, "node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.2.0.tgz", + "integrity": "sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg==", "dev": true, "funding": [ { @@ -2695,50 +2827,34 @@ "node": ">=8" } }, - "node_modules/cjs-module-lexer": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", - "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", - "dev": true, - "license": "MIT" - }, - "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==", + "node_modules/clean-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz", + "integrity": "sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" + "escape-string-regexp": "^1.0.5" }, "engines": { - "node": ">=12" + "node": ">=4" } }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "node_modules/clean-regexp/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": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, "license": "MIT", "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" + "node": ">=0.8.0" } }, - "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==", - "dev": true, - "license": "MIT" - }, "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==", + "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -2751,15 +2867,26 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, "license": "MIT" }, "node_modules/commander": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", - "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.0.tgz", + "integrity": "sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20" + } + }, + "node_modules/comment-parser": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", + "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12.0.0" } }, "node_modules/concat-map": { @@ -2769,33 +2896,25 @@ "dev": true, "license": "MIT" }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "node_modules/confbox": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", + "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", "dev": true, "license": "MIT" }, - "node_modules/create-jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", - "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "node_modules/core-js-compat": { + "version": "3.42.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.42.0.tgz", + "integrity": "sha512-bQasjMfyDGyaeWKBIu33lHh9qlSR0MFE/Nmc6nMjf/iU9b3rSMdAYz1Baxrv4lPdGUsTqZudHA4jIGSJy0SWZQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "prompts": "^2.0.1" - }, - "bin": { - "create-jest": "bin/create-jest.js" + "browserslist": "^4.24.4" }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" } }, "node_modules/create-require": { @@ -2820,58 +2939,17 @@ "node": ">= 8" } }, - "node_modules/data-view-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", - "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", - "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/inspect-js" - } - }, - "node_modules/data-view-byte-offset": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", - "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true, "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" + "bin": { + "cssesc": "bin/cssesc" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=4" } }, "node_modules/debug": { @@ -2891,19 +2969,28 @@ } } }, - "node_modules/dedent": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.6.0.tgz", - "integrity": "sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA==", + "node_modules/decode-named-character-reference": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.1.0.tgz", + "integrity": "sha512-Wy+JTSbFThEOXQIR2L6mxJvEs+veIzpmqD7ynWxMXGpnk3smkHQOp6forLdHsKpAMW9iJpaBBIxz285t1n1C3w==", "dev": true, "license": "MIT", - "peerDependencies": { - "babel-plugin-macros": "^3.1.0" + "dependencies": { + "character-entities": "^2.0.0" }, - "peerDependenciesMeta": { - "babel-plugin-macros": { - "optional": true - } + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" } }, "node_modules/deep-equal": { @@ -2943,17 +3030,8 @@ "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==", - "dev": true, "license": "MIT", - "engines": { - "node": ">=0.10.0" - } + "peer": true }, "node_modules/define-data-property": { "version": "1.1.4", @@ -2989,14 +3067,28 @@ "url": "https://github.com/sponsors/ljharb" } }, - "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==", + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=6" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, "node_modules/diff": { @@ -3009,16 +3101,6 @@ "node": ">=0.3.1" } }, - "node_modules/diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, "node_modules/dns-packet": { "version": "5.6.1", "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", @@ -3031,19 +3113,6 @@ "node": ">=6" } }, - "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/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -3065,27 +3134,11 @@ "license": "MIT" }, "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true, - "license": "MIT" - }, - "node_modules/ejs": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", - "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "jake": "^10.8.5" - }, - "bin": { - "ejs": "bin/cli.js" - }, - "engines": { - "node": ">=0.10.0" - } + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" }, "node_modules/electron-to-chromium": { "version": "1.5.165", @@ -3094,26 +3147,27 @@ "dev": true, "license": "ISC" }, - "node_modules/emittery": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/enhanced-resolve": { + "version": "5.18.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", + "integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==", "dev": true, "license": "MIT", - "engines": { - "node": ">=12" + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" + "engines": { + "node": ">=10.13.0" } }, - "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==", - "dev": true, - "license": "MIT" - }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -3127,85 +3181,6 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", - "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.2", - "arraybuffer.prototype.slice": "^1.0.4", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "data-view-buffer": "^1.0.2", - "data-view-byte-length": "^1.0.2", - "data-view-byte-offset": "^1.0.1", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "es-set-tostringtag": "^2.1.0", - "es-to-primitive": "^1.3.0", - "function.prototype.name": "^1.1.8", - "get-intrinsic": "^1.3.0", - "get-proto": "^1.0.1", - "get-symbol-description": "^1.1.0", - "globalthis": "^1.0.4", - "gopd": "^1.2.0", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "internal-slot": "^1.1.0", - "is-array-buffer": "^3.0.5", - "is-callable": "^1.2.7", - "is-data-view": "^1.0.2", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.2.1", - "is-set": "^2.0.3", - "is-shared-array-buffer": "^1.0.4", - "is-string": "^1.1.1", - "is-typed-array": "^1.1.15", - "is-weakref": "^1.1.1", - "math-intrinsics": "^1.1.0", - "object-inspect": "^1.13.4", - "object-keys": "^1.1.1", - "object.assign": "^4.1.7", - "own-keys": "^1.0.1", - "regexp.prototype.flags": "^1.5.4", - "safe-array-concat": "^1.1.3", - "safe-push-apply": "^1.0.0", - "safe-regex-test": "^1.1.0", - "set-proto": "^1.0.0", - "stop-iteration-iterator": "^1.1.0", - "string.prototype.trim": "^1.2.10", - "string.prototype.trimend": "^1.0.9", - "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.3", - "typed-array-byte-length": "^1.0.3", - "typed-array-byte-offset": "^1.0.4", - "typed-array-length": "^1.0.7", - "unbox-primitive": "^1.1.0", - "which-typed-array": "^1.1.19" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", @@ -3244,6 +3219,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, "node_modules/es-object-atoms": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", @@ -3256,320 +3238,686 @@ "node": ">= 0.4" } }, - "node_modules/es-set-tostringtag": { + "node_modules/esbuild": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz", + "integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.5", + "@esbuild/android-arm": "0.25.5", + "@esbuild/android-arm64": "0.25.5", + "@esbuild/android-x64": "0.25.5", + "@esbuild/darwin-arm64": "0.25.5", + "@esbuild/darwin-x64": "0.25.5", + "@esbuild/freebsd-arm64": "0.25.5", + "@esbuild/freebsd-x64": "0.25.5", + "@esbuild/linux-arm": "0.25.5", + "@esbuild/linux-arm64": "0.25.5", + "@esbuild/linux-ia32": "0.25.5", + "@esbuild/linux-loong64": "0.25.5", + "@esbuild/linux-mips64el": "0.25.5", + "@esbuild/linux-ppc64": "0.25.5", + "@esbuild/linux-riscv64": "0.25.5", + "@esbuild/linux-s390x": "0.25.5", + "@esbuild/linux-x64": "0.25.5", + "@esbuild/netbsd-arm64": "0.25.5", + "@esbuild/netbsd-x64": "0.25.5", + "@esbuild/openbsd-arm64": "0.25.5", + "@esbuild/openbsd-x64": "0.25.5", + "@esbuild/sunos-x64": "0.25.5", + "@esbuild/win32-arm64": "0.25.5", + "@esbuild/win32-ia32": "0.25.5", + "@esbuild/win32-x64": "0.25.5" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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": { + "version": "9.28.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.28.0.tgz", + "integrity": "sha512-ocgh41VhRlf9+fVpe7QKzwLj9c92fDiqOj8Y3Sd4/ZmVA4Btx4PlUYPq4pp9JDyupkf1upbEXecxL2mwNV7jPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.20.0", + "@eslint/config-helpers": "^0.2.1", + "@eslint/core": "^0.14.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.28.0", + "@eslint/plugin-kit": "^0.3.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.3.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-compat-utils": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.6.5.tgz", + "integrity": "sha512-vAUHYzue4YAa2hNACjB8HvUQj5yehAZgiClyFVVom9cP8z5NSFq3PwB/TtJslN2zAMgRX6FCFCjYBbQh71g5RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/eslint-config-flat-gitignore": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "resolved": "https://registry.npmjs.org/eslint-config-flat-gitignore/-/eslint-config-flat-gitignore-2.1.0.tgz", + "integrity": "sha512-cJzNJ7L+psWp5mXM7jBX+fjHtBvvh06RBlcweMhKD8jWqQw0G78hOW5tpVALGHGFPsBV+ot2H+pdDGJy6CV8pA==", "dev": true, "license": "MIT", "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" + "@eslint/compat": "^1.2.5" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "eslint": "^9.5.0" + } + }, + "node_modules/eslint-flat-config-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-flat-config-utils/-/eslint-flat-config-utils-2.1.0.tgz", + "integrity": "sha512-6fjOJ9tS0k28ketkUcQ+kKptB4dBZY2VijMZ9rGn8Cwnn1SH0cZBoPXT8AHBFHxmHcLFQK9zbELDinZ2Mr1rng==", + "dev": true, + "license": "MIT", + "dependencies": { + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/eslint-formatting-reporter": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/eslint-formatting-reporter/-/eslint-formatting-reporter-0.0.0.tgz", + "integrity": "sha512-k9RdyTqxqN/wNYVaTk/ds5B5rA8lgoAmvceYN7bcZMBwU7TuXx5ntewJv81eF3pIL/CiJE+pJZm36llG8yhyyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "prettier-linter-helpers": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/eslint-json-compat-utils": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/eslint-json-compat-utils/-/eslint-json-compat-utils-0.2.1.tgz", + "integrity": "sha512-YzEodbDyW8DX8bImKhAcCeu/L31Dd/70Bidx2Qex9OFUtgzXLqtfWL4Hr5fM/aCCB8QUZLuJur0S9k6UfgFkfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esquery": "^1.6.0" }, "engines": { - "node": ">= 0.4" + "node": ">=12" + }, + "peerDependencies": { + "eslint": "*", + "jsonc-eslint-parser": "^2.4.0" + }, + "peerDependenciesMeta": { + "@eslint/json": { + "optional": true + } } }, - "node_modules/es-shim-unscopables": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", - "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "node_modules/eslint-merge-processors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-merge-processors/-/eslint-merge-processors-2.0.0.tgz", + "integrity": "sha512-sUuhSf3IrJdGooquEUB5TNpGNpBoQccbnaLHsb1XkBLUPPqCNivCpY05ZcpCOiV9uHwO2yxXEWVczVclzMxYlA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "eslint": "*" + } + }, + "node_modules/eslint-parser-plain": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/eslint-parser-plain/-/eslint-parser-plain-0.1.1.tgz", + "integrity": "sha512-KRgd6wuxH4U8kczqPp+Oyk4irThIhHWxgFgLDtpgjUGVIS3wGrJntvZW/p6hHq1T4FOwnOtCNkvAI4Kr+mQ/Hw==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint-plugin-antfu": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-antfu/-/eslint-plugin-antfu-3.1.1.tgz", + "integrity": "sha512-7Q+NhwLfHJFvopI2HBZbSxWXngTwBLKxW1AGXLr2lEGxcEIK/AsDs8pn8fvIizl5aZjBbVbVK5ujmMpBe4Tvdg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "eslint": "*" + } + }, + "node_modules/eslint-plugin-command": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-command/-/eslint-plugin-command-3.2.1.tgz", + "integrity": "sha512-PcpzWe8dvAPaBobxE9zgz1w94fO4JYvzciDzw6thlUb9Uqf5e2/gJz97itOGxvdq+mFeudi71m1OGFgvWmb93w==", "dev": true, "license": "MIT", "dependencies": { - "hasown": "^2.0.2" + "@es-joy/jsdoccomment": "^0.50.2" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "eslint": "*" + } + }, + "node_modules/eslint-plugin-es-x": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.8.0.tgz", + "integrity": "sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/ota-meshi", + "https://opencollective.com/eslint" + ], + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.1.2", + "@eslint-community/regexpp": "^4.11.0", + "eslint-compat-utils": "^0.5.1" }, "engines": { - "node": ">= 0.4" + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": ">=8" } }, - "node_modules/es-to-primitive": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", - "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "node_modules/eslint-plugin-es-x/node_modules/eslint-compat-utils": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz", + "integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==", "dev": true, "license": "MIT", "dependencies": { - "is-callable": "^1.2.7", - "is-date-object": "^1.0.5", - "is-symbol": "^1.0.4" + "semver": "^7.5.4" }, "engines": { - "node": ">= 0.4" + "node": ">=12" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/eslint-plugin-format": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-format/-/eslint-plugin-format-1.0.1.tgz", + "integrity": "sha512-Tdns+CDjS+m7QrM85wwRi2yLae88XiWVdIOXjp9mDII0pmTBQlczPCmjpKnjiUIY3yPZNLqb5Ms/A/JXcBF2Dw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@dprint/formatter": "^0.3.0", + "@dprint/markdown": "^0.17.8", + "@dprint/toml": "^0.6.4", + "eslint-formatting-reporter": "^0.0.0", + "eslint-parser-plain": "^0.1.1", + "prettier": "^3.4.2", + "synckit": "^0.9.2" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "eslint": "^8.40.0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-jsdoc": { + "version": "50.7.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-50.7.1.tgz", + "integrity": "sha512-XBnVA5g2kUVokTNUiE1McEPse5n9/mNUmuJcx52psT6zBs2eVcXSmQBvjfa7NZdfLVSy3u1pEDDUxoxpwy89WA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@es-joy/jsdoccomment": "~0.50.2", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.4.1", + "debug": "^4.4.1", + "escape-string-regexp": "^4.0.0", + "espree": "^10.3.0", + "esquery": "^1.6.0", + "parse-imports-exports": "^0.2.4", + "semver": "^7.7.2", + "spdx-expression-parse": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-jsonc": { + "version": "2.20.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsonc/-/eslint-plugin-jsonc-2.20.1.tgz", + "integrity": "sha512-gUzIwQHXx7ZPypUoadcyRi4WbHW2TPixDr0kqQ4miuJBU0emJmyGTlnaT3Og9X2a8R1CDayN9BFSq5weGWbTng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.5.1", + "eslint-compat-utils": "^0.6.4", + "eslint-json-compat-utils": "^0.2.1", + "espree": "^9.6.1 || ^10.3.0", + "graphemer": "^1.4.0", + "jsonc-eslint-parser": "^2.4.0", + "natural-compare": "^1.4.0", + "synckit": "^0.6.2 || ^0.7.3 || ^0.11.5" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/ota-meshi" + }, + "peerDependencies": { + "eslint": ">=6.0.0" } }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "node_modules/eslint-plugin-jsonc/node_modules/@pkgr/core": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.7.tgz", + "integrity": "sha512-YLT9Zo3oNPJoBjBc4q8G2mjU4tqIbf5CEOORbUUr48dCD9q3umJ3IPlVqOqDakPfd2HuwccBaqlGhN4Gmr5OWg==", "dev": true, "license": "MIT", "engines": { - "node": ">=6" + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" } }, - "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==", + "node_modules/eslint-plugin-jsonc/node_modules/synckit": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.8.tgz", + "integrity": "sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A==", "dev": true, "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.2.4" + }, "engines": { - "node": ">=10" + "node": "^14.18.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/synckit" } }, - "node_modules/eslint": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", - "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", - "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "node_modules/eslint-plugin-n": { + "version": "17.19.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.19.0.tgz", + "integrity": "sha512-qxn1NaDHtizbhVAPpbMT8wWFaLtPnwhfN/e+chdu2i6Vgzmo/tGM62tcJ1Hf7J5Ie4dhse3DOPMmDxduzfifzw==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.1", - "@humanwhocodes/config-array": "^0.13.0", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "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.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "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", - "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", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" + "@eslint-community/eslint-utils": "^4.5.0", + "@typescript-eslint/utils": "^8.26.1", + "enhanced-resolve": "^5.17.1", + "eslint-plugin-es-x": "^7.8.0", + "get-tsconfig": "^4.8.1", + "globals": "^15.11.0", + "ignore": "^5.3.2", + "minimatch": "^9.0.5", + "semver": "^7.6.3", + "ts-declaration-location": "^1.0.6" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": ">=8.23.0" } }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", - "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "node_modules/eslint-plugin-n/node_modules/globals": { + "version": "15.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", + "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", "dev": true, "license": "MIT", - "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "node_modules/eslint-plugin-no-only-tests": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-no-only-tests/-/eslint-plugin-no-only-tests-3.3.0.tgz", + "integrity": "sha512-brcKcxGnISN2CcVhXJ/kEQlNa0MEfGRtwKtWA16SkqXHKitaKIMrfemJKLKX1YqDU5C/5JY3PvZXd5jEW04e0Q==", "dev": true, "license": "MIT", - "dependencies": { - "ms": "^2.1.1" + "engines": { + "node": ">=5.0.0" } }, - "node_modules/eslint-module-utils": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz", - "integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==", + "node_modules/eslint-plugin-perfectionist": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-perfectionist/-/eslint-plugin-perfectionist-4.14.0.tgz", + "integrity": "sha512-BkhiOqzdum8vQSFgj1/q5+6UUWPMn4GELdxuX7uIsGegmAeH/+LnWsiVxgMrxalD0p68sYfMeKaHF1NfrpI/mg==", "dev": true, "license": "MIT", "dependencies": { - "debug": "^3.2.7" + "@typescript-eslint/types": "^8.33.1", + "@typescript-eslint/utils": "^8.33.1", + "natural-orderby": "^5.0.0" }, "engines": { - "node": ">=4" + "node": "^18.0.0 || >=20.0.0" }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } + "peerDependencies": { + "eslint": ">=8.45.0" } }, - "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==", + "node_modules/eslint-plugin-pnpm": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-pnpm/-/eslint-plugin-pnpm-0.3.1.tgz", + "integrity": "sha512-vi5iHoELIAlBbX4AW8ZGzU3tUnfxuXhC/NKo3qRcI5o9igbz6zJUqSlQ03bPeMqWIGTPatZnbWsNR1RnlNERNQ==", "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], "license": "MIT", "dependencies": { - "ms": "^2.1.1" + "find-up-simple": "^1.0.1", + "jsonc-eslint-parser": "^2.4.0", + "pathe": "^2.0.3", + "pnpm-workspace-yaml": "0.3.1", + "tinyglobby": "^0.2.12", + "yaml-eslint-parser": "^1.3.0" + }, + "peerDependencies": { + "eslint": "^9.0.0" } }, - "node_modules/eslint-plugin-import": { - "version": "2.31.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz", - "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", + "node_modules/eslint-plugin-regexp": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-regexp/-/eslint-plugin-regexp-2.8.0.tgz", + "integrity": "sha512-xme90IvkMgdyS+NJC21FM0H6ek4urGsdlIFTXpZRqH2BKJKVSd8hRbyrCpbcqfGBi2jth3eQoLiO3RC1gxZHiw==", "dev": true, "license": "MIT", "dependencies": { - "@rtsao/scc": "^1.1.0", - "array-includes": "^3.1.8", - "array.prototype.findlastindex": "^1.2.5", - "array.prototype.flat": "^1.3.2", - "array.prototype.flatmap": "^1.3.2", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.12.0", - "hasown": "^2.0.2", - "is-core-module": "^2.15.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.8", - "object.groupby": "^1.0.3", - "object.values": "^1.2.0", - "semver": "^6.3.1", - "string.prototype.trimend": "^1.0.8", - "tsconfig-paths": "^3.15.0" + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.11.0", + "comment-parser": "^1.4.0", + "jsdoc-type-pratt-parser": "^4.0.0", + "refa": "^0.12.1", + "regexp-ast-analysis": "^0.7.1", + "scslre": "^0.3.0" }, "engines": { - "node": ">=4" + "node": "^18 || >=20" }, "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + "eslint": ">=8.44.0" } }, - "node_modules/eslint-plugin-import-newlines": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import-newlines/-/eslint-plugin-import-newlines-1.4.0.tgz", - "integrity": "sha512-+Cz1x2xBLtI9gJbmuYEpvY7F8K75wskBmJ7rk4VRObIJo+jklUJaejFJgtnWeL0dCFWabGEkhausrikXaNbtoQ==", + "node_modules/eslint-plugin-toml": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-toml/-/eslint-plugin-toml-0.12.0.tgz", + "integrity": "sha512-+/wVObA9DVhwZB1nG83D2OAQRrcQZXy+drqUnFJKymqnmbnbfg/UPmEMCKrJNcEboUGxUjYrJlgy+/Y930mURQ==", "dev": true, "license": "MIT", - "bin": { - "import-linter": "lib/index.js" + "dependencies": { + "debug": "^4.1.1", + "eslint-compat-utils": "^0.6.0", + "lodash": "^4.17.19", + "toml-eslint-parser": "^0.10.0" }, "engines": { - "node": ">=10.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" }, "peerDependencies": { "eslint": ">=6.0.0" } }, - "node_modules/eslint-plugin-import/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==", + "node_modules/eslint-plugin-unicorn": { + "version": "59.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-59.0.1.tgz", + "integrity": "sha512-EtNXYuWPUmkgSU2E7Ttn57LbRREQesIP1BiLn7OZLKodopKfDXfBUkC/0j6mpw2JExwf43Uf3qLSvrSvppgy8Q==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@babel/helper-validator-identifier": "^7.25.9", + "@eslint-community/eslint-utils": "^4.5.1", + "@eslint/plugin-kit": "^0.2.7", + "ci-info": "^4.2.0", + "clean-regexp": "^1.0.0", + "core-js-compat": "^3.41.0", + "esquery": "^1.6.0", + "find-up-simple": "^1.0.1", + "globals": "^16.0.0", + "indent-string": "^5.0.0", + "is-builtin-module": "^5.0.0", + "jsesc": "^3.1.0", + "pluralize": "^8.0.0", + "regexp-tree": "^0.1.27", + "regjsparser": "^0.12.0", + "semver": "^7.7.1", + "strip-indent": "^4.0.0" + }, + "engines": { + "node": "^18.20.0 || ^20.10.0 || >=21.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1" + }, + "peerDependencies": { + "eslint": ">=9.22.0" } }, - "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==", + "node_modules/eslint-plugin-unicorn/node_modules/@eslint/core": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz", + "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "ms": "^2.1.1" + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "node_modules/eslint-plugin-unicorn/node_modules/@eslint/plugin-kit": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", + "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "esutils": "^2.0.2" + "@eslint/core": "^0.13.0", + "levn": "^0.4.1" }, "engines": { - "node": ">=0.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/eslint-plugin-import/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/eslint-plugin-unused-imports": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.1.4.tgz", + "integrity": "sha512-YptD6IzQjDardkl0POxnnRBhU1OEePMV0nd6siHaRBbd+lyh6NAhFEobiznKU7kTsSsDeSD62Pe7kAM1b7dAZQ==", "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" + "license": "MIT", + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0", + "eslint": "^9.0.0 || ^8.0.0" }, - "engines": { - "node": "*" + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + } } }, - "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==", + "node_modules/eslint-plugin-vue": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-10.2.0.tgz", + "integrity": "sha512-tl9s+KN3z0hN2b8fV2xSs5ytGl7Esk1oSCxULLwFcdaElhZ8btYYZFrWxvh4En+czrSDtuLCeCOGa8HhEZuBdQ==", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "natural-compare": "^1.4.0", + "nth-check": "^2.1.1", + "postcss-selector-parser": "^6.0.15", + "semver": "^7.6.3", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "vue-eslint-parser": "^10.0.0" } }, - "node_modules/eslint-plugin-jest": { - "version": "28.13.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-28.13.0.tgz", - "integrity": "sha512-4AuBcFWOriOeEqy6s4Zup/dQ7E1EPTyyfDaMYmM2YP9xEWPWwK3yYifH1dzY6aHRvyx7y53qMSIyT5s+jrorsQ==", + "node_modules/eslint-plugin-yml": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-yml/-/eslint-plugin-yml-1.18.0.tgz", + "integrity": "sha512-9NtbhHRN2NJa/s3uHchO3qVVZw0vyOIvWlXWGaKCr/6l3Go62wsvJK5byiI6ZoYztDsow4GnS69BZD3GnqH3hA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/utils": "^6.0.0 || ^7.0.0 || ^8.0.0" + "debug": "^4.3.2", + "escape-string-regexp": "4.0.0", + "eslint-compat-utils": "^0.6.0", + "natural-compare": "^1.4.0", + "yaml-eslint-parser": "^1.2.1" }, "engines": { - "node": "^16.10.0 || ^18.12.0 || >=20.0.0" + "node": "^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" }, "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^6.0.0 || ^7.0.0 || ^8.0.0", - "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0", - "jest": "*" + "eslint": ">=6.0.0" + } + }, + "node_modules/eslint-processor-vue-blocks": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-processor-vue-blocks/-/eslint-processor-vue-blocks-2.0.0.tgz", + "integrity": "sha512-u4W0CJwGoWY3bjXAuFpc/b6eK3NQEI8MoeW7ritKj3G3z/WtHrKjkqf+wk8mPEy5rlMGS+k6AZYOw2XBoN/02Q==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" }, - "peerDependenciesMeta": { - "@typescript-eslint/eslint-plugin": { - "optional": true - }, - "jest": { - "optional": true - } + "peerDependencies": { + "@vue/compiler-sfc": "^3.3.0", + "eslint": ">=9.0.0" } }, "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", + "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -3577,44 +3925,70 @@ "estraverse": "^5.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "dev": true, "license": "Apache-2.0", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/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==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/eslint/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==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, - "node_modules/eslint/node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, "engines": { - "node": ">= 4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, "node_modules/eslint/node_modules/minimatch": { @@ -3623,6 +3997,7 @@ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -3631,37 +4006,23 @@ } }, "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.9.0", + "acorn": "^8.14.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "eslint-visitor-keys": "^4.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.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==", - "dev": true, - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/esquery": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", @@ -3698,12 +4059,21 @@ "node": ">=4.0" } }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -3723,55 +4093,22 @@ "through": "^2.3.8" } }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "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": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "node_modules/expect-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.1.tgz", + "integrity": "sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==", "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">= 0.8.0" + "node": ">=12.0.0" } }, - "node_modules/expect": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", - "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "node_modules/exsolve": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.5.tgz", + "integrity": "sha512-pz5dvkYYKQ1AHVrgOzBKWeP4u4FRb3a6DNK2ucr0OoNwYIU4QWsJ+NM36LLzORT+z845MzKHHhpXiUF5nvQoJg==", "dev": true, - "license": "MIT", - "dependencies": { - "@jest/expect-utils": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } + "license": "MIT" }, "node_modules/fast-deep-equal": { "version": "3.1.3", @@ -3779,6 +4116,13 @@ "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.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", @@ -3814,14 +4158,16 @@ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/fast-srp-hap": { "version": "2.0.4", @@ -3842,50 +4188,47 @@ "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==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "bser": "2.1.1" - } - }, - "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==", + "node_modules/fault": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fault/-/fault-2.0.1.tgz", + "integrity": "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==", "dev": true, "license": "MIT", "dependencies": { - "flat-cache": "^3.0.4" + "format": "^0.2.0" }, - "engines": { - "node": "^10.12.0 || >=12.0.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/filelist": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", - "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "node_modules/fdir": { + "version": "6.4.5", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.5.tgz", + "integrity": "sha512-4BG7puHpVsIYxZUbiUE3RqGloLaSSwzYie5jvasC4LWuBWzZawynvYouhjbQKw2JuIGYdm0DzIxl8iVidKlUEw==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "minimatch": "^5.0.1" + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, - "node_modules/filelist/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, - "license": "ISC", + "license": "MIT", + "peer": true, "dependencies": { - "brace-expansion": "^2.0.1" + "flat-cache": "^4.0.0" }, "engines": { - "node": ">=10" + "node": ">=16.0.0" } }, "node_modules/fill-range": { @@ -3907,6 +4250,7 @@ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -3918,36 +4262,32 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "node_modules/find-up-simple": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz", + "integrity": "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==", "dev": true, "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/flat-cache/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, - "license": "ISC", + "license": "MIT", + "peer": true, "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" + "flatted": "^3.2.9", + "keyv": "^4.5.4" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "engines": { + "node": ">=16" } }, "node_modules/flatted": { @@ -3955,7 +4295,8 @@ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", "dev": true, - "license": "ISC" + "license": "ISC", + "peer": true }, "node_modules/for-each": { "version": "0.3.5", @@ -3989,17 +4330,13 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "node_modules/format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", "dev": true, - "license": "ISC", "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=0.4.x" } }, "node_modules/from": { @@ -4022,13 +4359,6 @@ "node": ">=14.14" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, - "license": "ISC" - }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -4053,27 +4383,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/function.prototype.name": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", - "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "functions-have-names": "^1.2.3", - "hasown": "^2.0.2", - "is-callable": "^1.2.7" - }, - "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", @@ -4092,26 +4401,6 @@ "node": ">=8" } }, - "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==", - "dev": true, - "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==", - "dev": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -4136,16 +4425,6 @@ "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - }, "node_modules/get-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", @@ -4159,54 +4438,38 @@ "node": ">= 0.4" } }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-symbol-description": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", - "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "node_modules/get-tsconfig": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", + "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" + "resolve-pkg-maps": "^1.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.2.tgz", + "integrity": "sha512-YT7U7Vye+t5fZ/QMkBFrTJ7ZQxInIUjwyAjVj84CYXqgBdv30MFUPGnBR6sQaVq6Is15wYJUsnzTuWaGRBhBAQ==", "dev": true, "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" + "foreground-child": "^3.1.0", + "jackspeak": "^4.0.1", + "minimatch": "^10.0.0", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" }, "engines": { - "node": "*" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -4218,6 +4481,7 @@ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "is-glob": "^4.0.3" }, @@ -4225,61 +4489,33 @@ "node": ">=10.13.0" } }, - "node_modules/glob/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==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, "node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=8" + "node": "20 || >=22" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/globalthis": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "node_modules/globals": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.2.0.tgz", + "integrity": "sha512-O+7l9tPdHCU320IigZZPj5zmRCFG9xHmx9cU8FqU2Rp+JN714seHV+2S9+JslCpY4gJwU2vOGox0wzgae/MCEg==", "dev": true, "license": "MIT", - "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" - }, "engines": { - "node": ">= 0.4" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/gopd": { @@ -4308,13 +4544,13 @@ "license": "MIT" }, "node_modules/hap-nodejs": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/hap-nodejs/-/hap-nodejs-0.13.1.tgz", - "integrity": "sha512-d5zL2U3L2oROyM5bRUkyuXuqD/uxc0TbrpB/Y5pxqXCsRe2q/O1eNVDB2LnFFIzbh7ahvEpU/KHoC5qYOqfuoQ==", + "version": "2.0.0-beta.0", + "resolved": "https://registry.npmjs.org/hap-nodejs/-/hap-nodejs-2.0.0-beta.0.tgz", + "integrity": "sha512-SUVIOW44w6pCi5pZleQz7XI7aseDEQCDJupxfWtM605GENk7kfzNt4HJYAJRGJgviU9MVIAlEc+vR7NX5BegpQ==", "license": "Apache-2.0", "dependencies": { - "@homebridge/ciao": "^1.3.1", - "@homebridge/dbus-native": "^0.6.0", + "@homebridge/ciao": "^1.3.2", + "@homebridge/dbus-native": "^0.7.1", "bonjour-hap": "^3.9.0", "debug": "^4.4.1", "fast-srp-hap": "^2.0.4", @@ -4325,7 +4561,7 @@ "tweetnacl": "^1.0.3" }, "engines": { - "node": "^18 || ^20 || ^22" + "node": "^20 || ^22" } }, "node_modules/has-bigints": { @@ -4344,6 +4580,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -4361,22 +4598,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-proto": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", - "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", @@ -4435,20 +4656,10 @@ "dev": true, "license": "MIT" }, - "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==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10.17.0" - } - }, "node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "license": "MIT", "engines": { @@ -4468,6 +4679,7 @@ "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -4479,55 +4691,30 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/import-local": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", - "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", - "dev": true, - "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": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=0.8.19" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "node_modules/indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "license": "ISC" - }, "node_modules/internal-slot": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", @@ -4575,33 +4762,6 @@ "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": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-async-function": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", - "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "async-function": "^1.0.0", - "call-bound": "^1.0.3", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-bigint": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", @@ -4646,45 +4806,27 @@ "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==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "node_modules/is-builtin-module": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-5.0.0.tgz", + "integrity": "sha512-f4RqJKBUe5rQkJ2eJEJBXSticB3hGbN9j0yxxMQFqIW89Jp9WYFtzfTcRlstDKVUTRzSOTLKRfO9vIztenwtxA==", "dev": true, "license": "MIT", "dependencies": { - "hasown": "^2.0.2" + "builtin-modules": "^5.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=18.20" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-data-view": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", - "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", - "dev": true, + "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==", "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "is-typed-array": "^1.1.13" - }, "engines": { "node": ">= 0.4" }, @@ -4718,22 +4860,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-finalizationregistry": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", - "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "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", @@ -4744,35 +4870,6 @@ "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/is-generator-function": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", - "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "get-proto": "^1.0.0", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -4798,19 +4895,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", - "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", @@ -4837,16 +4921,6 @@ "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-regex": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", @@ -4892,19 +4966,6 @@ "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-string": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", @@ -4938,22 +4999,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", - "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-weakmap": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", @@ -4966,22 +5011,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-weakref": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", - "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-weakset": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", @@ -5021,23 +5050,6 @@ "node": ">=8" } }, - "node_modules/istanbul-lib-instrument": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", - "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/core": "^7.23.9", - "@babel/parser": "^7.23.9", - "@istanbuljs/schema": "^0.1.3", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^7.5.4" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/istanbul-lib-report": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", @@ -5054,15 +5066,15 @@ } }, "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==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", "dev": true, "license": "BSD-3-Clause", "dependencies": { + "@jridgewell/trace-mapping": "^0.3.23", "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" + "istanbul-lib-coverage": "^3.0.0" }, "engines": { "node": ">=10" @@ -5082,943 +5094,1237 @@ "node": ">=8" } }, - "node_modules/jackspeak": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz", - "integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==", + "node_modules/jackspeak": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz", + "integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "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", + "peer": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdoc-type-pratt-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.1.0.tgz", + "integrity": "sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "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", + "peer": true + }, + "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": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/jsonc-eslint-parser": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonc-eslint-parser/-/jsonc-eslint-parser-2.4.0.tgz", + "integrity": "sha512-WYDyuc/uFcGp6YtM2H0uKmUwieOuzeE/5YocFJLnLfclZ4inf3mRn8ZVy1s7Hxji7Jxm6Ss8gqpexD/GlKoGgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.5.0", + "eslint-visitor-keys": "^3.0.0", + "espree": "^9.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + } + }, + "node_modules/jsonc-eslint-parser/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "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/jsonc-eslint-parser/node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "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/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "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/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, + "node_modules/local-pkg": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.1.tgz", + "integrity": "sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "MIT", "dependencies": { - "@isaacs/cliui": "^8.0.2" + "mlly": "^1.7.4", + "pkg-types": "^2.0.1", + "quansync": "^0.2.8" }, "engines": { - "node": "20 || >=22" + "node": ">=14" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/antfu" } }, - "node_modules/jake": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", - "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", + "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": "Apache-2.0", + "license": "MIT", + "peer": true, "dependencies": { - "async": "^3.2.3", - "chalk": "^4.0.2", - "filelist": "^1.0.4", - "minimatch": "^3.1.2" - }, - "bin": { - "jake": "bin/cli.js" + "p-locate": "^5.0.0" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jake/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==", + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "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", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "peer": true + }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/jake/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/loupe": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.3.tgz", + "integrity": "sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.1.0.tgz", + "integrity": "sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==", "dev": true, "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, "engines": { - "node": "*" + "node": "20 || >=22" } }, - "node_modules/jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", - "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/core": "^29.7.0", - "@jest/types": "^29.6.3", - "import-local": "^3.0.2", - "jest-cli": "^29.7.0" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "@jridgewell/sourcemap-codec": "^1.5.0" } }, - "node_modules/jest-changed-files": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", - "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "node_modules/magicast": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz", + "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==", "dev": true, "license": "MIT", "dependencies": { - "execa": "^5.0.0", - "jest-util": "^29.7.0", - "p-limit": "^3.1.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "@babel/parser": "^7.25.4", + "@babel/types": "^7.25.4", + "source-map-js": "^1.2.0" } }, - "node_modules/jest-circus": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", - "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/expect": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^1.0.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.7.0", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "p-limit": "^3.1.0", - "pretty-format": "^29.7.0", - "pure-rand": "^6.0.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "semver": "^7.5.3" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-cli": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", - "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "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==", + "dev": true, + "license": "ISC" + }, + "node_modules/map-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", + "integrity": "sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==", + "license": "MIT" + }, + "node_modules/markdown-it": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/core": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "create-jest": "^29.7.0", - "exit": "^0.1.2", - "import-local": "^3.0.2", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "yargs": "^17.3.1" + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" }, "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "markdown-it": "bin/markdown-it.mjs" } }, - "node_modules/jest-config": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", - "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "node_modules/markdown-table": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", "dev": true, "license": "MIT", - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.7.0", - "@jest/types": "^29.6.3", - "babel-jest": "^29.7.0", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.7.0", - "jest-environment-node": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-runner": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@types/node": "*", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "ts-node": { - "optional": true - } + "node": ">= 0.4" } }, - "node_modules/jest-diff": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", - "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", + "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", "dev": true, "license": "MIT", "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.6.3", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/jest-docblock": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", - "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", "dev": true, "license": "MIT", - "dependencies": { - "detect-newline": "^3.0.0" - }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-each": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", - "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "node_modules/mdast-util-from-markdown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz", + "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "jest-util": "^29.7.0", - "pretty-format": "^29.7.0" + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/jest-environment-node": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", - "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "node_modules/mdast-util-frontmatter": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-frontmatter/-/mdast-util-frontmatter-2.0.1.tgz", + "integrity": "sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0" + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "escape-string-regexp": "^5.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-extension-frontmatter": "^2.0.0" }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/jest-get-type": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "node_modules/mdast-util-frontmatter/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", "dev": true, "license": "MIT", "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-haste-map": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", - "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "node_modules/mdast-util-gfm": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "^29.6.3", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.6.3", - "jest-util": "^29.7.0", - "jest-worker": "^29.7.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/jest-leak-detector": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", - "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", "dev": true, "license": "MIT", "dependencies": { - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/jest-matcher-utils": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", - "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "node_modules/mdast-util-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", "dev": true, "license": "MIT", "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/jest-message-util": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", - "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.6.3", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/jest-mock": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", - "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-util": "^29.7.0" + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "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==", + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/jest-regex-util": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", - "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", "dev": true, "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/jest-resolve": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", - "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "node_modules/mdast-util-to-markdown": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", "dev": true, "license": "MIT", "dependencies": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "resolve": "^1.20.0", - "resolve.exports": "^2.0.0", - "slash": "^3.0.0" + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/jest-resolve-dependencies": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", - "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", "dev": true, "license": "MIT", "dependencies": { - "jest-regex-util": "^29.6.3", - "jest-snapshot": "^29.7.0" + "@types/mdast": "^4.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "dev": true, + "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": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">= 8" } }, - "node_modules/jest-runner": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", - "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "@jest/console": "^29.7.0", - "@jest/environment": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.7.0", - "jest-environment-node": "^29.7.0", - "jest-haste-map": "^29.7.0", - "jest-leak-detector": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-resolve": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-util": "^29.7.0", - "jest-watcher": "^29.7.0", - "jest-worker": "^29.7.0", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner/node_modules/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/jest-runtime": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", - "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-frontmatter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-frontmatter/-/micromark-extension-frontmatter-2.0.0.tgz", + "integrity": "sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/fake-timers": "^29.7.0", - "@jest/globals": "^29.7.0", - "@jest/source-map": "^29.6.3", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-mock": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", - "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.7.0", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "natural-compare": "^1.4.0", - "pretty-format": "^29.7.0", - "semver": "^7.5.3" + "fault": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/jest-util": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", - "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/jest-validate": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", - "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "^29.6.3", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "leven": "^3.1.0", - "pretty-format": "^29.7.0" + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "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==", + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", "dev": true, "license": "MIT", - "engines": { - "node": ">=10" + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/jest-watcher": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", - "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "jest-util": "^29.7.0", - "string-length": "^4.0.1" + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/jest-worker": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", - "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", + "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", "dev": true, "license": "MIT", "dependencies": { - "@types/node": "*", - "jest-util": "^29.7.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "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==", + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", "dev": true, "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" + "micromark-util-types": "^2.0.0" }, "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "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==", - "dev": true, - "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==", + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", "dev": true, "license": "MIT", "dependencies": { - "argparse": "^2.0.1" + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, - "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==", - "dev": true, - "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": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "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==", + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "json-buffer": "3.0.1" + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">=6" + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "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==", + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">=6" + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "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==", + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" + "micromark-util-symbol": "^2.0.0" } }, - "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==", - "dev": true, - "license": "MIT" - }, - "node_modules/linkify-it": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", - "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "uc.micro": "^2.0.0" + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "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==", + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "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==", + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", "dev": true, - "license": "MIT" + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } }, - "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==", + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", "dev": true, - "license": "ISC", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "yallist": "^3.0.2" + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/lunr": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", - "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT" }, - "node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "micromark-util-symbol": "^2.0.0" } }, - "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==", - "dev": true, - "license": "ISC" - }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", "dev": true, - "license": "BSD-3-Clause", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "tmpl": "1.0.5" + "micromark-util-types": "^2.0.0" } }, - "node_modules/map-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", - "integrity": "sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==", - "license": "MIT" - }, - "node_modules/markdown-it": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", - "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "argparse": "^2.0.1", - "entities": "^4.4.0", - "linkify-it": "^5.0.0", - "mdurl": "^2.0.0", - "punycode.js": "^2.3.1", - "uc.micro": "^2.1.0" - }, - "bin": { - "markdown-it": "bin/markdown-it.mjs" + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">= 0.4" + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/mdurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", - "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT" }, - "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==", + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "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.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -6033,14 +6339,27 @@ "node": ">=8.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==", + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "license": "MIT", "engines": { - "node": ">=6" + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" } }, "node_modules/minimatch": { @@ -6090,6 +6409,38 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/mlly": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.4.tgz", + "integrity": "sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.14.0", + "pathe": "^2.0.1", + "pkg-types": "^1.3.0", + "ufo": "^1.5.4" + } + }, + "node_modules/mlly/node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/mlly/node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -6115,6 +6466,25 @@ "integrity": "sha512-cnAsSVxIDsYt0v7HmC0hWZFwwXSh+E6PgCrREDuN/EsjgLwA5XRmlMHhSiDPrt6HxY1gTivEa/Zh7GtODoLevQ==", "license": "MIT" }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -6122,12 +6492,15 @@ "dev": true, "license": "MIT" }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "node_modules/natural-orderby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/natural-orderby/-/natural-orderby-5.0.0.tgz", + "integrity": "sha512-kKHJhxwpR/Okycz4HhQKKlhWe4ASEfPgkSWNmKFHd7+ezuQlxkA5cM3+XkBPvm1gmHen3w53qsYAv+8GwRrBlg==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=18" + } }, "node_modules/node-persist": { "version": "0.0.12", @@ -6232,17 +6605,17 @@ "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==", + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "path-key": "^3.0.0" + "boolbase": "^1.0.0" }, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" } }, "node_modules/object-inspect": { @@ -6302,91 +6675,13 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object.fromentries": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", - "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.groupby": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", - "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.values": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", - "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", @@ -6399,30 +6694,13 @@ "node": ">= 0.8.0" } }, - "node_modules/own-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", - "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.2.6", - "object-keys": "^1.1.1", - "safe-push-apply": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "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", + "peer": true, "dependencies": { "yocto-queue": "^0.1.0" }, @@ -6439,6 +6717,7 @@ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "p-limit": "^3.0.2" }, @@ -6449,16 +6728,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/package-json-from-dist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", @@ -6466,12 +6735,20 @@ "dev": true, "license": "BlueOak-1.0.0" }, + "node_modules/package-manager-detector": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.3.0.tgz", + "integrity": "sha512-ZsEbbZORsyHuO00lY1kV3/t72yp6Ysay6Pd17ZAlNGuGwmWDLCJxFpRs0IzfXfj1o4icJOkUEioexFHzyPurSQ==", + "dev": true, + "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", + "peer": true, "dependencies": { "callsites": "^3.0.0" }, @@ -6479,45 +6756,44 @@ "node": ">=6" } }, - "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==", + "node_modules/parse-gitignore": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parse-gitignore/-/parse-gitignore-2.0.0.tgz", + "integrity": "sha512-RmVuCHWsfu0QPNW+mraxh/xjQVw/lhUCUru8Zni3Ctq3AoMhpDTq0OVdKS6iesd6Kqb7viCV3isAL43dciOSog==", "dev": true, "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": ">=14" + } + }, + "node_modules/parse-imports-exports": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/parse-imports-exports/-/parse-imports-exports-0.2.4.tgz", + "integrity": "sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-statements": "1.0.11" } }, + "node_modules/parse-statements": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/parse-statements/-/parse-statements-1.0.11.tgz", + "integrity": "sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==", + "dev": true, + "license": "MIT" + }, "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==", "dev": true, "license": "MIT", + "peer": true, "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": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "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", @@ -6528,13 +6804,6 @@ "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==", - "dev": true, - "license": "MIT" - }, "node_modules/path-scurry": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", @@ -6552,14 +6821,21 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.1.0.tgz", - "integrity": "sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==", + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "dev": true, - "license": "ISC", + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", + "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", + "dev": true, + "license": "MIT", "engines": { - "node": "20 || >=22" + "node": ">= 14.16" } }, "node_modules/pause-stream": { @@ -6582,104 +6858,110 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, "license": "MIT", "engines": { - "node": ">=8.6" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pirates": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", - "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "node_modules/pkg-types": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.1.0.tgz", + "integrity": "sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 6" + "dependencies": { + "confbox": "^0.2.1", + "exsolve": "^1.0.1", + "pathe": "^2.0.3" } }, - "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==", + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", "dev": true, "license": "MIT", - "dependencies": { - "find-up": "^4.0.0" - }, "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/pkg-dir/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==", + "node_modules/pnpm-workspace-yaml": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/pnpm-workspace-yaml/-/pnpm-workspace-yaml-0.3.1.tgz", + "integrity": "sha512-3nW5RLmREmZ8Pm8MbPsO2RM+99RRjYd25ynj3NV0cFsN7CcEl4sDFzgoFmSyduFwxFQ2Qbu3y2UdCh6HlyUOeA==", "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], "license": "MIT", "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" + "yaml": "^2.7.0" } }, - "node_modules/pkg-dir/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==", - "dev": true, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, "engines": { - "node": ">=8" + "node": ">= 0.4" } }, - "node_modules/pkg-dir/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==", + "node_modules/postcss": { + "version": "8.5.4", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.4.tgz", + "integrity": "sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", "dependencies": { - "p-try": "^2.0.0" + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^10 || ^12 || >=14" } }, - "node_modules/pkg-dir/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==", + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "dev": true, "license": "MIT", "dependencies": { - "p-limit": "^2.2.0" + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" }, "engines": { - "node": ">=8" - } - }, - "node_modules/possible-typed-array-names": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", - "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" + "node": ">=4" } }, "node_modules/prelude-ls": { @@ -6692,46 +6974,33 @@ "node": ">= 0.8.0" } }, - "node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "node_modules/prettier": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", + "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", "dev": true, "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "bin": { + "prettier": "bin/prettier.cjs" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" + "node": ">=14" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "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==", + "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": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" + "fast-diff": "^1.1.2" }, "engines": { - "node": ">= 6" + "node": ">=6.0.0" } }, "node_modules/pstree.remy": { @@ -6747,6 +7016,7 @@ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=6" } @@ -6761,23 +7031,6 @@ "node": ">=6" } }, - "node_modules/pure-rand": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", - "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ], - "license": "MIT" - }, "node_modules/q": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/q/-/q-1.1.2.tgz", @@ -6797,6 +7050,23 @@ "qrcode-terminal": "bin/qrcode-terminal.js" } }, + "node_modules/quansync": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.10.tgz", + "integrity": "sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], + "license": "MIT" + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -6818,13 +7088,6 @@ ], "license": "MIT" }, - "node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, - "license": "MIT" - }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -6838,27 +7101,61 @@ "node": ">=8.10.0" } }, - "node_modules/reflect.getprototypeof": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", - "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/refa": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/refa/-/refa-0.12.1.tgz", + "integrity": "sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.9", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.7", - "get-proto": "^1.0.1", - "which-builtin-type": "^1.2.1" + "@eslint-community/regexpp": "^4.8.0" }, "engines": { - "node": ">= 0.4" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/regexp-ast-analysis": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/regexp-ast-analysis/-/regexp-ast-analysis-0.7.1.tgz", + "integrity": "sha512-sZuz1dYW/ZsfG17WSAG7eS85r5a0dDsvg+7BiiYR5o6lKCAtUrEwdmRmaGF6rwVj3LcmAeYkOWKEPlbPzN3Y3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.8.0", + "refa": "^0.12.1" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/regexp-to-ast": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/regexp-to-ast/-/regexp-to-ast-0.5.0.tgz", + "integrity": "sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==", + "dev": true, + "license": "MIT" + }, + "node_modules/regexp-tree": { + "version": "0.1.27", + "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz", + "integrity": "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==", + "dev": true, + "license": "MIT", + "bin": { + "regexp-tree": "bin/regexp-tree" } }, "node_modules/regexp.prototype.flags": { @@ -6881,58 +7178,30 @@ "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": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.10", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", - "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "node_modules/regjsparser": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", + "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "is-core-module": "^2.16.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" + "jsesc": "~3.0.2" }, "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "regjsparser": "bin/parser" } }, - "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==", + "node_modules/regjsparser/node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", "dev": true, "license": "MIT", - "dependencies": { - "resolve-from": "^5.0.0" + "bin": { + "jsesc": "bin/jsesc" }, "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-cwd/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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" + "node": ">=6" } }, "node_modules/resolve-from": { @@ -6941,18 +7210,19 @@ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=4" } }, - "node_modules/resolve.exports": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", - "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", "dev": true, "license": "MIT", - "engines": { - "node": ">=10" + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, "node_modules/reusify": { @@ -6972,36 +7242,12 @@ "integrity": "sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==", "dev": true, "license": "ISC", - "dependencies": { - "glob": "^11.0.0", - "package-json-from-dist": "^1.0.0" - }, - "bin": { - "rimraf": "dist/esm/bin.mjs" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.2.tgz", - "integrity": "sha512-YT7U7Vye+t5fZ/QMkBFrTJ7ZQxInIUjwyAjVj84CYXqgBdv30MFUPGnBR6sQaVq6Is15wYJUsnzTuWaGRBhBAQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^4.0.1", - "minimatch": "^10.0.0", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^2.0.0" + "dependencies": { + "glob": "^11.0.0", + "package-json-from-dist": "^1.0.0" }, "bin": { - "glob": "dist/esm/bin.mjs" + "rimraf": "dist/esm/bin.mjs" }, "engines": { "node": "20 || >=22" @@ -7010,22 +7256,53 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/rimraf/node_modules/minimatch": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", - "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", + "node_modules/rollup": { + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.42.0.tgz", + "integrity": "sha512-LW+Vse3BJPyGJGAJt1j8pWDKPd73QM8cRXYK1IxOBgL2AGLu7Xd2YOW0M2sLUBCkF5MshXXtMApyEAEzMVMsnw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "brace-expansion": "^2.0.1" + "@types/estree": "1.0.7" + }, + "bin": { + "rollup": "dist/bin/rollup" }, "engines": { - "node": "20 || >=22" + "node": ">=18.0.0", + "npm": ">=8.0.0" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.42.0", + "@rollup/rollup-android-arm64": "4.42.0", + "@rollup/rollup-darwin-arm64": "4.42.0", + "@rollup/rollup-darwin-x64": "4.42.0", + "@rollup/rollup-freebsd-arm64": "4.42.0", + "@rollup/rollup-freebsd-x64": "4.42.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.42.0", + "@rollup/rollup-linux-arm-musleabihf": "4.42.0", + "@rollup/rollup-linux-arm64-gnu": "4.42.0", + "@rollup/rollup-linux-arm64-musl": "4.42.0", + "@rollup/rollup-linux-loongarch64-gnu": "4.42.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.42.0", + "@rollup/rollup-linux-riscv64-gnu": "4.42.0", + "@rollup/rollup-linux-riscv64-musl": "4.42.0", + "@rollup/rollup-linux-s390x-gnu": "4.42.0", + "@rollup/rollup-linux-x64-gnu": "4.42.0", + "@rollup/rollup-linux-x64-musl": "4.42.0", + "@rollup/rollup-win32-arm64-msvc": "4.42.0", + "@rollup/rollup-win32-ia32-msvc": "4.42.0", + "@rollup/rollup-win32-x64-msvc": "4.42.0", + "fsevents": "~2.3.2" } }, + "node_modules/rollup/node_modules/@types/estree": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "dev": true, + "license": "MIT" + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -7050,26 +7327,6 @@ "queue-microtask": "^1.2.2" } }, - "node_modules/safe-array-concat": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", - "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "has-symbols": "^1.1.0", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -7090,23 +7347,6 @@ ], "license": "MIT" }, - "node_modules/safe-push-apply": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", - "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/safe-regex-test": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", @@ -7130,6 +7370,21 @@ "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", "license": "ISC" }, + "node_modules/scslre": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/scslre/-/scslre-0.3.0.tgz", + "integrity": "sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.8.0", + "refa": "^0.12.0", + "regexp-ast-analysis": "^0.7.0" + }, + "engines": { + "node": "^14.0.0 || >=16.0.0" + } + }, "node_modules/semver": { "version": "7.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", @@ -7174,21 +7429,6 @@ "node": ">= 0.4" } }, - "node_modules/set-proto": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", - "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -7284,13 +7524,26 @@ "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==", + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", "dev": true, "license": "ISC" }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/simple-update-notifier": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", @@ -7311,16 +7564,6 @@ "dev": true, "license": "MIT" }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "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", @@ -7330,6 +7573,16 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "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", @@ -7340,6 +7593,31 @@ "source-map": "^0.6.0" } }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.21", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz", + "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==", + "dev": true, + "license": "CC0-1.0" + }, "node_modules/split": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", @@ -7352,35 +7630,19 @@ "node": "*" } }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true, - "license": "BSD-3-Clause" - }, - "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==", + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", "dev": true, - "license": "MIT", - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } + "license": "MIT" }, - "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==", + "node_modules/std-env": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz", + "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } + "license": "MIT" }, "node_modules/stop-iteration-iterator": { "version": "1.1.0", @@ -7405,33 +7667,22 @@ "through": "~2.3.4" } }, - "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==", - "dev": true, - "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==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/string-width-cjs": { @@ -7450,76 +7701,50 @@ "node": ">=8" } }, - "node_modules/string.prototype.trim": { - "version": "1.2.10", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", - "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "node_modules/string-width-cjs/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==", "dev": true, "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "define-data-property": "^1.1.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-object-atoms": "^1.0.0", - "has-property-descriptors": "^1.0.2" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/string.prototype.trimend": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", - "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "node_modules/string-width-cjs/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==", "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "license": "MIT" }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", - "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "node_modules/string-width-cjs/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==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, "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==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "ansi-regex": "^6.0.1" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, "node_modules/strip-ansi-cjs": { @@ -7536,24 +7761,30 @@ "node": ">=8" } }, - "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==", + "node_modules/strip-ansi-cjs/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==", "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, - "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==", + "node_modules/strip-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.0.0.tgz", + "integrity": "sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==", "dev": true, "license": "MIT", + "dependencies": { + "min-indent": "^1.0.1" + }, "engines": { - "node": ">=6" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/strip-json-comments": { @@ -7562,6 +7793,7 @@ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=8" }, @@ -7573,6 +7805,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -7581,65 +7814,109 @@ "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==", + "node_modules/synckit": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.3.tgz", + "integrity": "sha512-JJoOEKTfL1urb1mDoEblhD9NhEbWmq9jHEMEnxoC4ujUaZ4itA8vKgwkFAyNClgxplLi9tsUKX+EduK0p/l7sg==", "dev": true, "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">= 0.4" + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/tapable": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz", + "integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/test-exclude": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", + "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^10.4.1", + "minimatch": "^9.0.4" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/isaacs" } }, - "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==", + "node_modules/test-exclude/node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" + "@isaacs/cliui": "^8.0.2" }, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" } }, - "node_modules/test-exclude/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==", + "node_modules/test-exclude/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } + "license": "ISC" }, - "node_modules/test-exclude/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/test-exclude/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^1.1.7" + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "license": "MIT" - }, "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -7652,12 +7929,66 @@ "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", "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==", + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", + "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinypool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.0.tgz", + "integrity": "sha512-7CotroY9a8DKsKprEy/a14aCCm8jYVmR7aFy4fpkZM8sdpNJbKkixuNjgM50yCmip2ezc8z4N7k3oe2+rfRJCQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.3.tgz", + "integrity": "sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==", "dev": true, - "license": "BSD-3-Clause" + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } }, "node_modules/to-regex-range": { "version": "5.0.1", @@ -7672,6 +8003,35 @@ "node": ">=8.0" } }, + "node_modules/toml-eslint-parser": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/toml-eslint-parser/-/toml-eslint-parser-0.10.0.tgz", + "integrity": "sha512-khrZo4buq4qVmsGzS5yQjKe/WsFvV8fGfOjDQN0q4iy9FjRfPWRgTFrU8u1R2iu/SfWLhY9WnCi4Jhdrcbtg+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.0.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + } + }, + "node_modules/toml-eslint-parser/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "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/touch": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", @@ -7695,67 +8055,27 @@ "typescript": ">=4.8.4" } }, - "node_modules/ts-jest": { - "version": "29.3.4", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.3.4.tgz", - "integrity": "sha512-Iqbrm8IXOmV+ggWHOTEbjwyCf2xZlUMv5npExksXohL+tk8va4Fjhb+X2+Rt9NBmgO7bJ8WpnMLOwih/DnMlFA==", + "node_modules/ts-declaration-location": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/ts-declaration-location/-/ts-declaration-location-1.0.7.tgz", + "integrity": "sha512-EDyGAwH1gO0Ausm9gV6T2nUvBgXT5kGoCMJPllOaooZ+4VvJiKBdZE7wK18N1deEowhcUptS+5GXZK8U/fvpwA==", "dev": true, - "license": "MIT", - "dependencies": { - "bs-logger": "^0.2.6", - "ejs": "^3.1.10", - "fast-json-stable-stringify": "^2.1.0", - "jest-util": "^29.0.0", - "json5": "^2.2.3", - "lodash.memoize": "^4.1.2", - "make-error": "^1.3.6", - "semver": "^7.7.2", - "type-fest": "^4.41.0", - "yargs-parser": "^21.1.1" - }, - "bin": { - "ts-jest": "cli.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.0.0-beta.0 <8", - "@jest/transform": "^29.0.0", - "@jest/types": "^29.0.0", - "babel-jest": "^29.0.0", - "jest": "^29.0.0", - "typescript": ">=4.3 <6" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "@jest/transform": { - "optional": true - }, - "@jest/types": { - "optional": true - }, - "babel-jest": { - "optional": true + "funding": [ + { + "type": "ko-fi", + "url": "https://ko-fi.com/rebeccastevens" }, - "esbuild": { - "optional": true + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/ts-declaration-location" } - } - }, - "node_modules/ts-jest/node_modules/type-fest": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", - "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=16" + ], + "license": "BSD-3-Clause", + "dependencies": { + "picomatch": "^4.0.2" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "typescript": ">=4.0.0" } }, "node_modules/ts-node": { @@ -7802,42 +8122,6 @@ } } }, - "node_modules/tsconfig-paths": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", - "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", - "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/tsconfig-paths/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -7863,107 +8147,6 @@ "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==", - "dev": true, - "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-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", - "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typed-array-byte-length": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", - "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", - "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.15", - "reflect.getprototypeof": "^1.0.9" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", - "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0", - "reflect.getprototypeof": "^1.0.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/typedoc": { "version": "0.28.5", "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.28.5.tgz", @@ -8009,38 +8192,85 @@ "dev": true, "license": "MIT" }, - "node_modules/unbox-primitive": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", - "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "node_modules/ufo": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz", + "integrity": "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==", + "dev": true, + "license": "MIT" + }, + "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-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", - "has-bigints": "^1.0.2", - "has-symbols": "^1.1.0", - "which-boxed-primitive": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "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-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } }, "node_modules/universalify": { "version": "2.0.1", @@ -8088,10 +8318,18 @@ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "dependencies": { "punycode": "^2.1.0" } }, + "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==", + "dev": true, + "license": "MIT" + }, "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", @@ -8099,29 +8337,207 @@ "dev": true, "license": "MIT" }, - "node_modules/v8-to-istanbul": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", - "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "node_modules/vite": { + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", + "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", "dev": true, - "license": "ISC", + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.2.tgz", + "integrity": "sha512-Xj/jovjZvDXOq2FgLXu8NsY4uHUMWtzVmMC2LkCu9HWdr9Qu1Is5sanX3Z4jOFKdohfaWDnEJWp9pRP0vVpAcA==", + "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^2.0.0" + "cac": "^6.7.14", + "debug": "^4.4.1", + "es-module-lexer": "^1.7.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "bin": { + "vite-node": "vite-node.mjs" }, "engines": { - "node": ">=10.12.0" + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "node_modules/vitest": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.2.tgz", + "integrity": "sha512-fyNn/Rp016Bt5qvY0OQvIUCwW2vnaEBLxP42PmKbNIoasSYjML+8xyeADOPvBe+Xfl/ubIw4og7Lt9jflRsCNw==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/expect": "3.2.2", + "@vitest/mocker": "3.2.2", + "@vitest/pretty-format": "^3.2.2", + "@vitest/runner": "3.2.2", + "@vitest/snapshot": "3.2.2", + "@vitest/spy": "3.2.2", + "@vitest/utils": "3.2.2", + "chai": "^5.2.0", + "debug": "^4.4.1", + "expect-type": "^1.2.1", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "picomatch": "^4.0.2", + "std-env": "^3.9.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.14", + "tinypool": "^1.1.0", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", + "vite-node": "3.2.2", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.2.2", + "@vitest/ui": "3.2.2", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/vue-eslint-parser": { + "version": "10.1.3", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-10.1.3.tgz", + "integrity": "sha512-dbCBnd2e02dYWsXoqX5yKUZlOt+ExIpq7hmHKPb5ZqKcjf++Eo0hMseFTZMLKThrUk61m+Uv6A2YSBve6ZvuDQ==", + "dev": true, + "license": "MIT", "dependencies": { - "makeerror": "1.0.12" + "debug": "^4.4.0", + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.6.0", + "lodash": "^4.17.21", + "semver": "^7.6.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" } }, "node_modules/which": { @@ -8159,34 +8575,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/which-builtin-type": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", - "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "function.prototype.name": "^1.1.6", - "has-tostringtag": "^1.0.2", - "is-async-function": "^2.0.0", - "is-date-object": "^1.1.0", - "is-finalizationregistry": "^1.1.0", - "is-generator-function": "^1.0.10", - "is-regex": "^1.2.1", - "is-weakref": "^1.0.2", - "isarray": "^2.0.5", - "which-boxed-primitive": "^1.1.0", - "which-collection": "^1.0.2", - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/which-collection": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", @@ -8226,29 +8614,47 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } }, "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==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" @@ -8273,25 +8679,75 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "node_modules/wrap-ansi-cjs/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==", "dev": true, - "license": "ISC" + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "node_modules/write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "node_modules/wrap-ansi-cjs/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==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/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==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/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==", + "dev": true, + "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/wrap-ansi-cjs/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=8" + } + }, + "node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12" } }, "node_modules/xml2js": { @@ -8316,23 +8772,6 @@ "node": ">=4.0" } }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC" - }, "node_modules/yaml": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", @@ -8346,33 +8785,34 @@ "node": ">= 14.6" } }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "node_modules/yaml-eslint-parser": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/yaml-eslint-parser/-/yaml-eslint-parser-1.3.0.tgz", + "integrity": "sha512-E/+VitOorXSLiAqtTd7Yqax0/pAS3xaYMP+AUUJGOK1OZG3rhcj9fcJOM5HJ2VrP1FrStVCWr1muTfQCdj4tAA==", "dev": true, "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" + "eslint-visitor-keys": "^3.0.0", + "yaml": "^2.0.0" }, "engines": { - "node": ">=12" + "node": "^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" } }, - "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==", + "node_modules/yaml-eslint-parser/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "license": "ISC", + "license": "Apache-2.0", "engines": { - "node": ">=12" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/yn": { @@ -8391,12 +8831,24 @@ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } } } } diff --git a/package.json b/package.json index 3c34f36d5..0e91eb99b 100644 --- a/package.json +++ b/package.json @@ -1,78 +1,75 @@ { "name": "homebridge", - "description": "HomeKit support for the impatient", + "type": "module", "version": "1.10.0", + "author": "Nick Farina", + "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "git://github.com/homebridge/homebridge.git" + }, + "bugs": { + "url": "https://github.com/homebridge/homebridge/issues" + }, + "exports": "./dist/index.js", "main": "lib/index.js", "types": "lib/index.d.ts", - "license": "Apache-2.0", - "author": "Nick Farina", "maintainers": [ "oznu ", "Andreas Bauer " ], + "bin": { + "homebridge": "bin/homebridge.js" + }, + "files": [ + "LICENSE", + "README.md", + "bin", + "config-sample.json", + "dist" + ], + "engines": { + "node": "^20.7.0 || ^22" + }, "scripts": { "build": "npm run clean && tsc", "check": "npm install && npm outdated", - "clean": "npm install rimraf && rimraf lib/", - "dev": "DEBUG=* ./bin/homebridge -D -P example-plugins/ || true", + "clean": "rimraf dist && rimraf coverage", + "dev": "DEBUG=* ./bin/homebridge.js -D -P example-plugins/ || true", "docs": "typedoc", - "lint": "eslint 'src/**/*.{js,ts,json}'", + "lint": "eslint .", "lint:fix": "npm run lint -- --fix", + "lint-docs": "typedoc --emit none --treatWarningsAsErrors", "prepublishOnly": "npm run build", "postpublish": "npm run clean", - "test": "jest --forceExit --detectOpenHandles", - "test-coverage": "jest --coverage --forceExit --detectOpenHandles", + "test": "vitest run", + "test-coverage": "npm run test -- --coverage", "watch": "nodemon" }, - "repository": { - "type": "git", - "url": "git://github.com/homebridge/homebridge.git" - }, - "bugs": { - "url": "https://github.com/homebridge/homebridge/issues" - }, - "bin": { - "homebridge": "bin/homebridge" - }, - "engines": { - "node": "^18.15.0 || ^20.7.0 || ^22" - }, - "files": [ - "README.md", - "config-sample.json", - "LICENSE", - "lib", - "bin" - ], - "preferGlobal": true, "dependencies": { - "chalk": "4.1.2", - "commander": "13.1.0", + "chalk": "5.4.1", + "commander": "14.0.0", "fs-extra": "11.3.0", - "hap-nodejs": "0.13.1", + "hap-nodejs": "2.0.0-beta.0", "qrcode-terminal": "0.12.0", "semver": "7.7.2", "source-map-support": "0.5.21" }, "devDependencies": { + "@antfu/eslint-config": "^4.14.1", + "@prettier/plugin-xml": "^3.4.1", "@types/debug": "^4.1.12", "@types/fs-extra": "^11.0.4", - "@types/jest": "^29.5.14", "@types/node": "^22.15.30", "@types/semver": "^7.7.0", "@types/source-map-support": "^0.5.10", - "@typescript-eslint/eslint-plugin": "^8.33.1", - "@typescript-eslint/parser": "^8.33.1", - "eslint": "^8.57.1", - "eslint-plugin-import": "^2.31.0", - "eslint-plugin-import-newlines": "^1.4.0", - "eslint-plugin-jest": "^28.13.0", - "jest": "^29.7.0", + "@vitest/coverage-v8": "^3.2.2", + "eslint-plugin-format": "^1.0.1", "nodemon": "^3.1.10", "rimraf": "^6.0.1", - "ts-jest": "^29.3.4", "ts-node": "^10.9.2", "typedoc": "^0.28.5", - "typescript": "^5.8.3" + "typescript": "^5.8.3", + "vitest": "^3.2.2" } } diff --git a/src/api.spec.ts b/src/api.spec.ts index f7edd32d4..7194582ac 100644 --- a/src/api.spec.ts +++ b/src/api.spec.ts @@ -1,62 +1,51 @@ -import { Service } from "hap-nodejs"; -import { - AccessoryPlugin, - HomebridgeAPI, - InternalAPIEvent, - DynamicPlatformPlugin, -} from "./api"; -import { PlatformAccessory } from "./platformAccessory"; - -const api = new HomebridgeAPI(); -const emitSpy = jest.spyOn(api, "emit"); +import type { AccessoryPlugin, DynamicPlatformPlugin } from './api.js' -class ExampleAccessory implements AccessoryPlugin { +import { Service } from 'hap-nodejs' +import { describe, expect, it, vi } from 'vitest' + +import { HomebridgeAPI, InternalAPIEvent } from './api.js' +const api = new HomebridgeAPI() +const emitSpy = vi.spyOn(api, 'emit') + +class ExampleAccessory implements AccessoryPlugin { getServices(): Service[] { - return [new Service.Switch("TestSwitch")]; + return [new Service.Switch('TestSwitch')] } - } class ExamplePlatform implements DynamicPlatformPlugin { - - // eslint-disable-next-line @typescript-eslint/no-unused-vars - configureAccessory(accessory: PlatformAccessory): void { + configureAccessory(): void { // do nothing } - } -const pluginName = "homebridge-example"; -const accessoryName = "MyCoolAccessory"; -const platformName = "MyCoolPlatform"; - -describe("HomebridgeAPI", () => { - describe("HomebridgeAPI.prototype.registerAccessory", () => { - - it("should register accessory with legacy style signature", function() { - api.registerAccessory(pluginName, accessoryName, ExampleAccessory); - expect(emitSpy).toHaveBeenLastCalledWith(InternalAPIEvent.REGISTER_ACCESSORY, accessoryName, ExampleAccessory, pluginName); - }); - - it("should register accessory without passing plugin name", function() { - api.registerAccessory(accessoryName, ExampleAccessory); - expect(emitSpy).toHaveBeenLastCalledWith(InternalAPIEvent.REGISTER_ACCESSORY, accessoryName, ExampleAccessory); - }); - - }); - - describe("HomebridgeAPI.prototype.registerPlatform", () => { - - it("should register platform with legacy style signature", function() { - api.registerPlatform(pluginName, platformName, ExamplePlatform); - expect(emitSpy).toHaveBeenLastCalledWith(InternalAPIEvent.REGISTER_PLATFORM, platformName, ExamplePlatform, pluginName); - }); - - it("should register platform without passing plugin name", function() { - api.registerPlatform(platformName, ExamplePlatform); - expect(emitSpy).toHaveBeenLastCalledWith(InternalAPIEvent.REGISTER_PLATFORM, platformName, ExamplePlatform); - }); - - }); -}); +const pluginName = 'homebridge-example' +const accessoryName = 'MyCoolAccessory' +const platformName = 'MyCoolPlatform' + +describe('homebridgeAPI', () => { + describe('homebridgeAPI.prototype.registerAccessory', () => { + it('should register accessory with legacy style signature', () => { + api.registerAccessory(pluginName, accessoryName, ExampleAccessory) + expect(emitSpy).toHaveBeenLastCalledWith(InternalAPIEvent.REGISTER_ACCESSORY, accessoryName, ExampleAccessory, pluginName) + }) + + it('should register accessory without passing plugin name', () => { + api.registerAccessory(accessoryName, ExampleAccessory) + expect(emitSpy).toHaveBeenLastCalledWith(InternalAPIEvent.REGISTER_ACCESSORY, accessoryName, ExampleAccessory) + }) + }) + + describe('homebridgeAPI.prototype.registerPlatform', () => { + it('should register platform with legacy style signature', () => { + api.registerPlatform(pluginName, platformName, ExamplePlatform) + expect(emitSpy).toHaveBeenLastCalledWith(InternalAPIEvent.REGISTER_PLATFORM, platformName, ExamplePlatform, pluginName) + }) + + it('should register platform without passing plugin name', () => { + api.registerPlatform(platformName, ExamplePlatform) + expect(emitSpy).toHaveBeenLastCalledWith(InternalAPIEvent.REGISTER_PLATFORM, platformName, ExamplePlatform) + }) + }) +}) diff --git a/src/api.ts b/src/api.ts index c93da90f5..65d17de77 100644 --- a/src/api.ts +++ b/src/api.ts @@ -1,31 +1,37 @@ -import { EventEmitter } from "events"; -import * as hapNodeJs from "hap-nodejs"; -import { Controller, Service } from "hap-nodejs"; -import semver from "semver"; -import { AccessoryConfig, PlatformConfig } from "./bridgeService"; -import { Logger, Logging } from "./logger"; -import { PlatformAccessory } from "./platformAccessory"; -import { PluginManager } from "./pluginManager"; -import { User } from "./user"; -import getVersion from "./version"; - -const log = Logger.internal; - -export type HAP = typeof hapNodeJs; -export type HAPLegacyTypes = typeof hapNodeJs.LegacyTypes; - -export type PluginIdentifier = PluginName | ScopedPluginName; -export type PluginName = string; // plugin name like "homebridge-dummy" -export type ScopedPluginName = string; // plugin name like "@scope/homebridge-dummy" -export type AccessoryName = string; -export type PlatformName = string; - -export type AccessoryIdentifier = string; // format: "PluginIdentifier.AccessoryName" -export type PlatformIdentifier = string; // format: "PluginIdentifier.PlatformName" +import type { Controller, Service } from 'hap-nodejs' +import type { AccessoryConfig, PlatformConfig } from './bridgeService.js' +import type { Logging } from './logger.js' + +import { EventEmitter } from 'node:events' + +import hapNodeJs from 'hap-nodejs' +import semver from 'semver' + +import { Logger } from './logger.js' +import { PlatformAccessory } from './platformAccessory.js' +import { PluginManager } from './pluginManager.js' +import { User } from './user.js' +import getVersion from './version.js' + +const log = Logger.internal + +export type HAP = typeof hapNodeJs +export type HAPLegacyTypes = typeof hapNodeJs.LegacyTypes + +export type PluginIdentifier = PluginName | ScopedPluginName +export type PluginName = string // plugin name like "homebridge-dummy" +export type ScopedPluginName = string // plugin name like "@scope/homebridge-dummy" +export type AccessoryName = string +export type PlatformName = string + +export type AccessoryIdentifier = string // format: "PluginIdentifier.AccessoryName" +export type PlatformIdentifier = string // format: "PluginIdentifier.PlatformName" + +// eslint-disable-next-line no-restricted-syntax export const enum PluginType { - ACCESSORY = "accessory", - PLATFORM = "platform", + ACCESSORY = 'accessory', + PLATFORM = 'platform', } /** @@ -33,7 +39,6 @@ export const enum PluginType { * It is called once the plugin is loaded from disk. */ export interface PluginInitializer { - /** * When the initializer is called the plugin must use the provided api instance and call the appropriate * register methods - {@link API.registerAccessory} or {@link API.registerPlatform} - in order to @@ -41,20 +46,18 @@ export interface PluginInitializer { * * @param {API} api */ - (api: API): void | Promise; - + (api: API): void | Promise } export interface AccessoryPluginConstructor { - new(logger: Logging, config: AccessoryConfig, api: API): AccessoryPlugin; + new(logger: Logging, config: AccessoryConfig, api: API): AccessoryPlugin } export interface AccessoryPlugin { - /** - * Optional method which will be called if a 'identify' of an Accessory is requested by HomeKit. + * Optional method which will be called if an 'identify' of an Accessory is requested by HomeKit. */ - identify?(): void; + identify?: () => void /** * This method will be called once on startup, to query all services to be exposed by the Accessory. @@ -62,7 +65,7 @@ export interface AccessoryPlugin { * * @returns {Service[]} services - returned services will be added to the Accessory */ - getServices(): Service[]; + getServices: () => Service[] /** * This method will be called once on startup, to query all controllers to be exposed by the Accessory. @@ -77,15 +80,13 @@ export interface AccessoryPlugin { * * @returns {Controller[]} controllers - returned controllers will be configured for the Accessory */ - getControllers?(): Controller[]; - + getControllers?: () => Controller[] } export interface PlatformPluginConstructor { - new(logger: Logging, config: Config, api: API): DynamicPlatformPlugin | StaticPlatformPlugin | IndependentPlatformPlugin; + new(logger: Logging, config: Config, api: API): DynamicPlatformPlugin | StaticPlatformPlugin | IndependentPlatformPlugin } -// eslint-disable-next-line @typescript-eslint/no-empty-object-type export interface PlatformPlugin {} // not exported to the public in index.ts /** @@ -94,7 +95,6 @@ export interface PlatformPlugin {} // not exported to the public in index.ts * Accessories can be added or removed by using {@link API.registerPlatformAccessories} or {@link API.unregisterPlatformAccessories}. */ export interface DynamicPlatformPlugin extends PlatformPlugin { - /** * This method is called for every PlatformAccessory, which is recreated from disk on startup. * It should be used to properly initialize the Accessory and setup all event handlers for @@ -102,8 +102,7 @@ export interface DynamicPlatformPlugin extends PlatformPlugin { * * @param {PlatformAccessory} accessory which needs to be configured */ - configureAccessory(accessory: PlatformAccessory): void; - + configureAccessory: (accessory: PlatformAccessory) => void } /** @@ -112,7 +111,6 @@ export interface DynamicPlatformPlugin extends PlatformPlugin { * The bridge waits for all callbacks to return before it is published and accessible by HomeKit controllers. */ export interface StaticPlatformPlugin extends PlatformPlugin { - /** * This method is called once at startup. The Platform should pass all accessories which need to be created * to the callback in form of a {@link AccessoryPlugin}. @@ -120,8 +118,7 @@ export interface StaticPlatformPlugin extends PlatformPlugin { * * @param {(foundAccessories: AccessoryPlugin[]) => void} callback */ - accessories(callback: (foundAccessories: AccessoryPlugin[]) => void): void; - + accessories: (callback: (foundAccessories: AccessoryPlugin[]) => void) => void } /** @@ -130,51 +127,53 @@ export interface StaticPlatformPlugin extends PlatformPlugin { * It should also be used when the platform doesn't intend to expose any accessories at all, like plugins * providing a UI for homebridge. */ -// eslint-disable-next-line @typescript-eslint/no-empty-object-type export interface IndependentPlatformPlugin extends PlatformPlugin { // does not expose any methods } +// eslint-disable-next-line no-restricted-syntax export const enum APIEvent { /** * Event is fired once homebridge has finished with booting up and initializing all components and plugins. * When this event is fired it is possible that the Bridge accessory isn't published yet, if homebridge still needs * to wait for some {@see StaticPlatformPlugin | StaticPlatformPlugins} to finish accessory creation. */ - DID_FINISH_LAUNCHING = "didFinishLaunching", + DID_FINISH_LAUNCHING = 'didFinishLaunching', + /** * This event is fired when homebridge gets shutdown. This could be a regular shutdown or an unexpected crash. * At this stage all Accessories are already unpublished and all PlatformAccessories are already saved to disk! */ - SHUTDOWN = "shutdown", + SHUTDOWN = 'shutdown', } +// eslint-disable-next-line no-restricted-syntax export const enum InternalAPIEvent { - REGISTER_ACCESSORY = "registerAccessory", - REGISTER_PLATFORM = "registerPlatform", + REGISTER_ACCESSORY = 'registerAccessory', + REGISTER_PLATFORM = 'registerPlatform', - PUBLISH_EXTERNAL_ACCESSORIES = "publishExternalAccessories", - REGISTER_PLATFORM_ACCESSORIES = "registerPlatformAccessories", - UPDATE_PLATFORM_ACCESSORIES = "updatePlatformAccessories", - UNREGISTER_PLATFORM_ACCESSORIES = "unregisterPlatformAccessories", + PUBLISH_EXTERNAL_ACCESSORIES = 'publishExternalAccessories', + REGISTER_PLATFORM_ACCESSORIES = 'registerPlatformAccessories', + UPDATE_PLATFORM_ACCESSORIES = 'updatePlatformAccessories', + UNREGISTER_PLATFORM_ACCESSORIES = 'unregisterPlatformAccessories', } export interface API { - /** * The homebridge API version as a floating point number. */ - readonly version: number; + readonly version: number + /** * The current homebridge semver version. */ - readonly serverVersion: string; + readonly serverVersion: string // ------------------ LEGACY EXPORTS FOR PRE TYPESCRIPT ------------------ - readonly user: typeof User; - readonly hap: HAP; - readonly hapLegacyTypes: HAPLegacyTypes; // used for older accessories/platforms - readonly platformAccessory: typeof PlatformAccessory; + readonly user: typeof User + readonly hap: HAP + readonly hapLegacyTypes: HAPLegacyTypes // used for older accessories/platforms + readonly platformAccessory: typeof PlatformAccessory // ------------------------------------------------------------------------ /** @@ -192,164 +191,134 @@ export interface API { * * @param version */ - versionGreaterOrEqual(version: string): boolean; + versionGreaterOrEqual: (version: string) => boolean - registerAccessory(accessoryName: AccessoryName, constructor: AccessoryPluginConstructor): void; - registerAccessory(pluginIdentifier: PluginIdentifier, accessoryName: AccessoryName, constructor: AccessoryPluginConstructor): void; + registerAccessory: ((accessoryName: AccessoryName, constructor: AccessoryPluginConstructor) => void) & ((pluginIdentifier: PluginIdentifier, accessoryName: AccessoryName, constructor: AccessoryPluginConstructor) => void) - registerPlatform(platformName: PlatformName, constructor: PlatformPluginConstructor): void; - registerPlatform(pluginIdentifier: PluginIdentifier, platformName: PlatformName, constructor: PlatformPluginConstructor): void; - registerPlatformAccessories(pluginIdentifier: PluginIdentifier, platformName: PlatformName, accessories: PlatformAccessory[]): void; - updatePlatformAccessories(accessories: PlatformAccessory[]): void; - unregisterPlatformAccessories(pluginIdentifier: PluginIdentifier, platformName: PlatformName, accessories: PlatformAccessory[]): void; + registerPlatform: ((platformName: PlatformName, constructor: PlatformPluginConstructor) => void) & ((pluginIdentifier: PluginIdentifier, platformName: PlatformName, constructor: PlatformPluginConstructor) => void) + registerPlatformAccessories: (pluginIdentifier: PluginIdentifier, platformName: PlatformName, accessories: PlatformAccessory[]) => void + updatePlatformAccessories: (accessories: PlatformAccessory[]) => void + unregisterPlatformAccessories: (pluginIdentifier: PluginIdentifier, platformName: PlatformName, accessories: PlatformAccessory[]) => void - publishExternalAccessories(pluginIdentifier: PluginIdentifier, accessories: PlatformAccessory[]): void; - - on(event: "didFinishLaunching", listener: () => void): this; - on(event: "shutdown", listener: () => void): this; + publishExternalAccessories: (pluginIdentifier: PluginIdentifier, accessories: PlatformAccessory[]) => void + on: ((event: 'didFinishLaunching', listener: () => void) => this) & ((event: 'shutdown', listener: () => void) => this) } +// eslint-disable-next-line ts/no-unsafe-declaration-merging export declare interface HomebridgeAPI { + on: ((event: 'didFinishLaunching', listener: () => void) => this) & ((event: 'shutdown', listener: () => void) => this) & ((event: InternalAPIEvent.REGISTER_ACCESSORY, listener: (accessoryName: AccessoryName, accessoryConstructor: AccessoryPluginConstructor, pluginIdentifier?: PluginIdentifier) => void) => this) & ((event: InternalAPIEvent.REGISTER_PLATFORM, listener: (platformName: PlatformName, platformConstructor: PlatformPluginConstructor, pluginIdentifier?: PluginIdentifier) => void) => this) & ((event: InternalAPIEvent.PUBLISH_EXTERNAL_ACCESSORIES, listener: (accessories: PlatformAccessory[]) => void) => this) & ((event: InternalAPIEvent.REGISTER_PLATFORM_ACCESSORIES, listener: (accessories: PlatformAccessory[]) => void) => this) & ((event: InternalAPIEvent.UPDATE_PLATFORM_ACCESSORIES, listener: (accessories: PlatformAccessory[]) => void) => this) & ((event: InternalAPIEvent.UNREGISTER_PLATFORM_ACCESSORIES, listener: (accessories: PlatformAccessory[]) => void) => this) - - on(event: "didFinishLaunching", listener: () => void): this; - on(event: "shutdown", listener: () => void): this; - - // Internal events (using enums directly to restrict access) - on(event: InternalAPIEvent.REGISTER_ACCESSORY, listener: (accessoryName: AccessoryName, accessoryConstructor: AccessoryPluginConstructor, pluginIdentifier?: PluginIdentifier) => void): this; - on(event: InternalAPIEvent.REGISTER_PLATFORM, listener: (platformName: PlatformName, platformConstructor: PlatformPluginConstructor, pluginIdentifier?: PluginIdentifier) => void): this; - - on(event: InternalAPIEvent.PUBLISH_EXTERNAL_ACCESSORIES, listener: (accessories: PlatformAccessory[]) => void): this; - on(event: InternalAPIEvent.REGISTER_PLATFORM_ACCESSORIES, listener: (accessories: PlatformAccessory[]) => void): this; - on(event: InternalAPIEvent.UPDATE_PLATFORM_ACCESSORIES, listener: (accessories: PlatformAccessory[]) => void): this; - on(event: InternalAPIEvent.UNREGISTER_PLATFORM_ACCESSORIES, listener: (accessories: PlatformAccessory[]) => void): this; - - - emit(event: "didFinishLaunching"): boolean; - emit(event: "shutdown"): boolean; - - emit(event: InternalAPIEvent.REGISTER_ACCESSORY, accessoryName: AccessoryName, accessoryConstructor: AccessoryPluginConstructor, pluginIdentifier?: PluginIdentifier): boolean; - emit(event: InternalAPIEvent.REGISTER_PLATFORM, platformName: PlatformName, platformConstructor: PlatformPluginConstructor, pluginIdentifier?: PluginIdentifier): boolean; - - emit(event: InternalAPIEvent.PUBLISH_EXTERNAL_ACCESSORIES, accessories: PlatformAccessory[]): boolean; - emit(event: InternalAPIEvent.REGISTER_PLATFORM_ACCESSORIES, accessories: PlatformAccessory[]): boolean; - emit(event: InternalAPIEvent.UPDATE_PLATFORM_ACCESSORIES, accessories: PlatformAccessory[]): boolean; - emit(event: InternalAPIEvent.UNREGISTER_PLATFORM_ACCESSORIES, accessories: PlatformAccessory[]): boolean; - + emit: ((event: 'didFinishLaunching') => boolean) & ((event: 'shutdown') => boolean) & ((event: InternalAPIEvent.REGISTER_ACCESSORY, accessoryName: AccessoryName, accessoryConstructor: AccessoryPluginConstructor, pluginIdentifier?: PluginIdentifier) => boolean) & ((event: InternalAPIEvent.REGISTER_PLATFORM, platformName: PlatformName, platformConstructor: PlatformPluginConstructor, pluginIdentifier?: PluginIdentifier) => boolean) & ((event: InternalAPIEvent.PUBLISH_EXTERNAL_ACCESSORIES, accessories: PlatformAccessory[]) => boolean) & ((event: InternalAPIEvent.REGISTER_PLATFORM_ACCESSORIES, accessories: PlatformAccessory[]) => boolean) & ((event: InternalAPIEvent.UPDATE_PLATFORM_ACCESSORIES, accessories: PlatformAccessory[]) => boolean) & ((event: InternalAPIEvent.UNREGISTER_PLATFORM_ACCESSORIES, accessories: PlatformAccessory[]) => boolean) } +// eslint-disable-next-line ts/no-unsafe-declaration-merging export class HomebridgeAPI extends EventEmitter implements API { - - public readonly version = 2.7; // homebridge API version - public readonly serverVersion = getVersion(); // homebridge node module version + public readonly version = 2.7 // homebridge API version + public readonly serverVersion = getVersion() // homebridge node module version // ------------------ LEGACY EXPORTS FOR PRE TYPESCRIPT ------------------ - readonly user = User; - readonly hap = hapNodeJs; - readonly hapLegacyTypes = hapNodeJs.LegacyTypes; // used for older accessories/platforms - readonly platformAccessory = PlatformAccessory; + readonly user = User + readonly hap = hapNodeJs + readonly hapLegacyTypes = hapNodeJs.LegacyTypes // used for older accessories/platforms + readonly platformAccessory = PlatformAccessory // ------------------------------------------------------------------------ constructor() { - super(); + super() } public versionGreaterOrEqual(version: string): boolean { - return semver.gte(this.serverVersion, version); + return semver.gte(this.serverVersion, version) } public static isDynamicPlatformPlugin(platformPlugin: PlatformPlugin): platformPlugin is DynamicPlatformPlugin { - return "configureAccessory" in platformPlugin; + return 'configureAccessory' in platformPlugin } public static isStaticPlatformPlugin(platformPlugin: PlatformPlugin): platformPlugin is StaticPlatformPlugin { - return "accessories" in platformPlugin; + return 'accessories' in platformPlugin } signalFinished(): void { - this.emit(APIEvent.DID_FINISH_LAUNCHING); + this.emit(APIEvent.DID_FINISH_LAUNCHING) } signalShutdown(): void { - this.emit(APIEvent.SHUTDOWN); + this.emit(APIEvent.SHUTDOWN) } - registerAccessory(accessoryName: AccessoryName, constructor: AccessoryPluginConstructor): void; - registerAccessory(pluginIdentifier: PluginIdentifier, accessoryName: AccessoryName, constructor: AccessoryPluginConstructor): void; - + registerAccessory(accessoryName: AccessoryName, constructor: AccessoryPluginConstructor): void + registerAccessory(pluginIdentifier: PluginIdentifier, accessoryName: AccessoryName, constructor: AccessoryPluginConstructor): void registerAccessory(pluginIdentifier: PluginIdentifier | AccessoryName, accessoryName: AccessoryName | AccessoryPluginConstructor, constructor?: AccessoryPluginConstructor): void { - if (typeof accessoryName === "function") { - constructor = accessoryName; - accessoryName = pluginIdentifier; - this.emit(InternalAPIEvent.REGISTER_ACCESSORY, accessoryName, constructor); + if (typeof accessoryName === 'function') { + constructor = accessoryName + accessoryName = pluginIdentifier + this.emit(InternalAPIEvent.REGISTER_ACCESSORY, accessoryName, constructor) } else { - this.emit(InternalAPIEvent.REGISTER_ACCESSORY, accessoryName, constructor!, pluginIdentifier); + this.emit(InternalAPIEvent.REGISTER_ACCESSORY, accessoryName, constructor!, pluginIdentifier) } } - registerPlatform(platformName: PlatformName, constructor: PlatformPluginConstructor): void; - registerPlatform(pluginIdentifier: PluginIdentifier, platformName: PlatformName, constructor: PlatformPluginConstructor): void; - + registerPlatform(platformName: PlatformName, constructor: PlatformPluginConstructor): void + registerPlatform(pluginIdentifier: PluginIdentifier, platformName: PlatformName, constructor: PlatformPluginConstructor): void registerPlatform(pluginIdentifier: PluginIdentifier | PlatformName, platformName: PlatformName | PlatformPluginConstructor, constructor?: PlatformPluginConstructor): void { - if (typeof platformName === "function") { - constructor = platformName; - platformName = pluginIdentifier; - this.emit(InternalAPIEvent.REGISTER_PLATFORM, platformName, constructor); + if (typeof platformName === 'function') { + constructor = platformName + platformName = pluginIdentifier + this.emit(InternalAPIEvent.REGISTER_PLATFORM, platformName, constructor) } else { - this.emit(InternalAPIEvent.REGISTER_PLATFORM, platformName, constructor!, pluginIdentifier); + this.emit(InternalAPIEvent.REGISTER_PLATFORM, platformName, constructor!, pluginIdentifier) } } publishCameraAccessories(pluginIdentifier: PluginIdentifier, accessories: PlatformAccessory[]): void { - this.publishExternalAccessories(pluginIdentifier, accessories); + this.publishExternalAccessories(pluginIdentifier, accessories) } publishExternalAccessories(pluginIdentifier: PluginIdentifier, accessories: PlatformAccessory[]): void { if (!PluginManager.isQualifiedPluginIdentifier(pluginIdentifier)) { - log.info(`One of your plugins incorrectly registered an external accessory using the platform name (${pluginIdentifier}) and not the plugin identifier. Please report this to the developer!`); + log.info(`One of your plugins incorrectly registered an external accessory using the platform name (${pluginIdentifier}) and not the plugin identifier. Please report this to the developer!`) } - accessories.forEach(accessory => { + accessories.forEach((accessory) => { // noinspection SuspiciousTypeOfGuard if (!(accessory instanceof PlatformAccessory)) { - throw new Error(`${pluginIdentifier} attempt to register an accessory that isn't PlatformAccessory!`); + throw new TypeError(`${pluginIdentifier} attempt to register an accessory that isn't PlatformAccessory!`) } - accessory._associatedPlugin = pluginIdentifier; - }); + accessory._associatedPlugin = pluginIdentifier + }) - this.emit(InternalAPIEvent.PUBLISH_EXTERNAL_ACCESSORIES, accessories); + this.emit(InternalAPIEvent.PUBLISH_EXTERNAL_ACCESSORIES, accessories) } registerPlatformAccessories(pluginIdentifier: PluginIdentifier, platformName: PlatformName, accessories: PlatformAccessory[]): void { - accessories.forEach(accessory => { + accessories.forEach((accessory) => { // noinspection SuspiciousTypeOfGuard if (!(accessory instanceof PlatformAccessory)) { - throw new Error(`${pluginIdentifier} - ${platformName} attempt to register an accessory that isn't PlatformAccessory!`); + throw new TypeError(`${pluginIdentifier} - ${platformName} attempt to register an accessory that isn't PlatformAccessory!`) } - accessory._associatedPlugin = pluginIdentifier; - accessory._associatedPlatform = platformName; - }); + accessory._associatedPlugin = pluginIdentifier + accessory._associatedPlatform = platformName + }) - this.emit(InternalAPIEvent.REGISTER_PLATFORM_ACCESSORIES, accessories); + this.emit(InternalAPIEvent.REGISTER_PLATFORM_ACCESSORIES, accessories) } updatePlatformAccessories(accessories: PlatformAccessory[]): void { - this.emit(InternalAPIEvent.UPDATE_PLATFORM_ACCESSORIES, accessories); + this.emit(InternalAPIEvent.UPDATE_PLATFORM_ACCESSORIES, accessories) } unregisterPlatformAccessories(pluginIdentifier: PluginIdentifier, platformName: PlatformName, accessories: PlatformAccessory[]): void { - accessories.forEach(accessory => { + accessories.forEach((accessory) => { // noinspection SuspiciousTypeOfGuard if (!(accessory instanceof PlatformAccessory)) { - throw new Error(`${pluginIdentifier} - ${platformName} attempt to unregister an accessory that isn't PlatformAccessory!`); + throw new TypeError(`${pluginIdentifier} - ${platformName} attempt to unregister an accessory that isn't PlatformAccessory!`) } - }); + }) - this.emit(InternalAPIEvent.UNREGISTER_PLATFORM_ACCESSORIES, accessories); + this.emit(InternalAPIEvent.UNREGISTER_PLATFORM_ACCESSORIES, accessories) } - - } diff --git a/src/bridgeService.ts b/src/bridgeService.ts index 74886f6bf..53028ccb7 100644 --- a/src/bridgeService.ts +++ b/src/bridgeService.ts @@ -1,117 +1,120 @@ -import { - Accessory, - AccessoryEventTypes, - Bridge, - Categories, - Characteristic, - CharacteristicEventTypes, +import type { CharacteristicWarning, - CharacteristicWarningType, InterfaceName, IPAddress, MacAddress, - once, + MDNSAdvertiser, PublishInfo, - Service, - uuid, VoidCallback, - MDNSAdvertiser, - HAPLibraryVersion, -} from "hap-nodejs"; -import { +} from 'hap-nodejs' + +import type { AccessoryIdentifier, AccessoryName, AccessoryPlugin, HomebridgeAPI, - InternalAPIEvent, PlatformIdentifier, PlatformName, PluginIdentifier, StaticPlatformPlugin, -} from "./api"; -import { ExternalPortService, ExternalPortsConfiguration } from "./externalPortService"; -import { Logger, Logging, getLogPrefix } from "./logger"; -import { PlatformAccessory, SerializedPlatformAccessory } from "./platformAccessory"; -import { Plugin } from "./plugin"; -import { PluginManager } from "./pluginManager"; -import { HomebridgeOptions } from "./server"; -import { StorageService } from "./storageService"; -import * as mac from "./util/mac"; -import getVersion from "./version"; - -const log = Logger.internal; +} from './api.js' +import type { ExternalPortsConfiguration, ExternalPortService } from './externalPortService.js' +import type { Logging } from './logger.js' +import type { SerializedPlatformAccessory } from './platformAccessory.js' +import type { Plugin } from './plugin.js' +import type { HomebridgeOptions } from './server.js' + +import { + Accessory, + AccessoryEventTypes, + Bridge, + Categories, + Characteristic, + CharacteristicEventTypes, + CharacteristicWarningType, + HAPLibraryVersion, + once, + Service, + uuid, +} from 'hap-nodejs' + +import { InternalAPIEvent } from './api.js' +import { getLogPrefix, Logger } from './logger.js' +import { PlatformAccessory } from './platformAccessory.js' +import { PluginManager } from './pluginManager.js' +import { StorageService } from './storageService.js' +import { generate } from './util/mac.js' +import getVersion from './version.js' + +const log = Logger.internal export interface BridgeConfiguration { - name: string; - username: MacAddress; - pin: string; // format like "000-00-000" - advertiser?: MDNSAdvertiser; - port?: number; - bind?: (InterfaceName | IPAddress) | (InterfaceName | IPAddress)[]; - setupID?: string[4]; - manufacturer?: string; - model?: string; - disableIpc?: boolean; - firmwareRevision?: string; - serialNumber?: string; + name: string + username: MacAddress + pin: string // format like "000-00-000" + advertiser?: MDNSAdvertiser + port?: number + bind?: (InterfaceName | IPAddress) | (InterfaceName | IPAddress)[] + setupID?: string[4] + manufacturer?: string + model?: string + disableIpc?: boolean + firmwareRevision?: string + serialNumber?: string env?: { - DEBUG?: string; - NODE_OPTIONS?: string; - }; + DEBUG?: string + NODE_OPTIONS?: string + } } -// eslint-disable-next-line @typescript-eslint/no-explicit-any export interface AccessoryConfig extends Record { - accessory: AccessoryName | AccessoryIdentifier; - name: string; - uuid_base?: string; - _bridge?: BridgeConfiguration, + accessory: AccessoryName | AccessoryIdentifier + name: string + uuid_base?: string + _bridge?: BridgeConfiguration } -// eslint-disable-next-line @typescript-eslint/no-explicit-any export interface PlatformConfig extends Record { - platform: PlatformName | PlatformIdentifier; - name?: string; - _bridge?: BridgeConfiguration, + platform: PlatformName | PlatformIdentifier + name?: string + _bridge?: BridgeConfiguration } export interface HomebridgeConfig { - bridge: BridgeConfiguration; + bridge: BridgeConfiguration - accessories: AccessoryConfig[]; - platforms: PlatformConfig[]; + accessories: AccessoryConfig[] + platforms: PlatformConfig[] - plugins?: PluginIdentifier[]; // array to define set of active plugins + plugins?: PluginIdentifier[] // array to define set of active plugins /** * Array of disabled plugins. * Unlike the plugins[] config which prevents plugins from being initialised at all, disabled plugins still have their alias loaded, so * we can match config blocks of disabled plugins and show an appropriate message in the logs. */ - disabledPlugins?: PluginIdentifier[]; + disabledPlugins?: PluginIdentifier[] // This section is used to control the range of ports (inclusive) that separate accessory (like camera or television) should be bind to - ports?: ExternalPortsConfiguration; + ports?: ExternalPortsConfiguration } export interface BridgeOptions extends HomebridgeOptions { - cachedAccessoriesDir: string; - cachedAccessoriesItemName: string; + cachedAccessoriesDir: string + cachedAccessoriesItemName: string } export interface CharacteristicWarningOpts { - ignoreSlow?: boolean; + ignoreSlow?: boolean } export class BridgeService { - public bridge: Bridge; - private storageService: StorageService; - - private readonly allowInsecureAccess: boolean; - - private cachedPlatformAccessories: PlatformAccessory[] = []; - private cachedAccessoriesFileLoaded = false; - private readonly publishedExternalAccessories: Map = new Map(); + public bridge: Bridge + private storageService: StorageService + private readonly allowInsecureAccess: boolean + private cachedPlatformAccessories: PlatformAccessory[] = [] + private cachedAccessoriesFileLoaded = false + private readonly publishedExternalAccessories: Map = new Map() constructor( private api: HomebridgeAPI, @@ -121,73 +124,73 @@ export class BridgeService { private bridgeConfig: BridgeConfiguration, private config: HomebridgeConfig, ) { - this.storageService = new StorageService(this.bridgeOptions.cachedAccessoriesDir); - this.storageService.initSync(); + this.storageService = new StorageService(this.bridgeOptions.cachedAccessoriesDir) + this.storageService.initSync() // Server is "secure by default", meaning it creates a top-level Bridge accessory that // will not allow unauthenticated requests. This matches the behavior of actual HomeKit // accessories. However, you can set this to true to allow all requests without authentication, // which can be useful for easy hacking. Note that this will expose all functions of your // bridged accessories, like changing characteristics (i.e. flipping your lights on and off). - this.allowInsecureAccess = this.bridgeOptions.insecureAccess || false; + this.allowInsecureAccess = this.bridgeOptions.insecureAccess || false - this.api.on(InternalAPIEvent.REGISTER_PLATFORM_ACCESSORIES, this.handleRegisterPlatformAccessories.bind(this)); - this.api.on(InternalAPIEvent.UPDATE_PLATFORM_ACCESSORIES, this.handleUpdatePlatformAccessories.bind(this)); - this.api.on(InternalAPIEvent.UNREGISTER_PLATFORM_ACCESSORIES, this.handleUnregisterPlatformAccessories.bind(this)); - this.api.on(InternalAPIEvent.PUBLISH_EXTERNAL_ACCESSORIES, this.handlePublishExternalAccessories.bind(this)); + this.api.on(InternalAPIEvent.REGISTER_PLATFORM_ACCESSORIES, this.handleRegisterPlatformAccessories.bind(this)) + this.api.on(InternalAPIEvent.UPDATE_PLATFORM_ACCESSORIES, this.handleUpdatePlatformAccessories.bind(this)) + this.api.on(InternalAPIEvent.UNREGISTER_PLATFORM_ACCESSORIES, this.handleUnregisterPlatformAccessories.bind(this)) + this.api.on(InternalAPIEvent.PUBLISH_EXTERNAL_ACCESSORIES, this.handlePublishExternalAccessories.bind(this)) - this.bridge = new Bridge(bridgeConfig.name, uuid.generate("HomeBridge")); + this.bridge = new Bridge(bridgeConfig.name, uuid.generate('HomeBridge')) this.bridge.on(AccessoryEventTypes.CHARACTERISTIC_WARNING, () => { // We register characteristic warning handlers on every bridged accessory (to have a reference to the plugin). // For Bridges the warnings will propagate to the main Bridge accessory, thus we need to silence them here. // Otherwise, those would be printed twice (by us and HAP-NodeJS as it detects no handlers on the bridge). - }); + }) } // characteristic warning event has additional parameter originatorChain: string[] which is currently unused public static printCharacteristicWriteWarning(plugin: Plugin, accessory: Accessory, opts: CharacteristicWarningOpts, warning: CharacteristicWarning): void { - const wikiInfo = "See https://homebridge.io/w/JtMGR for more info."; + const wikiInfo = 'See https://homebridge.io/w/JtMGR for more info.' switch (warning.type) { case CharacteristicWarningType.SLOW_READ: case CharacteristicWarningType.SLOW_WRITE: if (!opts.ignoreSlow) { - log.info(getLogPrefix(plugin.getPluginIdentifier()), "This plugin slows down Homebridge.", warning.message, wikiInfo); + log.info(getLogPrefix(plugin.getPluginIdentifier()), 'This plugin slows down Homebridge.', warning.message, wikiInfo) } - break; + break case CharacteristicWarningType.TIMEOUT_READ: case CharacteristicWarningType.TIMEOUT_WRITE: - log.error(getLogPrefix(plugin.getPluginIdentifier()), "This plugin slows down Homebridge.", warning.message, wikiInfo); - break; + log.error(getLogPrefix(plugin.getPluginIdentifier()), 'This plugin slows down Homebridge.', warning.message, wikiInfo) + break case CharacteristicWarningType.WARN_MESSAGE: - log.info(getLogPrefix(plugin.getPluginIdentifier()), `This plugin generated a warning from the characteristic '${warning.characteristic.displayName}':`, warning.message + ".", wikiInfo); - break; + log.info(getLogPrefix(plugin.getPluginIdentifier()), `This plugin generated a warning from the characteristic '${warning.characteristic.displayName}':`, `${warning.message}.`, wikiInfo) + break case CharacteristicWarningType.ERROR_MESSAGE: - log.error(getLogPrefix(plugin.getPluginIdentifier()), `This plugin threw an error from the characteristic '${warning.characteristic.displayName}':`, warning.message + ".", wikiInfo); - break; + log.error(getLogPrefix(plugin.getPluginIdentifier()), `This plugin threw an error from the characteristic '${warning.characteristic.displayName}':`, `${warning.message}.`, wikiInfo) + break case CharacteristicWarningType.DEBUG_MESSAGE: - log.debug(getLogPrefix(plugin.getPluginIdentifier()), `Characteristic '${warning.characteristic.displayName}':`, warning.message + ".", wikiInfo); - break; + log.debug(getLogPrefix(plugin.getPluginIdentifier()), `Characteristic '${warning.characteristic.displayName}':`, `${warning.message}.`, wikiInfo) + break default: // generic message for yet unknown types - log.info(getLogPrefix(plugin.getPluginIdentifier()), `This plugin generated a warning from the characteristic '${warning.characteristic.displayName}':`, warning.message + ".", wikiInfo); - break; + log.info(getLogPrefix(plugin.getPluginIdentifier()), `This plugin generated a warning from the characteristic '${warning.characteristic.displayName}':`, `${warning.message}.`, wikiInfo) + break } if (warning.stack) { - log.debug(getLogPrefix(plugin.getPluginIdentifier()), warning.stack); + log.debug(getLogPrefix(plugin.getPluginIdentifier()), warning.stack) } } public publishBridge(): void { - const bridgeConfig = this.bridgeConfig; + const bridgeConfig = this.bridgeConfig - const info = this.bridge.getService(Service.AccessoryInformation)!; - info.setCharacteristic(Characteristic.Manufacturer, bridgeConfig.manufacturer || "homebridge.io"); - info.setCharacteristic(Characteristic.Model, bridgeConfig.model || "homebridge"); - info.setCharacteristic(Characteristic.SerialNumber, bridgeConfig.serialNumber || bridgeConfig.username); - info.setCharacteristic(Characteristic.FirmwareRevision, bridgeConfig.firmwareRevision || getVersion()); + const info = this.bridge.getService(Service.AccessoryInformation)! + info.setCharacteristic(Characteristic.Manufacturer, bridgeConfig.manufacturer || 'homebridge.io') + info.setCharacteristic(Characteristic.Model, bridgeConfig.model || 'homebridge') + info.setCharacteristic(Characteristic.SerialNumber, bridgeConfig.serialNumber || bridgeConfig.username) + info.setCharacteristic(Characteristic.FirmwareRevision, bridgeConfig.firmwareRevision || getVersion()) this.bridge.on(AccessoryEventTypes.LISTENING, (port: number) => { - log.success("Homebridge v%s (HAP v%s) (%s) is running on port %s.", getVersion(), HAPLibraryVersion(), bridgeConfig.name, port); - }); + log.success('Homebridge v%s (HAP v%s) (%s) is running on port %s.', getVersion(), HAPLibraryVersion(), bridgeConfig.name, port) + }) // noinspection JSDeprecatedSymbols const publishInfo: PublishInfo = { @@ -198,55 +201,55 @@ export class BridgeService { bind: bridgeConfig.bind, addIdentifyingMaterial: true, advertiser: bridgeConfig.advertiser, - }; + } if (bridgeConfig.setupID && bridgeConfig.setupID.length === 4) { - publishInfo.setupID = bridgeConfig.setupID; + publishInfo.setupID = bridgeConfig.setupID } - log.debug("Publishing bridge accessory (name: %s, publishInfo: %o).", this.bridge.displayName, BridgeService.strippingPinCode(publishInfo)); - this.bridge.publish(publishInfo, this.allowInsecureAccess); + log.debug('Publishing bridge accessory (name: %s, publishInfo: %o).', this.bridge.displayName, BridgeService.strippingPinCode(publishInfo)) + this.bridge.publish(publishInfo, this.allowInsecureAccess) } /** * Attempt to load the cached accessories from disk. */ public async loadCachedPlatformAccessoriesFromDisk(): Promise { - let cachedAccessories: SerializedPlatformAccessory[] | null = null; + let cachedAccessories: SerializedPlatformAccessory[] | null = null try { - cachedAccessories = await this.storageService.getItem(this.bridgeOptions.cachedAccessoriesItemName); - } catch (e) { - log.error("Failed to load cached accessories from disk:", e.message); - if (e instanceof SyntaxError) { + cachedAccessories = await this.storageService.getItem(this.bridgeOptions.cachedAccessoriesItemName) + } catch (error: any) { + log.error('Failed to load cached accessories from disk:', error.message) + if (error instanceof SyntaxError) { // syntax error probably means invalid json / corrupted file; try and restore from backup - cachedAccessories = await this.restoreCachedAccessoriesBackup(); + cachedAccessories = await this.restoreCachedAccessoriesBackup() } else { - log.error("Not restoring cached accessories - some accessories may be reset."); + log.error('Not restoring cached accessories - some accessories may be reset.') } } if (cachedAccessories) { - log.info(`Loaded ${cachedAccessories.length} cached accessories from ${this.bridgeOptions.cachedAccessoriesItemName}.`); + log.info(`Loaded ${cachedAccessories.length} cached accessories from ${this.bridgeOptions.cachedAccessoriesItemName}.`) - this.cachedPlatformAccessories = cachedAccessories.map(serialized => { - return PlatformAccessory.deserialize(serialized); - }); + this.cachedPlatformAccessories = cachedAccessories.map((serialized) => { + return PlatformAccessory.deserialize(serialized) + }) if (cachedAccessories.length) { // create a backup of the cache file - await this.createCachedAccessoriesBackup(); + await this.createCachedAccessoriesBackup() } } - this.cachedAccessoriesFileLoaded = true; + this.cachedAccessoriesFileLoaded = true } /** * Return the name of the backup cache file */ private get backupCacheFileName() { - return `.${this.bridgeOptions.cachedAccessoriesItemName}.bak`; + return `.${this.bridgeOptions.cachedAccessoriesItemName}.bak` } /** @@ -255,9 +258,9 @@ export class BridgeService { */ private async createCachedAccessoriesBackup(): Promise { try { - await this.storageService.copyItem(this.bridgeOptions.cachedAccessoriesItemName, this.backupCacheFileName); - } catch (e) { - log.warn(`Failed to create a backup of the ${this.bridgeOptions.cachedAccessoriesItemName} cached accessories file:`, e.message); + await this.storageService.copyItem(this.bridgeOptions.cachedAccessoriesItemName, this.backupCacheFileName) + } catch (error: any) { + log.warn(`Failed to create a backup of the ${this.bridgeOptions.cachedAccessoriesItemName} cached accessories file:`, error.message) } } @@ -267,66 +270,66 @@ export class BridgeService { */ private async restoreCachedAccessoriesBackup(): Promise { try { - const cachedAccessories = await this.storageService.getItem(this.backupCacheFileName); + const cachedAccessories = await this.storageService.getItem(this.backupCacheFileName) if (cachedAccessories && cachedAccessories.length) { - log.warn(`Recovered ${cachedAccessories.length} accessories from ${this.bridgeOptions.cachedAccessoriesItemName} cache backup.`); + log.warn(`Recovered ${cachedAccessories.length} accessories from ${this.bridgeOptions.cachedAccessoriesItemName} cache backup.`) } - return cachedAccessories; - } catch (e) { - return null; + return cachedAccessories + } catch (error: any) { + return null } } public restoreCachedPlatformAccessories(): void { - this.cachedPlatformAccessories = this.cachedPlatformAccessories.filter(accessory => { - let plugin = this.pluginManager.getPlugin(accessory._associatedPlugin!); + this.cachedPlatformAccessories = this.cachedPlatformAccessories.filter((accessory) => { + let plugin = this.pluginManager.getPlugin(accessory._associatedPlugin!) if (!plugin) { // a little explainer here. This section is basically here to resolve plugin name changes of dynamic platform plugins try { // resolve platform accessories by searching for plugins which registered a dynamic platform for the given name - plugin = this.pluginManager.getPluginByActiveDynamicPlatform(accessory._associatedPlatform!); + plugin = this.pluginManager.getPluginByActiveDynamicPlatform(accessory._associatedPlatform!) if (plugin) { // if it's undefined the no plugin was found // could improve on this by calculating the Levenshtein distance to only allow platform ownership changes // when something like a typo happened. Are there other reasons the name could change? // And how would we define the threshold? - log.info("When searching for the associated plugin of the accessory '" + accessory.displayName + "' " + - "it seems like the plugin name changed from '" + accessory._associatedPlugin + "' to '" + - plugin.getPluginIdentifier() + "'. Plugin association is now being transformed!"); + log.info(`When searching for the associated plugin of the accessory '${accessory.displayName}' ` + + `it seems like the plugin name changed from '${accessory._associatedPlugin}' to '${ + plugin.getPluginIdentifier()}'. Plugin association is now being transformed!`) - accessory._associatedPlugin = plugin.getPluginIdentifier(); // update the associated plugin to the new one + accessory._associatedPlugin = plugin.getPluginIdentifier() // update the associated plugin to the new one } - } catch (error) { // error is thrown if multiple plugins where found for the given platform name - log.info("Could not find the associated plugin for the accessory '" + accessory.displayName + "'. " + - "Tried to find the plugin by the platform name but " + error.message); + } catch (error: any) { // error is thrown if multiple plugins where found for the given platform name + log.info(`Could not find the associated plugin for the accessory '${accessory.displayName}'. ` + + `Tried to find the plugin by the platform name but ${error.message}`) } } - const platformPlugins = plugin && plugin.getActiveDynamicPlatform(accessory._associatedPlatform!); + const platformPlugins = plugin && plugin.getActiveDynamicPlatform(accessory._associatedPlatform!) if (plugin) { - accessory._associatedHAPAccessory.on(AccessoryEventTypes.CHARACTERISTIC_WARNING, BridgeService.printCharacteristicWriteWarning.bind(this, plugin, accessory._associatedHAPAccessory, {})); + accessory._associatedHAPAccessory.on(AccessoryEventTypes.CHARACTERISTIC_WARNING, BridgeService.printCharacteristicWriteWarning.bind(this, plugin, accessory._associatedHAPAccessory, {})) } if (!platformPlugins) { - log.info(`Failed to find plugin to handle accessory ${accessory._associatedHAPAccessory.displayName}`); + log.info(`Failed to find plugin to handle accessory ${accessory._associatedHAPAccessory.displayName}`) if (!this.bridgeOptions.keepOrphanedCachedAccessories) { - log.info(`Removing orphaned accessory ${accessory._associatedHAPAccessory.displayName}`); - return false; // filter it from the list + log.info(`Removing orphaned accessory ${accessory._associatedHAPAccessory.displayName}`) + return false // filter it from the list } } else { // We set a placeholder for FirmwareRevision before configureAccessory is called so the plugin has the opportunity to override it. - accessory.getService(Service.AccessoryInformation)?.setCharacteristic(Characteristic.FirmwareRevision, "0"); - platformPlugins.configureAccessory(accessory); + accessory.getService(Service.AccessoryInformation)?.setCharacteristic(Characteristic.FirmwareRevision, '0') + platformPlugins.configureAccessory(accessory) } try { - this.bridge.addBridgedAccessory(accessory._associatedHAPAccessory); - } catch (e) { - log.warn(`${accessory._associatedPlugin ? getLogPrefix(accessory._associatedPlugin): ""} Could not restore cached accessory '${accessory._associatedHAPAccessory.displayName}':`, e?.message); - return false; // filter it from the list + this.bridge.addBridgedAccessory(accessory._associatedHAPAccessory) + } catch (error: any) { + log.warn(`${accessory._associatedPlugin ? getLogPrefix(accessory._associatedPlugin) : ''} Could not restore cached accessory '${accessory._associatedHAPAccessory.displayName}':`, error.message) + return false // filter it from the list } - return true; // keep it in the list - }); + return true // keep it in the list + }) } /** @@ -337,99 +340,99 @@ export class BridgeService { // only save the cache file back to disk if we have already attempted to load it // this should prevent the cache being deleted should homebridge be shutdown before it has finished launching if (this.cachedAccessoriesFileLoaded) { - const serializedAccessories = this.cachedPlatformAccessories.map(accessory => PlatformAccessory.serialize(accessory)); - this.storageService.setItemSync(this.bridgeOptions.cachedAccessoriesItemName, serializedAccessories); + const serializedAccessories = this.cachedPlatformAccessories.map(accessory => PlatformAccessory.serialize(accessory)) + this.storageService.setItemSync(this.bridgeOptions.cachedAccessoriesItemName, serializedAccessories) } - } catch (e) { - log.error("Failed to save cached accessories to disk:", e.message); - log.error("Your accessories will not persist between restarts until this issue is resolved."); + } catch (error: any) { + log.error('Failed to save cached accessories to disk:', error.message) + log.error('Your accessories will not persist between restarts until this issue is resolved.') } } handleRegisterPlatformAccessories(accessories: PlatformAccessory[]): void { - const hapAccessories = accessories.map(accessory => { - this.cachedPlatformAccessories.push(accessory); + const hapAccessories = accessories.map((accessory) => { + this.cachedPlatformAccessories.push(accessory) - const plugin = this.pluginManager.getPlugin(accessory._associatedPlugin!); + const plugin = this.pluginManager.getPlugin(accessory._associatedPlugin!) if (plugin) { - const platforms = plugin.getActiveDynamicPlatform(accessory._associatedPlatform!); + const platforms = plugin.getActiveDynamicPlatform(accessory._associatedPlatform!) if (!platforms) { - log.warn("The plugin '%s' registered a new accessory for the platform '%s'. The platform couldn't be found though!", accessory._associatedPlugin!, accessory._associatedPlatform!); + log.warn('The plugin \'%s\' registered a new accessory for the platform \'%s\'. The platform couldn\'t be found though!', accessory._associatedPlugin!, accessory._associatedPlatform!) } - accessory._associatedHAPAccessory.on(AccessoryEventTypes.CHARACTERISTIC_WARNING, BridgeService.printCharacteristicWriteWarning.bind(this, plugin, accessory._associatedHAPAccessory, {})); + accessory._associatedHAPAccessory.on(AccessoryEventTypes.CHARACTERISTIC_WARNING, BridgeService.printCharacteristicWriteWarning.bind(this, plugin, accessory._associatedHAPAccessory, {})) } else { - log.warn("A platform configured a new accessory under the plugin name '%s'. However no loaded plugin could be found for the name!", accessory._associatedPlugin); + log.warn('A platform configured a new accessory under the plugin name \'%s\'. However no loaded plugin could be found for the name!', accessory._associatedPlugin) } - return accessory._associatedHAPAccessory; - }); + return accessory._associatedHAPAccessory + }) - this.bridge.addBridgedAccessories(hapAccessories); - this.saveCachedPlatformAccessoriesOnDisk(); + this.bridge.addBridgedAccessories(hapAccessories) + this.saveCachedPlatformAccessoriesOnDisk() } handleUpdatePlatformAccessories(accessories: PlatformAccessory[]): void { if (!Array.isArray(accessories)) { // This could be quite destructive if a non-array is passed in, so we'll just ignore it. - return; + return } const nonUpdatedPlugins = this.cachedPlatformAccessories.filter( cachedPlatformAccessory => ( accessories.find(accessory => accessory.UUID === cachedPlatformAccessory._associatedHAPAccessory.UUID) === undefined ), - ); + ) - this.cachedPlatformAccessories = [ ...nonUpdatedPlugins, ...accessories]; + this.cachedPlatformAccessories = [...nonUpdatedPlugins, ...accessories] // Update persisted accessories - this.saveCachedPlatformAccessoriesOnDisk(); + this.saveCachedPlatformAccessoriesOnDisk() } handleUnregisterPlatformAccessories(accessories: PlatformAccessory[]): void { - const hapAccessories = accessories.map(accessory => { - const index = this.cachedPlatformAccessories.indexOf(accessory); + const hapAccessories = accessories.map((accessory) => { + const index = this.cachedPlatformAccessories.indexOf(accessory) if (index >= 0) { - this.cachedPlatformAccessories.splice(index, 1); + this.cachedPlatformAccessories.splice(index, 1) } - return accessory._associatedHAPAccessory; - }); + return accessory._associatedHAPAccessory + }) - this.bridge.removeBridgedAccessories(hapAccessories); - this.saveCachedPlatformAccessoriesOnDisk(); + this.bridge.removeBridgedAccessories(hapAccessories) + this.saveCachedPlatformAccessoriesOnDisk() } async handlePublishExternalAccessories(accessories: PlatformAccessory[]): Promise { - const accessoryPin = this.bridgeConfig.pin; + const accessoryPin = this.bridgeConfig.pin for (const accessory of accessories) { - const hapAccessory = accessory._associatedHAPAccessory; - const advertiseAddress = mac.generate(hapAccessory.UUID); + const hapAccessory = accessory._associatedHAPAccessory + const advertiseAddress = generate(hapAccessory.UUID) // get external port allocation - const accessoryPort = await this.externalPortService.requestPort(advertiseAddress); + const accessoryPort = await this.externalPortService.requestPort(advertiseAddress) if (this.publishedExternalAccessories.has(advertiseAddress)) { - throw new Error(`Accessory ${hapAccessory.displayName} experienced an address collision.`); + throw new Error(`Accessory ${hapAccessory.displayName} experienced an address collision.`) } else { - this.publishedExternalAccessories.set(advertiseAddress, accessory); + this.publishedExternalAccessories.set(advertiseAddress, accessory) } - const plugin = this.pluginManager.getPlugin(accessory._associatedPlugin!); + const plugin = this.pluginManager.getPlugin(accessory._associatedPlugin!) if (plugin) { - hapAccessory.on(AccessoryEventTypes.CHARACTERISTIC_WARNING, BridgeService.printCharacteristicWriteWarning.bind(this, plugin, hapAccessory, { ignoreSlow: true })); + hapAccessory.on(AccessoryEventTypes.CHARACTERISTIC_WARNING, BridgeService.printCharacteristicWriteWarning.bind(this, plugin, hapAccessory, { ignoreSlow: true })) } else if (PluginManager.isQualifiedPluginIdentifier(accessory._associatedPlugin!)) { // we did already complain in api.ts if it wasn't a qualified name - log.warn("A platform configured a external accessory under the plugin name '%s'. However no loaded plugin could be found for the name!", accessory._associatedPlugin); + log.warn('A platform configured a external accessory under the plugin name \'%s\'. However no loaded plugin could be found for the name!', accessory._associatedPlugin) } hapAccessory.on(AccessoryEventTypes.LISTENING, (port: number) => { - log.success("%s is running on port %s.", hapAccessory.displayName, port); - log.info("Please add [%s] manually in Home app. Setup Code: %s", hapAccessory.displayName, accessoryPin); - }); + log.success('%s is running on port %s.', hapAccessory.displayName, port) + log.info('Please add [%s] manually in Home app. Setup Code: %s', hapAccessory.displayName, accessoryPin) + }) // noinspection JSDeprecatedSymbols const publishInfo: PublishInfo = { @@ -440,117 +443,114 @@ export class BridgeService { bind: this.bridgeConfig.bind, addIdentifyingMaterial: true, advertiser: this.bridgeConfig.advertiser, - }; + } - log.debug("Publishing external accessory (name: %s, publishInfo: %o).", hapAccessory.displayName, BridgeService.strippingPinCode(publishInfo)); - hapAccessory.publish(publishInfo, this.allowInsecureAccess); + log.debug('Publishing external accessory (name: %s, publishInfo: %o).', hapAccessory.displayName, BridgeService.strippingPinCode(publishInfo)) + hapAccessory.publish(publishInfo, this.allowInsecureAccess) } } public createHAPAccessory(plugin: Plugin, accessoryInstance: AccessoryPlugin, displayName: string, accessoryType: AccessoryName | AccessoryIdentifier, uuidBase?: string): Accessory | undefined { const services = (accessoryInstance.getServices() || []) - .filter(service => !!service); // filter out undefined values; a common mistake - const controllers = (accessoryInstance.getControllers && accessoryInstance.getControllers() || []) - .filter(controller => !!controller); + .filter(service => !!service) // filter out undefined values; a common mistake + const controllers = ((accessoryInstance.getControllers && accessoryInstance.getControllers()) || []) + .filter(controller => !!controller) if (services.length === 0 && controllers.length === 0) { // check that we only add valid accessory with at least one service - return undefined; + return undefined } // The returned "services" for this accessory are simply an array of new-API-style // Service instances which we can add to a created HAP-NodeJS Accessory directly. - const accessoryUUID = uuid.generate(accessoryType + ":" + (uuidBase || displayName)); - const accessory = new Accessory(displayName, accessoryUUID); + const accessoryUUID = uuid.generate(`${accessoryType}:${uuidBase || displayName}`) + const accessory = new Accessory(displayName, accessoryUUID) // listen for the identify event if the accessory instance has defined an identify() method if (accessoryInstance.identify) { accessory.on(AccessoryEventTypes.IDENTIFY, (paired: boolean, callback: VoidCallback) => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - // eslint-disable-next-line @typescript-eslint/no-empty-function - accessoryInstance.identify!(() => { }); // empty callback for backwards compatibility - callback(); - }); + // @ts-expect-error: empty callback for backwards compatibility + accessoryInstance.identify!(() => {}) + callback() + }) } - const informationService = accessory.getService(Service.AccessoryInformation)!; - services.forEach(service => { + const informationService = accessory.getService(Service.AccessoryInformation)! + services.forEach((service) => { // if you returned an AccessoryInformation service, merge its values with ours if (service instanceof Service.AccessoryInformation) { - service.setCharacteristic(Characteristic.Name, displayName); // ensure display name is set + service.setCharacteristic(Characteristic.Name, displayName) // ensure display name is set // ensure the plugin has not hooked already some listeners (some weird ones do). // Otherwise, they would override our identify listener registered by the HAP-NodeJS accessory - service.getCharacteristic(Characteristic.Identify).removeAllListeners(CharacteristicEventTypes.SET); + service.getCharacteristic(Characteristic.Identify).removeAllListeners(CharacteristicEventTypes.SET) // pull out any values and listeners (get and set) you may have defined - informationService.replaceCharacteristicsFromService(service); + informationService.replaceCharacteristicsFromService(service) } else { - accessory.addService(service); + accessory.addService(service) } - }); + }) - accessory.on(AccessoryEventTypes.CHARACTERISTIC_WARNING, BridgeService.printCharacteristicWriteWarning.bind(this, plugin, accessory, {})); + accessory.on(AccessoryEventTypes.CHARACTERISTIC_WARNING, BridgeService.printCharacteristicWriteWarning.bind(this, plugin, accessory, {})) - controllers.forEach(controller => { - accessory.configureController(controller); - }); + controllers.forEach((controller) => { + accessory.configureController(controller) + }) - return accessory; + return accessory } public async loadPlatformAccessories(plugin: Plugin, platformInstance: StaticPlatformPlugin, platformType: PlatformName | PlatformIdentifier, logger: Logging): Promise { // Plugin 1.0, load accessories - return new Promise(resolve => { + return new Promise((resolve) => { // warn the user if the static platform is blocking the startup of Homebridge for to long const loadDelayWarningInterval = setInterval(() => { - log.warn(getLogPrefix(plugin.getPluginIdentifier()), "This plugin is taking long time to load and preventing Homebridge from starting. See https://homebridge.io/w/JtMGR for more info."); - }, 20000); + log.warn(getLogPrefix(plugin.getPluginIdentifier()), 'This plugin is taking long time to load and preventing Homebridge from starting. See https://homebridge.io/w/JtMGR for more info.') + }, 20000) platformInstance.accessories(once((accessories: AccessoryPlugin[]) => { // clear the load delay warning interval - clearInterval(loadDelayWarningInterval); + clearInterval(loadDelayWarningInterval) // loop through accessories adding them to the list and registering them accessories.forEach((accessoryInstance, index) => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - const accessoryName = accessoryInstance.name; // assume this property was set - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - const uuidBase: string | undefined = accessoryInstance.uuid_base; // optional base uuid + // @ts-expect-error: assume this property was set + const accessoryName = accessoryInstance.name - log.info("Initializing platform accessory '%s'...", accessoryName); + // @ts-expect-error: optional base uuid + const uuidBase: string | undefined = accessoryInstance.uuid_base - const accessory = this.createHAPAccessory(plugin, accessoryInstance, accessoryName, platformType, uuidBase); + log.info('Initializing platform accessory \'%s\'...', accessoryName) + + const accessory = this.createHAPAccessory(plugin, accessoryInstance, accessoryName, platformType, uuidBase) if (accessory) { - this.bridge.addBridgedAccessory(accessory); + this.bridge.addBridgedAccessory(accessory) } else { - logger("Platform %s returned an accessory at index %d with an empty set of services. Won't adding it to the bridge!", platformType, index); + logger('Platform %s returned an accessory at index %d with an empty set of services. Won\'t adding it to the bridge!', platformType, index) } - }); + }) - resolve(); - })); - }); + resolve() + })) + }) } teardown(): void { - this.bridge.unpublish(); + this.bridge.unpublish() for (const accessory of this.publishedExternalAccessories.values()) { - accessory._associatedHAPAccessory.unpublish(); + accessory._associatedHAPAccessory.unpublish() } - this.saveCachedPlatformAccessoriesOnDisk(); + this.saveCachedPlatformAccessoriesOnDisk() - this.api.signalShutdown(); + this.api.signalShutdown() } private static strippingPinCode(publishInfo: PublishInfo): PublishInfo { const info = { ...publishInfo, - }; - info.pincode = "***-**-***"; - return info; + } + info.pincode = '***-**-***' + return info } } diff --git a/src/childBridgeFork.ts b/src/childBridgeFork.ts index 20329e3d8..0ff95961d 100644 --- a/src/childBridgeFork.ts +++ b/src/childBridgeFork.ts @@ -1,60 +1,64 @@ -/** - * This is a standalone script executed as a child process fork - */ -process.title = "homebridge: child bridge"; - -// registering node-source-map-support for typescript stack traces -import "source-map-support/register"; - -import { AccessoryEventTypes, HAPStorage, MacAddress } from "hap-nodejs"; -import { - AccessoryPlugin, - HomebridgeAPI, - PlatformPlugin, - PluginType, -} from "./api"; -import { +/* global NodeJS */ + +import type { MacAddress } from 'hap-nodejs' + +import type { AccessoryPlugin, PlatformPlugin } from './api.js' +import type { AccessoryConfig, BridgeConfiguration, BridgeOptions, - BridgeService, HomebridgeConfig, PlatformConfig, -} from "./bridgeService"; -import { - ChildProcessMessageEventType, - ChildProcessMessageEvent, +} from './bridgeService.js' +import type { + ChildBridgePairedStatusEventData, ChildProcessLoadEventData, - ChildProcessPortRequestEventData, - ChildProcessPortAllocatedEventData, + ChildProcessMessageEvent, ChildProcessPluginLoadedEventData, - ChildBridgePairedStatusEventData, -} from "./childBridgeService"; -import { ChildBridgeExternalPortService } from "./externalPortService"; -import { Logger } from "./logger"; -import { Plugin } from "./plugin"; -import { PluginManager } from "./pluginManager"; -import { User } from "./user"; + ChildProcessPortAllocatedEventData, + ChildProcessPortRequestEventData, +} from './childBridgeService.js' +import type { Plugin } from './plugin.js' + +import process from 'node:process' + +import { AccessoryEventTypes, HAPStorage } from 'hap-nodejs' + +import { HomebridgeAPI, PluginType } from './api.js' +import { BridgeService } from './bridgeService.js' +import { ChildProcessMessageEventType } from './childBridgeService.js' +import { ChildBridgeExternalPortService } from './externalPortService.js' +import { Logger } from './logger.js' +import { PluginManager } from './pluginManager.js' +import { User } from './user.js' + +import 'source-map-support/register.js' + +/** + * This is a standalone script executed as a child process fork + */ + +process.title = 'homebridge: child bridge' export class ChildBridgeFork { - private bridgeService!: BridgeService; - private api!: HomebridgeAPI; - private pluginManager!: PluginManager; - private externalPortService!: ChildBridgeExternalPortService; + private bridgeService!: BridgeService + private api!: HomebridgeAPI + private pluginManager!: PluginManager + private externalPortService!: ChildBridgeExternalPortService - private type!: PluginType; - private plugin!: Plugin; - private identifier!: string; - private pluginConfig!: Array; - private bridgeConfig!: BridgeConfiguration; - private bridgeOptions!: BridgeOptions; - private homebridgeConfig!: HomebridgeConfig; + private type!: PluginType + private plugin!: Plugin + private identifier!: string + private pluginConfig!: Array + private bridgeConfig!: BridgeConfiguration + private bridgeOptions!: BridgeOptions + private homebridgeConfig!: HomebridgeConfig - private portRequestCallback: Map void> = new Map(); + private portRequestCallback: Map void> = new Map() constructor() { // tell the parent process we are ready to accept plugin config - this.sendMessage(ChildProcessMessageEventType.READY); + this.sendMessage(ChildProcessMessageEventType.READY) } sendMessage(type: ChildProcessMessageEventType, data?: T): void { @@ -62,60 +66,60 @@ export class ChildBridgeFork { process.send({ id: type, data, - }); + }) } } async loadPlugin(data: ChildProcessLoadEventData): Promise { // set data - this.type = data.type; - this.identifier = data.identifier; - this.pluginConfig = data.pluginConfig; - this.bridgeConfig = data.bridgeConfig; - this.bridgeOptions = data.bridgeOptions; - this.homebridgeConfig = data.homebridgeConfig; + this.type = data.type + this.identifier = data.identifier + this.pluginConfig = data.pluginConfig + this.bridgeConfig = data.bridgeConfig + this.bridgeOptions = data.bridgeOptions + this.homebridgeConfig = data.homebridgeConfig // remove the _bridge key (some plugins do not like unknown config) for (const config of this.pluginConfig) { - delete config._bridge; + delete config._bridge } // set bridge settings (inherited from main bridge) if (this.bridgeOptions.noLogTimestamps) { - Logger.setTimestampEnabled(false); + Logger.setTimestampEnabled(false) } if (this.bridgeOptions.debugModeEnabled) { - Logger.setDebugEnabled(true); + Logger.setDebugEnabled(true) } if (this.bridgeOptions.forceColourLogging) { - Logger.forceColor(); + Logger.forceColor() } if (this.bridgeOptions.customStoragePath) { - User.setStoragePath(this.bridgeOptions.customStoragePath); + User.setStoragePath(this.bridgeOptions.customStoragePath) } // Initialize HAP-NodeJS with a custom persist directory - HAPStorage.setCustomStoragePath(User.persistPath()); + HAPStorage.setCustomStoragePath(User.persistPath()) // load api - this.api = new HomebridgeAPI(); - this.pluginManager = new PluginManager(this.api); - this.externalPortService = new ChildBridgeExternalPortService(this); + this.api = new HomebridgeAPI() + this.pluginManager = new PluginManager(this.api) + this.externalPortService = new ChildBridgeExternalPortService(this) // load plugin - this.plugin = this.pluginManager.loadPlugin(data.pluginPath); - await this.plugin.load(); - await this.pluginManager.initializePlugin(this.plugin, data.identifier); + this.plugin = this.pluginManager.loadPlugin(data.pluginPath) + await this.plugin.load() + await this.pluginManager.initializePlugin(this.plugin, data.identifier) // change process title to include plugin name - process.title = `homebridge: ${this.plugin.getPluginIdentifier()}`; + process.title = `homebridge: ${this.plugin.getPluginIdentifier()}` this.sendMessage(ChildProcessMessageEventType.LOADED, { version: this.plugin.version, - }); + }) } async startBridge(): Promise { @@ -126,75 +130,74 @@ export class ChildBridgeFork { this.bridgeOptions, this.bridgeConfig, this.homebridgeConfig, - ); + ) // watch bridge events to check when server is online this.bridgeService.bridge.on(AccessoryEventTypes.ADVERTISED, () => { - this.sendPairedStatusEvent(); - }); + this.sendPairedStatusEvent() + }) // watch for the paired event to update the server status this.bridgeService.bridge.on(AccessoryEventTypes.PAIRED, () => { - this.sendPairedStatusEvent(); - }); + this.sendPairedStatusEvent() + }) // watch for the unpaired event to update the server status this.bridgeService.bridge.on(AccessoryEventTypes.UNPAIRED, () => { - this.sendPairedStatusEvent(); - }); + this.sendPairedStatusEvent() + }) // load the cached accessories - await this.bridgeService.loadCachedPlatformAccessoriesFromDisk(); + await this.bridgeService.loadCachedPlatformAccessoriesFromDisk() for (const config of this.pluginConfig) { if (this.type === PluginType.PLATFORM) { - const plugin = this.pluginManager.getPluginForPlatform(this.identifier); - const displayName = config.name || plugin.getPluginIdentifier(); - const logger = Logger.withPrefix(displayName); - const constructor = plugin.getPlatformConstructor(this.identifier); - const platform: PlatformPlugin = new constructor(logger, config as PlatformConfig, this.api); + const plugin = this.pluginManager.getPluginForPlatform(this.identifier) + const displayName = config.name || plugin.getPluginIdentifier() + const logger = Logger.withPrefix(displayName) + const constructor = plugin.getPlatformConstructor(this.identifier) + const platform: PlatformPlugin = new constructor(logger, config as PlatformConfig, this.api) if (HomebridgeAPI.isDynamicPlatformPlugin(platform)) { - plugin.assignDynamicPlatform(this.identifier, platform); + plugin.assignDynamicPlatform(this.identifier, platform) } else if (HomebridgeAPI.isStaticPlatformPlugin(platform)) { // Plugin 1.0, load accessories - await this.bridgeService.loadPlatformAccessories(plugin, platform, this.identifier, logger); + await this.bridgeService.loadPlatformAccessories(plugin, platform, this.identifier, logger) } else { // otherwise it's a IndependentPlatformPlugin which doesn't expose any methods at all. // We just call the constructor and let it be enabled. } - } else if (this.type === PluginType.ACCESSORY) { - const plugin = this.pluginManager.getPluginForAccessory(this.identifier); - const displayName = config.name; + const plugin = this.pluginManager.getPluginForAccessory(this.identifier) + const displayName = config.name if (!displayName) { - Logger.internal.warn("Could not load accessory %s as it is missing the required 'name' property!", this.identifier); - return; + Logger.internal.warn('Could not load accessory %s as it is missing the required \'name\' property!', this.identifier) + return } - const logger = Logger.withPrefix(displayName); - const constructor = plugin.getAccessoryConstructor(this.identifier); - const accessoryInstance: AccessoryPlugin = new constructor(logger, config as AccessoryConfig, this.api); + const logger = Logger.withPrefix(displayName) + const constructor = plugin.getAccessoryConstructor(this.identifier) + const accessoryInstance: AccessoryPlugin = new constructor(logger, config as AccessoryConfig, this.api) - //pass accessoryIdentifier for UUID generation, and optional parameter uuid_base which can be used instead of displayName for UUID generation - const accessory = this.bridgeService.createHAPAccessory(plugin, accessoryInstance, displayName, this.identifier, config.uuid_base); + // pass accessoryIdentifier for UUID generation, and optional parameter uuid_base which can be used instead of displayName for UUID generation + const accessory = this.bridgeService.createHAPAccessory(plugin, accessoryInstance, displayName, this.identifier, config.uuid_base) if (accessory) { - this.bridgeService.bridge.addBridgedAccessory(accessory); + this.bridgeService.bridge.addBridgedAccessory(accessory) } else { - logger("Accessory %s returned empty set of services. Won't adding it to the bridge!", this.identifier); + logger('Accessory %s returned empty set of services. Won\'t adding it to the bridge!', this.identifier) } } } // restore the cached accessories - this.bridgeService.restoreCachedPlatformAccessories(); + this.bridgeService.restoreCachedPlatformAccessories() - this.bridgeService.publishBridge(); - this.api.signalFinished(); + this.bridgeService.publishBridge() + this.api.signalFinished() // tell the parent we are online - this.sendMessage(ChildProcessMessageEventType.ONLINE); + this.sendMessage(ChildProcessMessageEventType.ONLINE) } /** @@ -204,21 +207,21 @@ export class ChildBridgeFork { public async requestExternalPort(username: MacAddress): Promise { return new Promise((resolve) => { const requestTimeout = setTimeout(() => { - Logger.internal.warn("Parent process did not respond to port allocation request within 5 seconds - assigning random port."); - resolve(undefined); - }, 5000); + Logger.internal.warn('Parent process did not respond to port allocation request within 5 seconds - assigning random port.') + resolve(undefined) + }, 5000) // setup callback const callback = (port: number | undefined) => { - clearTimeout(requestTimeout); - resolve(port); - this.portRequestCallback.delete(username); - }; - this.portRequestCallback.set(username, callback); + clearTimeout(requestTimeout) + resolve(port) + this.portRequestCallback.delete(username) + } + this.portRequestCallback.set(username, callback) // send port request - this.sendMessage(ChildProcessMessageEventType.PORT_REQUEST, { username }); - }); + this.sendMessage(ChildProcessMessageEventType.PORT_REQUEST, { username }) + }) } /** @@ -226,9 +229,9 @@ export class ChildBridgeFork { * @param data */ public handleExternalResponse(data: ChildProcessPortAllocatedEventData): void { - const callback = this.portRequestCallback.get(data.username); + const callback = this.portRequestCallback.get(data.username) if (callback) { - callback(data.port); + callback(data.port) } } @@ -239,73 +242,73 @@ export class ChildBridgeFork { this.sendMessage(ChildProcessMessageEventType.STATUS_UPDATE, { paired: this.bridgeService?.bridge?._accessoryInfo?.paired() ?? null, setupUri: this.bridgeService?.bridge?.setupURI() ?? null, - }); + }) } shutdown(): void { - this.bridgeService.teardown(); + this.bridgeService.teardown() } } /** * Start Self */ -const childPluginFork = new ChildBridgeFork(); +const childPluginFork = new ChildBridgeFork() /** * Handle incoming IPC messages from the parent Homebridge process */ -process.on("message", (message: ChildProcessMessageEvent) => { - if (typeof message !== "object" || !message.id) { - return; +process.on('message', (message: ChildProcessMessageEvent) => { + if (typeof message !== 'object' || !message.id) { + return } switch (message.id) { case ChildProcessMessageEventType.LOAD: { - childPluginFork.loadPlugin(message.data as ChildProcessLoadEventData); - break; + childPluginFork.loadPlugin(message.data as ChildProcessLoadEventData) + break } case ChildProcessMessageEventType.START: { - childPluginFork.startBridge(); - break; + childPluginFork.startBridge() + break } case ChildProcessMessageEventType.PORT_ALLOCATED: { - childPluginFork.handleExternalResponse(message.data as ChildProcessPortAllocatedEventData); - break; + childPluginFork.handleExternalResponse(message.data as ChildProcessPortAllocatedEventData) + break } } -}); +}) /** * Handle the sigterm shutdown signals */ -let shuttingDown = false; -const signalHandler = (signal: NodeJS.Signals, signalNum: number): void => { +let shuttingDown = false +function signalHandler(signal: NodeJS.Signals, signalNum: number): void { if (shuttingDown) { - return; + return } - shuttingDown = true; + shuttingDown = true - Logger.internal.info("Got %s, shutting down child bridge process...", signal); + Logger.internal.info('Got %s, shutting down child bridge process...', signal) try { - childPluginFork.shutdown(); - } catch (e) { + childPluginFork.shutdown() + } catch (error: any) { // do nothing } - setTimeout(() => process.exit(128 + signalNum), 5000); -}; + setTimeout(() => process.exit(128 + signalNum), 5000) +} -process.on("SIGINT", signalHandler.bind(undefined, "SIGINT", 2)); -process.on("SIGTERM", signalHandler.bind(undefined, "SIGTERM", 15)); +process.on('SIGINT', signalHandler.bind(undefined, 'SIGINT', 2)) +process.on('SIGTERM', signalHandler.bind(undefined, 'SIGTERM', 15)) /** * Ensure orphaned processes are cleaned up */ setInterval(() => { if (!process.connected) { - Logger.internal.info("Parent process not connected, terminating process..."); - process.exit(1); + Logger.internal.info('Parent process not connected, terminating process...') + process.exit(1) } -}, 5000); +}, 5000) diff --git a/src/childBridgeService.ts b/src/childBridgeService.ts index bb7492767..ac92411e0 100644 --- a/src/childBridgeService.ts +++ b/src/childBridgeService.ts @@ -1,125 +1,140 @@ -import child_process from "child_process"; -import path from "path"; -import fs from "fs-extra"; -import { MacAddress } from "hap-nodejs"; -import { HomebridgeAPI, PluginType } from "./api"; -import { +import type { MacAddress } from 'hap-nodejs' +import type { ChildProcess, ForkOptions } from 'node:child_process' + +import type { HomebridgeAPI } from './api.js' +import type { AccessoryConfig, BridgeConfiguration, BridgeOptions, HomebridgeConfig, PlatformConfig, -} from "./bridgeService"; -import { ExternalPortService } from "./externalPortService"; -import { IpcOutgoingEvent, IpcService } from "./ipcService"; -import { Logger, Logging } from "./logger"; -import { Plugin } from "./plugin"; -import { HomebridgeOptions } from "./server"; -import { User } from "./user"; +} from './bridgeService.js' +import type { ExternalPortService } from './externalPortService.js' +import type { IpcService } from './ipcService.js' +import type { Logging } from './logger.js' +import type { Plugin } from './plugin.js' +import type { HomebridgeOptions } from './server.js' + +import { fork } from 'node:child_process' +import { dirname, resolve } from 'node:path' +import process from 'node:process' +import { fileURLToPath } from 'node:url' + +import fs from 'fs-extra' + +import { PluginType } from './api.js' +import { IpcOutgoingEvent } from './ipcService.js' +import { Logger } from './logger.js' +import { User } from './user.js' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = dirname(__filename) +// eslint-disable-next-line no-restricted-syntax export const enum ChildProcessMessageEventType { /** * Sent from the child process when it is ready to accept config */ - READY = "ready", + READY = 'ready', /** * Sent to the child process with a ChildProcessLoadEventData payload */ - LOAD = "load", + LOAD = 'load', /** * Sent from the child process once it has loaded the plugin */ - LOADED = "loaded", + LOADED = 'loaded', /** * Sent to the child process telling it to start */ - START = "start", + START = 'start', /** * Sent from the child process when the bridge is online */ - ONLINE = "online", + ONLINE = 'online', /** * Sent from the child when it wants to request port allocation for an external accessory */ - PORT_REQUEST = "portRequest", + PORT_REQUEST = 'portRequest', /** * Sent from the parent with the port allocation response */ - PORT_ALLOCATED= "portAllocated", + PORT_ALLOCATED = 'portAllocated', /** * Sent from the child to update its current status */ - STATUS_UPDATE = "status", + STATUS_UPDATE = 'status', } +// eslint-disable-next-line no-restricted-syntax export const enum ChildBridgeStatus { /** * When the child bridge is loading, or restarting */ - PENDING = "pending", + PENDING = 'pending', /** * The child bridge is online and has published it's accessory */ - OK = "ok", + OK = 'ok', /** * The bridge is shutting down, or the process ended unexpectedly */ - DOWN = "down" + DOWN = 'down', } export interface ChildProcessMessageEvent { - id: ChildProcessMessageEventType; + id: ChildProcessMessageEventType data?: T } export interface ChildProcessLoadEventData { - type: PluginType; - identifier: string; - pluginPath: string; - pluginConfig: Array; - bridgeConfig: BridgeConfiguration; - homebridgeConfig: HomebridgeConfig; - bridgeOptions: BridgeOptions; + type: PluginType + identifier: string + pluginPath: string + pluginConfig: Array + bridgeConfig: BridgeConfiguration + homebridgeConfig: HomebridgeConfig + bridgeOptions: BridgeOptions } export interface ChildProcessPluginLoadedEventData { - version: string; + version: string } export interface ChildProcessPortRequestEventData { - username: MacAddress; + username: MacAddress } export interface ChildProcessPortAllocatedEventData { - username: MacAddress; - port?: number; + username: MacAddress + port?: number } export interface ChildBridgePairedStatusEventData { - paired: boolean | null; - setupUri: string | null; + paired: boolean | null + setupUri: string | null } export interface ChildMetadata { - status: ChildBridgeStatus; - paired?: boolean | null; - setupUri?: string | null; - username: MacAddress; - pin: string; - name: string; - plugin: string; - identifier: string; - manuallyStopped: boolean; - pid?: number; + status: ChildBridgeStatus + paired?: boolean | null + setupUri?: string | null + username: MacAddress + pin: string + name: string + plugin: string + identifier: string + manuallyStopped: boolean + pid?: number } /** @@ -127,17 +142,19 @@ export interface ChildMetadata { * A child bridge runs a single platform or accessory. */ export class ChildBridgeService { - private child?: child_process.ChildProcess; - private args: string[] = []; - private processEnv: child_process.ForkOptions = {}; - private shuttingDown = false; - private lastBridgeStatus: ChildBridgeStatus = ChildBridgeStatus.PENDING; - private pairedStatus: boolean | null = null; - private manuallyStopped = false; - private setupUri: string | null = null; - private pluginConfig: Array = []; - private log: Logging; - private displayName?: string; + private child?: ChildProcess + private args: string[] = [] + private processEnv: ForkOptions = {} + private shuttingDown = false + private lastBridgeStatus: ChildBridgeStatus = ChildBridgeStatus.PENDING + private pairedStatus: boolean | null = null + private manuallyStopped = false + private setupUri: string | null = null + private pluginConfig: Array = [] + private log: Logging + private displayName?: string + private restartCount = 0 + private readonly maxRestarts = 4 constructor( public type: PluginType, @@ -150,33 +167,33 @@ export class ChildBridgeService { private ipcService: IpcService, private externalPortService: ExternalPortService, ) { - this.log = Logger.withPrefix(this.plugin.getPluginIdentifier()); - this.api.on("shutdown", () => { - this.shuttingDown = true; - this.teardown(); - }); + this.log = Logger.withPrefix(this.plugin.getPluginIdentifier()) + this.api.on('shutdown', () => { + this.shuttingDown = true + this.teardown() + }) // make sure we don't hit the max listeners limit - this.api.setMaxListeners(this.api.getMaxListeners() + 1); + this.api.setMaxListeners(this.api.getMaxListeners() + 1) } /** * Start the child bridge service */ public start(): void { - this.setProcessFlags(); - this.setProcessEnv(); - this.startChildProcess(); + this.setProcessFlags() + this.setProcessEnv() + this.startChildProcess() // set display name if (this.pluginConfig.length > 1 || this.pluginConfig.length === 0) { - this.displayName = this.plugin.getPluginIdentifier(); + this.displayName = this.plugin.getPluginIdentifier() } else { - this.displayName = this.pluginConfig[0]?.name || this.plugin.getPluginIdentifier(); + this.displayName = this.pluginConfig[0]?.name || this.plugin.getPluginIdentifier() } // re-configured log with display name - this.log = Logger.withPrefix(this.displayName); + this.log = Logger.withPrefix(this.displayName) } /** @@ -185,86 +202,81 @@ export class ChildBridgeService { * @param config */ public addConfig(config: PlatformConfig | AccessoryConfig): void { - this.pluginConfig.push(config); + this.pluginConfig.push(config) } private get bridgeStatus(): ChildBridgeStatus { - return this.lastBridgeStatus; + return this.lastBridgeStatus } private set bridgeStatus(value: ChildBridgeStatus) { - this.lastBridgeStatus = value; - this.sendStatusUpdate(); + this.lastBridgeStatus = value + this.sendStatusUpdate() } /** * Start the child bridge process */ private startChildProcess(): void { - this.bridgeStatus = ChildBridgeStatus.PENDING; + this.bridgeStatus = ChildBridgeStatus.PENDING - this.child = child_process.fork(path.resolve(__dirname, "childBridgeFork.js"), this.args, this.processEnv); + this.child = fork(resolve(__dirname, 'childBridgeFork.js'), this.args, this.processEnv) - this.child.stdout?.on("data", (data) => { - process.stdout.write(data); - }); + this.child.stdout?.on('data', (data) => { + process.stdout.write(data) + }) - this.child.stderr?.on("data", (data) => { - process.stderr.write(data); - }); + this.child.stderr?.on('data', (data) => { + process.stderr.write(data) + }) - this.child.on("exit", () => { - this.log.warn("Child bridge process ended"); - }); + this.child.on('error', (e) => { + this.bridgeStatus = ChildBridgeStatus.DOWN + this.log.error('Child bridge process error', e) + }) - this.child.on("error", (e) => { - this.bridgeStatus = ChildBridgeStatus.DOWN; - this.log.error("Child process error", e); - }); - - this.child.once("close", (code, signal) => { - this.bridgeStatus = ChildBridgeStatus.DOWN; - this.handleProcessClose(code, signal); - }); + this.child.once('close', (code, signal) => { + this.handleProcessClose(code, signal) + }) // handle incoming ipc messages from the child process - this.child.on("message", (message: ChildProcessMessageEvent) => { - if (typeof message !== "object" || !message.id) { - return; + this.child.on('message', (message: ChildProcessMessageEvent) => { + if (typeof message !== 'object' || !message.id) { + return } - switch(message.id) { + switch (message.id) { case ChildProcessMessageEventType.READY: { - this.log(`Launched child bridge with PID ${this.child?.pid}`); - this.loadPlugin(); - break; + this.log(`Child bridge starting${this.child?.pid ? ` (pid ${this.child.pid})` : ''}...`) + this.loadPlugin() + break } case ChildProcessMessageEventType.LOADED: { - const version = (message.data as ChildProcessPluginLoadedEventData).version; + const version = (message.data as ChildProcessPluginLoadedEventData).version if (this.pluginConfig.length > 1) { - this.log(`Loaded ${this.plugin.getPluginIdentifier()} v${version} child bridge successfully with ${this.pluginConfig.length} accessories`); + this.log.success(`Child bridge started successfully with ${this.pluginConfig.length} accessories (plugin v${version}).`) } else { - this.log(`Loaded ${this.plugin.getPluginIdentifier()} v${version} child bridge successfully`); + this.log.success(`Child bridge started successfully (plugin v${version}).`) } - this.startBridge(); - break; + this.startBridge() + break } case ChildProcessMessageEventType.ONLINE: { - this.bridgeStatus = ChildBridgeStatus.OK; - break; + this.bridgeStatus = ChildBridgeStatus.OK + break } case ChildProcessMessageEventType.PORT_REQUEST: { - this.handlePortRequest(message.data as ChildProcessPortRequestEventData); - break; + this.handlePortRequest(message.data as ChildProcessPortRequestEventData) + break } case ChildProcessMessageEventType.STATUS_UPDATE: { - this.pairedStatus = (message.data as ChildBridgePairedStatusEventData).paired; - this.setupUri = (message.data as ChildBridgePairedStatusEventData).setupUri; - this.sendStatusUpdate(); - break; + this.pairedStatus = (message.data as ChildBridgePairedStatusEventData).paired + this.setupUri = (message.data as ChildBridgePairedStatusEventData).setupUri + this.sendStatusUpdate() + break } } - }); + }) } /** @@ -273,14 +285,36 @@ export class ChildBridgeService { * @param signal */ private handleProcessClose(code: number | null, signal: string | null): void { - this.log(`Process Ended. Code: ${code}, Signal: ${signal}`); - - setTimeout(() => { - if (!this.shuttingDown) { - this.log("Restarting Process..."); - this.startChildProcess(); + const isLikelyPluginCrash = code === 1 && signal === null + this.log.warn(`Child bridge ended (code ${code}, signal ${signal}).${isLikelyPluginCrash + ? ' The child bridge ended unexpectedly, which is normally due to the plugin not catching its errors properly. Please report this to the plugin developer by clicking on the' + + ' \'Report An Issue\' option in the plugin menu dropdown from the Homebridge UI. If there are related logs shown above, please include them in your report.' + : ''}`) + + if (isLikelyPluginCrash) { + if (this.restartCount < this.maxRestarts) { + this.bridgeStatus = ChildBridgeStatus.PENDING + this.restartCount += 1 + const delay = this.restartCount * 10 // first attempt after 10 seconds, second after 20 seconds, etc. + this.log(`Child bridge will automatically restart in ${delay} seconds (restart attempt ${this.restartCount} of ${this.maxRestarts}).`) + setTimeout(() => { + if (!this.shuttingDown) { + this.startChildProcess() + } + }, delay * 1000) + } else { + this.bridgeStatus = ChildBridgeStatus.DOWN + this.manuallyStopped = true + this.log.error(`Child bridge will no longer restart after failing ${this.maxRestarts + 1} times, you will need to manually start this child bridge from the Homebridge UI.`) } - }, 7000); + return + } + + if (!this.shuttingDown) { + this.bridgeStatus = ChildBridgeStatus.DOWN + this.restartCount = 0 + this.startChildProcess() + } } /** @@ -293,7 +327,7 @@ export class ChildBridgeService { this.child.send({ id: type, data, - }); + }) } } @@ -303,31 +337,31 @@ export class ChildBridgeService { */ private setProcessFlags(): void { if (this.homebridgeOptions.debugModeEnabled) { - this.args.push("-D"); + this.args.push('-D') } if (this.homebridgeOptions.forceColourLogging) { - this.args.push("-C"); + this.args.push('-C') } if (this.homebridgeOptions.insecureAccess) { - this.args.push("-I"); + this.args.push('-I') } if (this.homebridgeOptions.noLogTimestamps) { - this.args.push("-T"); + this.args.push('-T') } if (this.homebridgeOptions.keepOrphanedCachedAccessories) { - this.args.push("-K"); + this.args.push('-K') } if (this.homebridgeOptions.customStoragePath) { - this.args.push("-U", this.homebridgeOptions.customStoragePath); + this.args.push('-U', this.homebridgeOptions.customStoragePath) } if (this.homebridgeOptions.customPluginPath) { - this.args.push("-P", this.homebridgeOptions.customPluginPath); + this.args.push('-P', this.homebridgeOptions.customPluginPath) } } @@ -338,11 +372,11 @@ export class ChildBridgeService { this.processEnv = { env: { ...process.env, - DEBUG: `${process.env.DEBUG || ""} ${this.bridgeConfig.env?.DEBUG || ""}`.trim(), - NODE_OPTIONS: `${process.env.NODE_OPTIONS || ""} ${this.bridgeConfig.env?.NODE_OPTIONS || ""}`.trim(), + DEBUG: `${process.env.DEBUG || ''} ${this.bridgeConfig.env?.DEBUG || ''}`.trim(), + NODE_OPTIONS: `${process.env.NODE_OPTIONS || ''} ${this.bridgeConfig.env?.NODE_OPTIONS || ''}`.trim(), }, silent: true, - }; + } } /** @@ -361,15 +395,15 @@ export class ChildBridgeService { model: this.bridgeConfig.model || this.homebridgeConfig.bridge.model, firmwareRevision: this.bridgeConfig.firmwareRevision || this.homebridgeConfig.bridge.firmwareRevision, serialNumber: this.bridgeConfig.serialNumber || this.bridgeConfig.username, - }; + } const bridgeOptions: BridgeOptions = { cachedAccessoriesDir: User.cachedAccessoryPath(), - cachedAccessoriesItemName: "cachedAccessories." + this.bridgeConfig.username.replace(/:/g, "").toUpperCase(), - }; + cachedAccessoriesItemName: `cachedAccessories.${this.bridgeConfig.username.replace(/:/g, '').toUpperCase()}`, + } // shallow copy the homebridge options to the bridge options object - Object.assign(bridgeOptions, this.homebridgeOptions); + Object.assign(bridgeOptions, this.homebridgeOptions) this.sendMessage(ChildProcessMessageEventType.LOAD, { type: this.type, @@ -385,25 +419,25 @@ export class ChildBridgeService { accessories: [], // not used by child bridges platforms: [], // not used by child bridges }, - }); + }) } /** * Tell the child bridge to start broadcasting */ private startBridge(): void { - this.sendMessage(ChildProcessMessageEventType.START); + this.sendMessage(ChildProcessMessageEventType.START) } /** * Handle external port requests from child */ private async handlePortRequest(request: ChildProcessPortRequestEventData) { - const port = await this.externalPortService.requestPort(request.username); + const port = await this.externalPortService.requestPort(request.username) this.sendMessage(ChildProcessMessageEventType.PORT_ALLOCATED, { username: request.username, - port: port, - }); + port, + }) } /** @@ -411,8 +445,8 @@ export class ChildBridgeService { */ private teardown(): void { if (this.child && this.child.connected) { - this.bridgeStatus = ChildBridgeStatus.DOWN; - this.child.kill("SIGTERM"); + this.bridgeStatus = ChildBridgeStatus.DOWN + this.child.kill('SIGTERM') } } @@ -420,7 +454,7 @@ export class ChildBridgeService { * Trigger sending child bridge metadata to the process parent via IPC */ private sendStatusUpdate(): void { - this.ipcService.sendMessage(IpcOutgoingEvent.CHILD_BRIDGE_STATUS_UPDATE, this.getMetadata()); + this.ipcService.sendMessage(IpcOutgoingEvent.CHILD_BRIDGE_STATUS_UPDATE, this.getMetadata()) } /** @@ -428,11 +462,12 @@ export class ChildBridgeService { */ public restartChildBridge(): void { if (this.manuallyStopped) { - this.startChildBridge(); + this.restartCount = 0 + this.startChildBridge() } else { - this.log.warn("Restarting child bridge..."); - this.refreshConfig(); - this.teardown(); + this.log.warn('Child bridge restarting...') + this.refreshConfig() + this.teardown() } } @@ -441,13 +476,15 @@ export class ChildBridgeService { */ public stopChildBridge(): void { if (!this.shuttingDown) { - this.log.warn("Stopping child bridge (will not restart)..."); - this.shuttingDown = true; - this.manuallyStopped = true; - this.child?.removeAllListeners("close"); - this.teardown(); + this.log.warn('Child bridge stopping, will not restart.') + this.shuttingDown = true + this.manuallyStopped = true + this.restartCount = 0 + this.bridgeStatus = ChildBridgeStatus.DOWN + this.child?.removeAllListeners('close') + this.teardown() } else { - this.log.warn("Bridge already shutting down or stopped."); + this.log.warn('Child bridge already shutting down or stopped.') } } @@ -456,13 +493,12 @@ export class ChildBridgeService { */ public startChildBridge(): void { if (this.manuallyStopped && this.bridgeStatus === ChildBridgeStatus.DOWN && (!this.child || !this.child.connected)) { - this.log.warn("Starting child bridge..."); - this.refreshConfig(); - this.startChildProcess(); - this.shuttingDown = false; - this.manuallyStopped = false; + this.refreshConfig() + this.startChildProcess() + this.shuttingDown = false + this.manuallyStopped = false } else { - this.log.warn("Cannot start child bridge, it is still running or was not manually stopped"); + this.log.warn('Child bridge cannot be started, it is still running or was not manually stopped.') } } @@ -471,28 +507,27 @@ export class ChildBridgeService { */ public async refreshConfig(): Promise { try { - const homebridgeConfig: HomebridgeConfig = await fs.readJson(User.configPath()); + const homebridgeConfig: HomebridgeConfig = await fs.readJson(User.configPath()) if (this.type === PluginType.PLATFORM) { - const config = homebridgeConfig.platforms?.filter(x => x.platform === this.identifier && x._bridge?.username === this.bridgeConfig.username); + const config = homebridgeConfig.platforms?.filter(x => x.platform === this.identifier && x._bridge?.username === this.bridgeConfig.username) if (config.length) { - this.pluginConfig = config; - this.bridgeConfig = this.pluginConfig[0]._bridge || this.bridgeConfig; + this.pluginConfig = config + this.bridgeConfig = this.pluginConfig[0]._bridge || this.bridgeConfig } else { - this.log.warn("Platform config could not be found, using existing config."); + this.log.warn('Platform config could not be found, using existing config.') } } else if (this.type === PluginType.ACCESSORY) { - const config = homebridgeConfig.accessories?.filter(x => x.accessory === this.identifier && x._bridge?.username === this.bridgeConfig.username); + const config = homebridgeConfig.accessories?.filter(x => x.accessory === this.identifier && x._bridge?.username === this.bridgeConfig.username) if (config.length) { - this.pluginConfig = config; - this.bridgeConfig = this.pluginConfig[0]._bridge || this.bridgeConfig; + this.pluginConfig = config + this.bridgeConfig = this.pluginConfig[0]._bridge || this.bridgeConfig } else { - this.log.warn("Accessory config could not be found, using existing config."); + this.log.warn('Accessory config could not be found, using existing config.') } } - - } catch (e) { - this.log.error("Failed to refresh plugin config:", e.message); + } catch (error: any) { + this.log.error('Failed to refresh plugin config:', error.message) } } @@ -511,7 +546,6 @@ export class ChildBridgeService { identifier: this.identifier, pid: this.child?.pid, manuallyStopped: this.manuallyStopped, - }; + } } - } diff --git a/src/cli.ts b/src/cli.ts index 6b523be42..a3c9b9791 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -1,111 +1,118 @@ -import "source-map-support/register"; // registering node-source-map-support for typescript stack traces -import { Command } from "commander"; -import { HAPStorage } from "hap-nodejs"; -import { satisfies } from "semver"; -import { Logger } from "./logger"; -import { Server } from "./server"; -import { HomebridgeOptions } from "./server"; -import { User } from "./user"; -import getVersion, { getRequiredNodeVersion } from "./version"; -import Signals = NodeJS.Signals; - -const log = Logger.internal; - -const requiredNodeVersion = getRequiredNodeVersion(); +/* global NodeJS */ + +import type { HomebridgeOptions } from './server.js' + +import process from 'node:process' + +import { Command } from 'commander' +import { HAPStorage } from 'hap-nodejs' +import { satisfies } from 'semver' + +import { Logger } from './logger.js' +import { Server } from './server.js' +import { User } from './user.js' +import getVersion, { getRequiredNodeVersion } from './version.js' + +import 'source-map-support/register.js' + +import Signals = NodeJS.Signals + +const log = Logger.internal + +const requiredNodeVersion = getRequiredNodeVersion() if (requiredNodeVersion && !satisfies(process.version, requiredNodeVersion)) { - log.warn(`Homebridge requires Node.js version of ${requiredNodeVersion} which does \ -not satisfy the current Node.js version of ${process.version}. You may need to upgrade your installation of Node.js - see https://homebridge.io/w/JTKEF`); + log.warn(`Homebridge requires a Node.js version of ${requiredNodeVersion} which does \ +not satisfy the current Node.js version of ${process.version}. You may need to upgrade your installation of Node.js - see https://homebridge.io/w/JTKEF`) } -// noinspection JSUnusedGlobalSymbols -export = function cli(): void { - let insecureAccess = false; - let hideQRCode = false; - let keepOrphans = false; - let customPluginPath: string | undefined = undefined; - let strictPluginResolution = false; - let noLogTimestamps = false; - let debugModeEnabled = false; - let forceColourLogging = false; - let customStoragePath: string | undefined = undefined; - - let shuttingDown = false; - - const program = new Command(); +export default function cli(): void { + let insecureAccess = false + let hideQRCode = false + let keepOrphans = false + let customPluginPath: string | undefined + let strictPluginResolution = false + let noLogTimestamps = false + let debugModeEnabled = false + let forceColourLogging = false + let customStoragePath: string | undefined + + let shuttingDown = false + + const program = new Command() program .version(getVersion()) .allowExcessArguments() - .option("-C, --color", "force color in logging", () => forceColourLogging = true) - .option("-D, --debug", "turn on debug level logging", () => debugModeEnabled = true) - .option("-I, --insecure", "allow unauthenticated requests (for easier hacking)", () => insecureAccess = true) - .option("-P, --plugin-path [path]", "look for plugins installed at [path] as well as the default locations ([path] can also point to a single plugin)", path => customPluginPath = path) - .option("-Q, --no-qrcode", "do not issue QRcode in logging", () => hideQRCode = true) - .option("-R, --remove-orphans", "remove cached accessories for which plugin is not loaded (deprecated)", () => { - console.warn("The cli option '-R' or '--remove-orphans' is deprecated and has no effect anymore. " + - "Removing orphans is now the default behavior and can be turned off by supplying '-K' or '--keep-orphans'."); + .option('-C, --color', 'force color in logging', () => forceColourLogging = true) + .option('-D, --debug', 'turn on debug level logging', () => debugModeEnabled = true) + .option('-I, --insecure', 'allow unauthenticated requests (for easier hacking)', () => insecureAccess = true) + .option('-P, --plugin-path [path]', 'look for plugins installed at [path] as well as the default locations ([path] can also point to a single plugin)', path => customPluginPath = path) + .option('-Q, --no-qrcode', 'do not issue QRcode in logging', () => hideQRCode = true) + .option('-R, --remove-orphans', 'remove cached accessories for which plugin is not loaded (deprecated)', () => { + console.warn('The cli option \'-R\' or \'--remove-orphans\' is deprecated and has no effect anymore. ' + + 'Removing orphans is now the default behavior and can be turned off by supplying \'-K\' or \'--keep-orphans\'.') }) - .option("-K, --keep-orphans", "keep cached accessories for which the associated plugin is not loaded", () => keepOrphans = true) - .option("-T, --no-timestamp", "do not issue timestamps in logging", () => noLogTimestamps = true) - .option("-U, --user-storage-path [path]", "look for homebridge user files at [path] instead of the default location (~/.homebridge)", path => customStoragePath = path) - .option("--strict-plugin-resolution", "only load plugins from the --plugin-path if set, otherwise from the primary global node_modules", () => strictPluginResolution = true) - .parse(process.argv); + .option('-K, --keep-orphans', 'keep cached accessories for which the associated plugin is not loaded', () => keepOrphans = true) + .option('-T, --no-timestamp', 'do not issue timestamps in logging', () => noLogTimestamps = true) + .option('-U, --user-storage-path [path]', 'look for homebridge user files at [path] instead of the default location (~/.homebridge)', path => customStoragePath = path) + .option('--strict-plugin-resolution', 'only load plugins from the --plugin-path if set, otherwise from the primary global node_modules', () => strictPluginResolution = true) + .parse(process.argv) if (noLogTimestamps) { - Logger.setTimestampEnabled(false); + Logger.setTimestampEnabled(false) } if (debugModeEnabled) { - Logger.setDebugEnabled(true); + Logger.setDebugEnabled(true) } if (forceColourLogging) { - Logger.forceColor(); + Logger.forceColor() } if (customStoragePath) { - User.setStoragePath(customStoragePath); + User.setStoragePath(customStoragePath) } // Initialize HAP-NodeJS with a custom persist directory - HAPStorage.setCustomStoragePath(User.persistPath()); + HAPStorage.setCustomStoragePath(User.persistPath()) const options: HomebridgeOptions = { keepOrphanedCachedAccessories: keepOrphans, - insecureAccess: insecureAccess, - hideQRCode: hideQRCode, - customPluginPath: customPluginPath, - noLogTimestamps: noLogTimestamps, - debugModeEnabled: debugModeEnabled, - forceColourLogging: forceColourLogging, - customStoragePath: customStoragePath, - strictPluginResolution: strictPluginResolution, - }; - - const server = new Server(options); + insecureAccess, + hideQRCode, + customPluginPath, + noLogTimestamps, + debugModeEnabled, + forceColourLogging, + customStoragePath, + strictPluginResolution, + } + + const server = new Server(options) const signalHandler = (signal: Signals, signalNum: number): void => { if (shuttingDown) { - return; + return } - shuttingDown = true; + shuttingDown = true - log.info("Got %s, shutting down Homebridge...", signal); - setTimeout(() => process.exit(128 + signalNum), 5000); + log.info('Got %s, shutting down Homebridge...', signal) + setTimeout(() => process.exit(128 + signalNum), 5000) - server.teardown(); - }; - process.on("SIGINT", signalHandler.bind(undefined, "SIGINT", 2)); - process.on("SIGTERM", signalHandler.bind(undefined, "SIGTERM", 15)); + server.teardown() + } + process.on('SIGINT', signalHandler.bind(undefined, 'SIGINT', 2)) + process.on('SIGTERM', signalHandler.bind(undefined, 'SIGTERM', 15)) const errorHandler = (error: Error): void => { if (error.stack) { - log.error(error.stack); + log.error(error.stack) } if (!shuttingDown) { - process.kill(process.pid, "SIGTERM"); + process.kill(process.pid, 'SIGTERM') } - }; - process.on("uncaughtException", errorHandler); - server.start().catch(errorHandler); + } + process.on('uncaughtException', errorHandler) + server.start().catch(errorHandler) } diff --git a/src/externalPortService.ts b/src/externalPortService.ts index d17806c40..db29798b9 100644 --- a/src/externalPortService.ts +++ b/src/externalPortService.ts @@ -1,10 +1,12 @@ -import type { MacAddress } from "hap-nodejs"; -import type { ChildBridgeFork } from "./childBridgeFork"; -import { Logger } from "./logger"; +import type { MacAddress } from 'hap-nodejs' + +import type { ChildBridgeFork } from './childBridgeFork.js' + +import { Logger } from './logger.js' export interface ExternalPortsConfiguration { - start: number; - end: number; + start: number + end: number } /** @@ -12,12 +14,12 @@ export interface ExternalPortsConfiguration { * This service is used to allocate ports for external accessories on the main bridge, and child bridges. */ export class ExternalPortService { - private nextExternalPort?: number; - private allocatedPorts: Map = new Map(); + private nextExternalPort?: number + private allocatedPorts: Map = new Map() constructor( private externalPorts?: ExternalPortsConfiguration, - ) { } + ) {} /** * Returns the next available port in the external port config. @@ -26,36 +28,36 @@ export class ExternalPortService { */ public async requestPort(username: MacAddress): Promise { // check to see if this device has already requested an external port - const existingPortAllocation = this.allocatedPorts.get(username); + const existingPortAllocation = this.allocatedPorts.get(username) if (existingPortAllocation) { - return existingPortAllocation; + return existingPortAllocation } // get the next unused port - const port = this.getNextFreePort(); - this.allocatedPorts.set(username, port); - return port; + const port = this.getNextFreePort() + this.allocatedPorts.set(username, port) + return port } - private getNextFreePort(): number | undefined { + private getNextFreePort(): number | undefined { if (!this.externalPorts) { - return undefined; + return undefined } if (this.nextExternalPort === undefined) { - this.nextExternalPort = this.externalPorts.start; - return this.nextExternalPort; + this.nextExternalPort = this.externalPorts.start + return this.nextExternalPort } - this.nextExternalPort++; + this.nextExternalPort++ if (this.nextExternalPort <= this.externalPorts.end) { - return this.nextExternalPort; + return this.nextExternalPort } - Logger.internal.warn("External port pool ran out of ports. Falling back to random port assignment."); + Logger.internal.warn('External port pool ran out of ports. Falling back to random port assignment.') - return undefined; + return undefined } } @@ -67,10 +69,10 @@ export class ChildBridgeExternalPortService extends ExternalPortService { constructor( private childBridge: ChildBridgeFork, ) { - super(); + super() } public async requestPort(username: MacAddress): Promise { - return await this.childBridge.requestExternalPort(username); + return await this.childBridge.requestExternalPort(username) } } diff --git a/src/index.ts b/src/index.ts index 97995ba10..bf830d5a4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,101 +1,81 @@ /** * Export HAP */ -import type { API } from "./api"; +import type { API } from './api.js' // noinspection JSUnusedGlobalSymbols -export type HAP = API["hap"]; - -/** - * Export API const enums - */ -export { - APIEvent, - PluginType, -} from "./api"; +export type HAP = API['hap'] /** * Export types for basically everything but the actual API implementation */ export type { - PluginIdentifier, - PluginName, - ScopedPluginName, - AccessoryName, - PlatformName, - AccessoryIdentifier, - PlatformIdentifier, - - PluginInitializer, - AccessoryPluginConstructor, + AccessoryName, AccessoryPlugin, - PlatformPluginConstructor, + AccessoryPluginConstructor, + API, DynamicPlatformPlugin, - StaticPlatformPlugin, IndependentPlatformPlugin, - - API, -} from "./api"; + PlatformIdentifier, + PlatformName, + PlatformPluginConstructor, + PluginIdentifier, + PluginInitializer, + PluginName, + ScopedPluginName, + StaticPlatformPlugin, +} from './api.js' /** - * Export Platform Accessory const enums + * Export API const enums */ -export { - PlatformAccessoryEvent, -} from "./platformAccessory"; +export { APIEvent, PluginType } from './api.js' /** - * Export Platform Accessory Types + * Export bridge types */ export type { - PlatformAccessory, - UnknownContext, -} from "./platformAccessory"; + AccessoryConfig, + BridgeConfiguration, + HomebridgeConfig, + PlatformConfig, +} from './bridgeService.js' /** - * Export server types + * Export port types */ -export type { - HomebridgeOptions, -} from "./server"; +export type { ExternalPortsConfiguration } from './externalPortService.js' /** - * Export bridge types + * Export Logger const enums */ -export type { - HomebridgeConfig, - BridgeConfiguration, - AccessoryConfig, - PlatformConfig, -} from "./bridgeService"; +export { LogLevel } from './logger.js' /** - * Export port types + * Export Logger types */ -export type { - ExternalPortsConfiguration, -} from "./externalPortService"; +export type { Logger, Logging } from './logger.js' /** - * Export User Types + * Export Platform Accessory const enums */ -export type { User } from "./user"; +export { PlatformAccessoryEvent } from './platformAccessory.js' /** - * Export Logger const enums + * Export Platform Accessory Types */ -export { - LogLevel, -} from "./logger"; +export type { PlatformAccessory, UnknownContext } from './platformAccessory.js' /** - * Export Logger types + * Export server types */ -export type { - Logger, - Logging, -} from "./logger"; +export type { HomebridgeOptions } from './server.js' + +/** + * Export User Types + */ +export type { User } from './user.js' /** * Export the CONST ENUMS from hap-nodejs @@ -141,22 +121,20 @@ export { Protocols, RemoteControllerEvents, ResourceRequestReason, - SRTPCryptoSuites, ServiceEventTypes, SiriAudioSessionEvents, + SRTPCryptoSuites, StreamRequestTypes, TargetCategory, TargetUpdates, Topics, Units, -} from "hap-nodejs"; +} from 'hap-nodejs' /** * Export HAP-NodeJS namespaces as type only */ -export type { - DataStreamParser, -} from "hap-nodejs"; +export type { DataStreamParser } from 'hap-nodejs' /** * Export HAP-NodeJS classes as type only @@ -174,15 +152,15 @@ export type { DataStreamWriter, DoorbellController, HAPServer, - HAPStorage, HapStatusError, + HAPStorage, HDSProtocolError, RecordingManagement, RemoteController, RTPStreamManagement, Service, SiriAudioSession, -} from "hap-nodejs"; +} from 'hap-nodejs' /** * Export HAP-NodeJS interfaces as type only @@ -219,16 +197,16 @@ export type { SiriAudioStreamProducerConstructor, SourceResponse, VideoRecordingOptions, -} from "hap-nodejs"; +} from 'hap-nodejs' /** * Export HAP-NodeJS type aliases as type only */ -export type { +export type { AccessoriesCallback, AccessoryCharacteristicChange, - AddPairingCallback, AdditionalAuthorizationHandler, + AddPairingCallback, AudioCodecConfiguration, AudioCodecParameters, AudioFrame, @@ -255,12 +233,12 @@ export type { GlobalRequestHandler, HAPHttpError, HAPPincode, - IPAddress, - IPv4Address, - IPv6Address, IdentificationCallback, IdentifyCallback, InterfaceName, + IPAddress, + IPv4Address, + IPv6Address, ListPairingsCallback, MacAddress, NodeCallback, @@ -268,20 +246,20 @@ export type { PairCallback, PairingsCallback, PartialAllowingNull, + PreparedDataStreamSession, PrepareStreamCallback, PrepareStreamRequest, PrepareStreamResponse, - PreparedDataStreamSession, PrimitiveTypes, - RTPTime, ReadCharacteristicsCallback, - ReconfigureStreamRequest, ReconfiguredVideoInfo, + ReconfigureStreamRequest, RemovePairingCallback, RequestHandler, Resolution, ResourceRequestCallback, ResponseHandler, + RTPTime, SerializedServiceMap, ServiceCharacteristicChange, ServiceId, @@ -292,27 +270,24 @@ export type { StartStreamRequest, StateChangeDelegate, StopStreamRequest, + StreamingRequest, StreamRequestCallback, StreamSessionIdentifier, - StreamingRequest, SupportedButtonConfiguration, SupportedConfiguration, - TLVEncodable, TargetConfiguration, + TLVEncodable, VideoInfo, VideoStreamingOptions, VoidCallback, WithUUID, WriteCharacteristicsCallback, -} from "hap-nodejs"; +} from 'hap-nodejs' /** * Export HAP-NodeJS variables as type only */ -export type { - LegacyTypes, - uuid, -} from "hap-nodejs"; +export type { LegacyTypes, uuid } from 'hap-nodejs' /** * Export HAP-NodeJS functions as type only @@ -326,4 +301,4 @@ export type { epochMillisFromMillisSince2001_01_01, epochMillisFromMillisSince2001_01_01Buffer, once, -} from "hap-nodejs"; +} from 'hap-nodejs' diff --git a/src/ipcService.ts b/src/ipcService.ts index 99bc64f73..0a502bcf6 100644 --- a/src/ipcService.ts +++ b/src/ipcService.ts @@ -1,28 +1,30 @@ -import { EventEmitter } from "events"; +import { EventEmitter } from 'node:events' +import process from 'node:process' +// eslint-disable-next-line no-restricted-syntax export const enum IpcIncomingEvent { - RESTART_CHILD_BRIDGE = "restartChildBridge", - STOP_CHILD_BRIDGE = "stopChildBridge", - START_CHILD_BRIDGE = "startChildBridge", - CHILD_BRIDGE_METADATA_REQUEST = "childBridgeMetadataRequest", + RESTART_CHILD_BRIDGE = 'restartChildBridge', + STOP_CHILD_BRIDGE = 'stopChildBridge', + START_CHILD_BRIDGE = 'startChildBridge', + CHILD_BRIDGE_METADATA_REQUEST = 'childBridgeMetadataRequest', } +// eslint-disable-next-line no-restricted-syntax export const enum IpcOutgoingEvent { - SERVER_STATUS_UPDATE = "serverStatusUpdate", - CHILD_BRIDGE_METADATA_RESPONSE = "childBridgeMetadataResponse", - CHILD_BRIDGE_STATUS_UPDATE = "childBridgeStatusUpdate", + SERVER_STATUS_UPDATE = 'serverStatusUpdate', + CHILD_BRIDGE_METADATA_RESPONSE = 'childBridgeMetadataResponse', + CHILD_BRIDGE_STATUS_UPDATE = 'childBridgeStatusUpdate', } +// eslint-disable-next-line ts/no-unsafe-declaration-merging export declare interface IpcService { - on(event: IpcIncomingEvent.RESTART_CHILD_BRIDGE, listener: (childBridgeUsername: string) => void): this; - on(event: IpcIncomingEvent.STOP_CHILD_BRIDGE, listener: (childBridgeUsername: string) => void): this; - on(event: IpcIncomingEvent.START_CHILD_BRIDGE, listener: (childBridgeUsername: string) => void): this; - on(event: IpcIncomingEvent.CHILD_BRIDGE_METADATA_REQUEST, listener: () => void): this; + on: ((event: IpcIncomingEvent.RESTART_CHILD_BRIDGE, listener: (childBridgeUsername: string) => void) => this) & ((event: IpcIncomingEvent.STOP_CHILD_BRIDGE, listener: (childBridgeUsername: string) => void) => this) & ((event: IpcIncomingEvent.START_CHILD_BRIDGE, listener: (childBridgeUsername: string) => void) => this) & ((event: IpcIncomingEvent.CHILD_BRIDGE_METADATA_REQUEST, listener: () => void) => this) } +// eslint-disable-next-line ts/no-unsafe-declaration-merging export class IpcService extends EventEmitter { constructor() { - super(); + super() } /** @@ -30,12 +32,12 @@ export class IpcService extends EventEmitter { * Currently this will only listen for messages from a parent process. */ public start(): void { - process.on("message", (message: { id: string, data: never }) => { - if (!message || typeof message !== "object" || !message.id) { - return; + process.on('message', (message: { id: string, data: never }) => { + if (!message || typeof message !== 'object' || !message.id) { + return } - this.emit(message.id, message.data); - }); + this.emit(message.id, message.data) + }) } /** @@ -48,8 +50,7 @@ export class IpcService extends EventEmitter { process.send({ id, data, - }); + }) } } - } diff --git a/src/logger.spec.ts b/src/logger.spec.ts index 63137cd8e..e7486aee6 100644 --- a/src/logger.spec.ts +++ b/src/logger.spec.ts @@ -1,110 +1,114 @@ -import chalk from "chalk"; -import { Logger } from "./logger"; +import type { MockInstance } from 'vitest' -describe("Logger", () => { - let consoleLogSpy: jest.SpyInstance; - let consoleErrorSpy: jest.SpyInstance; +import chalk from 'chalk' +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' + +import { Logger } from './logger.js' + +describe('logger', () => { + let consoleLogSpy: MockInstance + let consoleErrorSpy: MockInstance beforeEach(() => { - consoleLogSpy = jest.spyOn(console, "log").mockImplementation(); - consoleErrorSpy = jest.spyOn(console, "error").mockImplementation(); - }); + consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {}) + consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) + }) afterEach(() => { - consoleLogSpy.mockRestore(); - consoleErrorSpy.mockRestore(); - }); - - it("should create a new logger with a prefix", () => { - const logger = Logger.withPrefix("test"); - expect(logger.prefix).toBe("test"); - }); - - it("should log info level messages", () => { - const logger = Logger.withPrefix("test"); - logger.info("test message"); - expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining("test message")); - }); - - it("should log success level messages", () => { - const logger = Logger.withPrefix("test"); - logger.success("test message"); - expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining("test message")); - }); - - it("should log warn level messages", () => { - const logger = Logger.withPrefix("test"); - logger.warn("test message"); - expect(consoleErrorSpy).toHaveBeenCalledWith(expect.stringContaining("test message")); - }); - - it("should log error level messages", () => { - const logger = Logger.withPrefix("test"); - logger.error("test message"); - expect(consoleErrorSpy).toHaveBeenCalledWith(expect.stringContaining("test message")); - }); - - it("should not log debug level messages when debug is disabled (via method)", () => { - const logger = Logger.withPrefix("test"); - logger.debug("test message"); - expect(consoleLogSpy).not.toHaveBeenCalled(); - }); - - it("should log debug level messages when debug is enabled (via method, no param)", () => { - Logger.setDebugEnabled(); - const logger = Logger.withPrefix("test"); - logger.debug("test message"); - expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining("test message")); - Logger.setDebugEnabled(false); // reset debug setting - }); - - it("should log debug level messages when debug is enabled (via method, with param)", () => { - Logger.setDebugEnabled(true); - const logger = Logger.withPrefix("test"); - logger.debug("test message"); - expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining("test message")); - Logger.setDebugEnabled(false); // reset debug setting - }); - - it("should not include timestamps in log messages when timestamp is disabled (via method)", () => { - Logger.setTimestampEnabled(false); - const logger = Logger.withPrefix("test"); - logger.info("test message"); - expect(consoleLogSpy).not.toHaveBeenCalledWith(expect.stringMatching(/\[\d{1,2}\/\d{1,2}\/\d{4}, \d{1,2}:\d{2}:\d{2} (AM|PM)].*/)); - }); - - it("should include timestamps in log messages when timestamp is enabled (via method, no param)", () => { - Logger.setTimestampEnabled(); - const logger = Logger.withPrefix("test"); - logger.info("test message"); - expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringMatching(/\[\d{1,2}\/\d{1,2}\/\d{4}, \d{1,2}:\d{2}:\d{2} (AM|PM)].*/)); - Logger.setTimestampEnabled(false); // reset timestamp setting - }); - - it("should include timestamps in log messages when timestamp is enabled (via method, with param)", () => { - Logger.setTimestampEnabled(true); - const logger = Logger.withPrefix("test"); - logger.info("test message"); - expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringMatching(/\[\d{1,2}\/\d{1,2}\/\d{4}, \d{1,2}:\d{2}:\d{2} (AM|PM)].*/)); - Logger.setTimestampEnabled(false); // reset timestamp setting - }); - - it("should set chalk level to 1 when forceColor is enabled (via method)", () => { - Logger.forceColor(); - expect(chalk.level).toBe(1); - }); - - it("should return the same logger when called with the same prefix", () => { - const logger1 = Logger.withPrefix("test"); - const logger2 = Logger.withPrefix("test"); - expect(logger1).toBe(logger2); - }); - - it("should create different loggers for different prefixes", () => { - const logger1 = Logger.withPrefix("test1"); - const logger2 = Logger.withPrefix("test2"); - expect(logger1).not.toBe(logger2); - expect(logger1.prefix).toBe("test1"); - expect(logger2.prefix).toBe("test2"); - }); -}); + consoleLogSpy.mockRestore() + consoleErrorSpy.mockRestore() + }) + + it('should create a new logger with a prefix', () => { + const logger = Logger.withPrefix('test') + expect(logger.prefix).toBe('test') + }) + + it('should log info level messages', () => { + const logger = Logger.withPrefix('test') + logger.info('test message') + expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('test message')) + }) + + it('should log success level messages', () => { + const logger = Logger.withPrefix('test') + logger.success('test message') + expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('test message')) + }) + + it('should log warn level messages', () => { + const logger = Logger.withPrefix('test') + logger.warn('test message') + expect(consoleErrorSpy).toHaveBeenCalledWith(expect.stringContaining('test message')) + }) + + it('should log error level messages', () => { + const logger = Logger.withPrefix('test') + logger.error('test message') + expect(consoleErrorSpy).toHaveBeenCalledWith(expect.stringContaining('test message')) + }) + + it('should not log debug level messages when debug is disabled (via method)', () => { + const logger = Logger.withPrefix('test') + logger.debug('test message') + expect(consoleLogSpy).not.toHaveBeenCalled() + }) + + it('should log debug level messages when debug is enabled (via method, no param)', () => { + Logger.setDebugEnabled() + const logger = Logger.withPrefix('test') + logger.debug('test message') + expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('test message')) + Logger.setDebugEnabled(false) // reset debug setting + }) + + it('should log debug level messages when debug is enabled (via method, with param)', () => { + Logger.setDebugEnabled(true) + const logger = Logger.withPrefix('test') + logger.debug('test message') + expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('test message')) + Logger.setDebugEnabled(false) // reset debug setting + }) + + it('should not include timestamps in log messages when timestamp is disabled (via method)', () => { + Logger.setTimestampEnabled(false) + const logger = Logger.withPrefix('test') + logger.info('test message') + expect(consoleLogSpy).not.toHaveBeenCalledWith(expect.stringMatching(/\[\d{1,2}\/\d{1,2}\/\d{4}, \d{1,2}:\d{2}:\d{2} (AM|PM)\].*/)) + }) + + it('should include timestamps in log messages when timestamp is enabled (via method, no param)', () => { + Logger.setTimestampEnabled() + const logger = Logger.withPrefix('test') + logger.info('test message') + expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringMatching(/\[\d{1,2}\/\d{1,2}\/\d{4}, \d{1,2}:\d{2}:\d{2} (AM|PM)\].*/)) + Logger.setTimestampEnabled(false) // reset timestamp setting + }) + + it('should include timestamps in log messages when timestamp is enabled (via method, with param)', () => { + Logger.setTimestampEnabled(true) + const logger = Logger.withPrefix('test') + logger.info('test message') + expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringMatching(/\[\d{1,2}\/\d{1,2}\/\d{4}, \d{1,2}:\d{2}:\d{2} (AM|PM)\].*/)) + Logger.setTimestampEnabled(false) // reset timestamp setting + }) + + it('should set chalk level to 1 when forceColor is enabled (via method)', () => { + Logger.forceColor() + expect(chalk.level).toBe(1) + }) + + it('should return the same logger when called with the same prefix', () => { + const logger1 = Logger.withPrefix('test') + const logger2 = Logger.withPrefix('test') + expect(logger1).toBe(logger2) + }) + + it('should create different loggers for different prefixes', () => { + const logger1 = Logger.withPrefix('test1') + const logger2 = Logger.withPrefix('test2') + expect(logger1).not.toBe(logger2) + expect(logger1.prefix).toBe('test1') + expect(logger2.prefix).toBe('test2') + }) +}) diff --git a/src/logger.ts b/src/logger.ts index fc61cc5bb..018c83f46 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -1,6 +1,6 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import util from "util"; -import chalk from "chalk"; +import util from 'node:util' + +import chalk from 'chalk' /** * Log levels to indicate importance of the logged message. @@ -14,12 +14,13 @@ import chalk from "chalk"; * * Messages with DEBUG level are only displayed if explicitly enabled. */ +// eslint-disable-next-line no-restricted-syntax export const enum LogLevel { - INFO = "info", - SUCCESS = "success", - WARN = "warn", - ERROR = "error", - DEBUG = "debug", + INFO = 'info', + SUCCESS = 'success', + WARN = 'warn', + ERROR = 'error', + DEBUG = 'debug', } /** @@ -27,82 +28,69 @@ export const enum LogLevel { * but also has dedicated logging functions for respective logging levels. */ export interface Logging { - - prefix: string; - - (message: string, ...parameters: any[]): void; - - info(message: string, ...parameters: any[]): void; - success(message: string, ...parameters: any[]): void; - warn(message: string, ...parameters: any[]): void; - error(message: string, ...parameters: any[]): void; - debug(message: string, ...parameters: any[]): void; - log(level: LogLevel, message: string, ...parameters: any[]): void; - + prefix: string + (message: string, ...parameters: any[]): void + info: (message: string, ...parameters: any[]) => void + success: (message: string, ...parameters: any[]) => void + warn: (message: string, ...parameters: any[]) => void + error: (message: string, ...parameters: any[]) => void + debug: (message: string, ...parameters: any[]) => void + log: (level: LogLevel, message: string, ...parameters: any[]) => void } interface IntermediateLogging { // some auxiliary interface used to correctly type stuff happening in "withPrefix" - - prefix?: string; - - (message: string, ...parameters: any[]): void; - - info?(message: string, ...parameters: any[]): void; - success?(message: string, ...parameters: any[]): void; - warn?(message: string, ...parameters: any[]): void; - error?(message: string, ...parameters: any[]): void; - debug?(message: string, ...parameters: any[]): void; - log?(level: LogLevel, message: string, ...parameters: any[]): void; - + prefix?: string + (message: string, ...parameters: any[]): void + info?: (message: string, ...parameters: any[]) => void + success?: (message: string, ...parameters: any[]) => void + warn?: (message: string, ...parameters: any[]) => void + error?: (message: string, ...parameters: any[]) => void + debug?: (message: string, ...parameters: any[]) => void + log?: (level: LogLevel, message: string, ...parameters: any[]) => void } /** * Logger class */ export class Logger { + public static readonly internal = new Logger() + private static readonly loggerCache = new Map() // global cache of logger instances by plugin name + private static debugEnabled = false + private static timestampEnabled = true - public static readonly internal = new Logger(); - - private static readonly loggerCache = new Map(); // global cache of logger instances by plugin name - private static debugEnabled = false; - private static timestampEnabled = true; - - readonly prefix?: string; + readonly prefix?: string constructor(prefix?: string) { - this.prefix = prefix; + this.prefix = prefix } - /** * Creates a new Logging device with a specified prefix. * * @param prefix {string} - the prefix of the logger */ static withPrefix(prefix: string): Logging { - const loggerStuff = Logger.loggerCache.get(prefix); + const loggerStuff = Logger.loggerCache.get(prefix) if (loggerStuff) { - return loggerStuff; + return loggerStuff } else { - const logger = new Logger(prefix); - - const log: IntermediateLogging = logger.info.bind(logger); - log.info = logger.info; - log.success = logger.success; - log.warn = logger.warn; - log.error = logger.error; - log.debug = logger.debug; - log.log = logger.log; - - log.prefix = logger.prefix; - - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - const logging: Logging = log; // I aimed to not use ts-ignore in this project, but this evil "thing" above is hell - Logger.loggerCache.set(prefix, logging); - return logging; + const logger = new Logger(prefix) + + const log: IntermediateLogging = logger.info.bind(logger) + log.info = logger.info + log.success = logger.success + log.warn = logger.warn + log.error = logger.error + log.debug = logger.debug + log.log = logger.log + + log.prefix = logger.prefix + + // @ts-expect-error: I aimed to not use ts-ignore in this project, but this evil "thing" above is hell + const logging: Logging = log + Logger.loggerCache.set(prefix, logging) + return logging } } @@ -112,7 +100,7 @@ export class Logger { * @param enabled {boolean} */ public static setDebugEnabled(enabled: boolean = true): void { - Logger.debugEnabled = enabled; + Logger.debugEnabled = enabled } /** @@ -121,74 +109,72 @@ export class Logger { * @param enabled {boolean} */ public static setTimestampEnabled(enabled: boolean = true): void { - Logger.timestampEnabled = enabled; + Logger.timestampEnabled = enabled } /** * Forces color in logging output, even if it seems like color is unsupported. */ public static forceColor(): void { - chalk.level = 1; // `1` - Basic 16 colors support. + chalk.level = 1 // `1` - Basic 16 colors support. } - public info(message: string, ...parameters: any[]): void { - this.log(LogLevel.INFO, message, ...parameters); + this.log(LogLevel.INFO, message, ...parameters) } public success(message: string, ...parameters: any[]): void { - this.log(LogLevel.SUCCESS, message, ...parameters); + this.log(LogLevel.SUCCESS, message, ...parameters) } public warn(message: string, ...parameters: any[]): void { - this.log(LogLevel.WARN, message, ...parameters); + this.log(LogLevel.WARN, message, ...parameters) } public error(message: string, ...parameters: any[]): void { - this.log(LogLevel.ERROR, message, ...parameters); + this.log(LogLevel.ERROR, message, ...parameters) } public debug(message: string, ...parameters: any[]): void { - this.log(LogLevel.DEBUG, message, ...parameters); + this.log(LogLevel.DEBUG, message, ...parameters) } public log(level: LogLevel, message: string, ...parameters: any[]): void { if (level === LogLevel.DEBUG && !Logger.debugEnabled) { - return; + return } - message = util.format(message, ...parameters); + message = util.format(message, ...parameters) - let loggingFunction = console.log; + let loggingFunction = console.log // eslint-disable-line no-console switch (level) { case LogLevel.SUCCESS: - message = chalk.green(message); - break; + message = chalk.green(message) + break case LogLevel.WARN: - message = chalk.yellow(message); - loggingFunction = console.error; - break; + message = chalk.yellow(message) + loggingFunction = console.error + break case LogLevel.ERROR: - message = chalk.red(message); - loggingFunction = console.error; - break; + message = chalk.red(message) + loggingFunction = console.error + break case LogLevel.DEBUG: - message = chalk.gray(message); - break; + message = chalk.gray(message) + break } if (this.prefix) { - message = getLogPrefix(this.prefix) + " " + message; + message = `${getLogPrefix(this.prefix)} ${message}` } if (Logger.timestampEnabled) { - const date = new Date(); - message = chalk.white(`[${date.toLocaleString()}] `) + message; + const date = new Date() + message = chalk.white(`[${date.toLocaleString()}] `) + message } - loggingFunction(message); + loggingFunction(message) } - } /** @@ -196,5 +182,5 @@ export class Logger { * @param prefix */ export function getLogPrefix(prefix: string): string { - return chalk.cyan(`[${prefix}]`); + return chalk.cyan(`[${prefix}]`) } diff --git a/src/platformAccessory.spec.ts b/src/platformAccessory.spec.ts index 4d7abbace..7901cc8ac 100644 --- a/src/platformAccessory.spec.ts +++ b/src/platformAccessory.spec.ts @@ -1,159 +1,158 @@ +import type { SerializedPlatformAccessory } from './platformAccessory.js' + import { - Service, - Categories, Accessory, + Categories, RemoteController, + Service, uuid, -} from "hap-nodejs"; -import { PlatformAccessory, SerializedPlatformAccessory } from "./platformAccessory"; - -function createAccessory(name = "TestAccessory", category?: Categories): PlatformAccessory { - const accessoryUUID = uuid.generate("test.uuid." + name); - const accessory = new PlatformAccessory(name, accessoryUUID, category); - accessory._associatedPlatform = "TestPlatform"; - accessory._associatedPlugin = "TestPlugin"; +} from 'hap-nodejs' +import { describe, expect, it, vi } from 'vitest' + +import { PlatformAccessory } from './platformAccessory.js' + +function createAccessory(name = 'TestAccessory', category?: Categories): PlatformAccessory { + const accessoryUUID = uuid.generate(`test.uuid.${name}`) + const accessory = new PlatformAccessory(name, accessoryUUID, category) + accessory._associatedPlatform = 'TestPlatform' + accessory._associatedPlugin = 'TestPlugin' accessory.context = { - "test": "context", - "doing": 234, - }; - return accessory; + test: 'context', + doing: 234, + } + return accessory } -describe("PlatformAccessory", () => { - - describe("properties", () => { - - it("should mirror displayName correctly", function() { - const accessory = createAccessory("TestName"); - expect(accessory._associatedHAPAccessory.displayName).toBe(accessory.displayName); - expect(accessory.displayName).toBe("TestName"); - }); - - it("should mirror UUID correctly", function() { - const accessory = createAccessory("TestName"); - expect(accessory._associatedHAPAccessory.UUID).toBe(accessory.UUID); - expect(accessory.UUID).toBe(uuid.generate("test.uuid.TestName")); - }); - - it("should mirror category correctly", function() { - const accessory = createAccessory("TestName", Categories.APPLE_TV); - expect(accessory._associatedHAPAccessory.category).toBe(accessory.category); - expect(accessory.category).toBe(Categories.APPLE_TV); - }); - - it("should mirror services correctly", function() { - const accessory = createAccessory("TestName"); - expect(accessory._associatedHAPAccessory.services).toStrictEqual(accessory.services); - expect(accessory.services.length).toBe(1); - }); - - }); - - describe("PlatformAccessory.prototype.updateDisplayName",() => { - it("should mirror displayName correctly", function() { - const accessory = createAccessory("TestName"); - accessory.updateDisplayName("NewTestName"); - expect(accessory._associatedHAPAccessory.displayName).toBe(accessory.displayName); - expect(accessory.displayName).toBe("NewTestName"); - }); - }); - - describe("PlatformAccessory.prototype.addService", () => { - it("should forward add service", function() { - const accessory = createAccessory(); - const service = new Service.Switch(); - const spy = jest.spyOn(accessory._associatedHAPAccessory, "addService"); - - expect(accessory.services.length).toBe(1); // AccessoryInformation service - expect(accessory.services.includes(service)).toBeFalsy(); - - accessory.addService(service); - - expect(accessory.services.length).toBe(2); // ensure our reference is valid - expect(accessory.services.includes(service)).toBeTruthy(); - - expect(spy).toHaveBeenCalledWith(service); // ensure HAP got called - }); - }); - - describe("PlatformAccessory.prototype.removeService", () => { - it("should forward remove service", function() { - const accessory = createAccessory(); - const service = new Service.Switch(); - const spy = jest.spyOn(accessory._associatedHAPAccessory, "removeService"); - - accessory.removeService(service); - expect(spy).toHaveBeenCalledWith(service); - }); - }); - - describe("PlatformAccessory.prototype.getService", () => { - it("should retrieve AccessoryInformation service", function() { - const accessory = createAccessory(); - const requested = Service.AccessoryInformation; - const spy = jest.spyOn(accessory._associatedHAPAccessory, "getService"); - - const service = accessory.getService(requested); - expect(spy).toHaveBeenCalledWith(requested); - expect(service).toBeDefined(); - expect(service!.UUID).toBe(requested.UUID); - }); - }); - - describe("PlatformAccessory.prototype.getServiceById", () => { - it("should forward service retrieval by id", function() { - const accessory = createAccessory(); - const spy = jest.spyOn(accessory._associatedHAPAccessory, "getServiceById"); - - const result = accessory.getServiceById(Service.Switch, "customSubType"); - expect(result).toBeUndefined(); - expect(spy).toHaveBeenCalledWith(Service.Switch, "customSubType"); - }); - }); - - describe("PlatformAccessory.prototype.configureController", () => { - it("should forward configureController correctly", function() { - const accessory = createAccessory(); - const spy = jest.spyOn(accessory._associatedHAPAccessory, "configureController").mockImplementationOnce(() => { +describe('platformAccessory', () => { + describe('properties', () => { + it('should mirror displayName correctly', () => { + const accessory = createAccessory('TestName') + expect(accessory._associatedHAPAccessory.displayName).toBe(accessory.displayName) + expect(accessory.displayName).toBe('TestName') + }) + + it('should mirror UUID correctly', () => { + const accessory = createAccessory('TestName') + expect(accessory._associatedHAPAccessory.UUID).toBe(accessory.UUID) + expect(accessory.UUID).toBe(uuid.generate('test.uuid.TestName')) + }) + + it('should mirror category correctly', () => { + const accessory = createAccessory('TestName', Categories.APPLE_TV) + expect(accessory._associatedHAPAccessory.category).toBe(accessory.category) + expect(accessory.category).toBe(Categories.APPLE_TV) + }) + + it('should mirror services correctly', () => { + const accessory = createAccessory('TestName') + expect(accessory._associatedHAPAccessory.services).toStrictEqual(accessory.services) + expect(accessory.services.length).toBe(1) + }) + }) + + describe('platformAccessory.prototype.updateDisplayName', () => { + it('should mirror displayName correctly', () => { + const accessory = createAccessory('TestName') + accessory.updateDisplayName('NewTestName') + expect(accessory._associatedHAPAccessory.displayName).toBe(accessory.displayName) + expect(accessory.displayName).toBe('NewTestName') + }) + }) + + describe('platformAccessory.prototype.addService', () => { + it('should forward add service', () => { + const accessory = createAccessory() + const service = new Service.Switch() + const spy = vi.spyOn(accessory._associatedHAPAccessory, 'addService') + + expect(accessory.services.length).toBe(1) // AccessoryInformation service + expect(accessory.services.includes(service)).toBeFalsy() + + accessory.addService(service) + expect(accessory.services.length).toBe(2) // ensure our reference is valid + expect(accessory.services.includes(service)).toBeTruthy() + + expect(spy).toHaveBeenCalledWith(service) // ensure HAP got called + }) + }) + + describe('platformAccessory.prototype.removeService', () => { + it('should forward remove service', () => { + const accessory = createAccessory() + const service = new Service.Switch() + const spy = vi.spyOn(accessory._associatedHAPAccessory, 'removeService') + + accessory.removeService(service) + expect(spy).toHaveBeenCalledWith(service) + }) + }) + + describe('platformAccessory.prototype.getService', () => { + it('should retrieve AccessoryInformation service', () => { + const accessory = createAccessory() + const requested = Service.AccessoryInformation + const spy = vi.spyOn(accessory._associatedHAPAccessory, 'getService') + + const service = accessory.getService(requested) + expect(spy).toHaveBeenCalledWith(requested) + expect(service).toBeDefined() + expect(service!.UUID).toBe(requested.UUID) + }) + }) + + describe('platformAccessory.prototype.getServiceById', () => { + it('should forward service retrieval by id', () => { + const accessory = createAccessory() + const spy = vi.spyOn(accessory._associatedHAPAccessory, 'getServiceById') + + const result = accessory.getServiceById(Service.Switch, 'customSubType') + expect(result).toBeUndefined() + expect(spy).toHaveBeenCalledWith(Service.Switch, 'customSubType') + }) + }) + + describe('platformAccessory.prototype.configureController', () => { + it('should forward configureController correctly', () => { + const accessory = createAccessory() + const spy = vi.spyOn(accessory._associatedHAPAccessory, 'configureController').mockImplementationOnce(() => { // do nothing - }); - - const controller = new RemoteController(); - accessory.configureController(controller); - expect(spy).toHaveBeenCalledWith(controller); - }); - }); - - describe("PlatformAccessory.serialize", () => { - it("should serialize accessory correctly", function() { - const accessory = createAccessory(); - accessory.addService(Service.Lightbulb); - const spy = jest.spyOn(Accessory, "serialize"); - - const json: SerializedPlatformAccessory = PlatformAccessory.serialize(accessory); - - expect(json.platform).toBe(accessory._associatedPlatform); - expect(json.plugin).toBe(accessory._associatedPlugin); - expect(json.context).toStrictEqual(accessory.context); - expect(spy).toHaveBeenCalledWith(accessory._associatedHAPAccessory); - }); - }); - - describe("PlatformAccessory.deserialize", () => { - it("should deserialize serialized accessory correctly", function() { - const accessory = createAccessory(); - accessory.addService(Service.Lightbulb); - - const json = PlatformAccessory.serialize(accessory); - const reconstructed = PlatformAccessory.deserialize(json); - - expect(reconstructed._associatedPlugin).toBe(accessory._associatedPlugin); - expect(reconstructed._associatedPlatform).toBe(accessory._associatedPlatform); - expect(reconstructed.displayName).toBe(accessory.displayName); - expect(reconstructed.UUID).toBe(accessory.UUID); - expect(reconstructed.category).toBe(accessory.category); - expect(reconstructed.context).toBe(accessory.context); - }); - }); - -}); + }) + + const controller = new RemoteController() + accessory.configureController(controller) + expect(spy).toHaveBeenCalledWith(controller) + }) + }) + + describe('platformAccessory.serialize', () => { + it('should serialize accessory correctly', () => { + const accessory = createAccessory() + accessory.addService(Service.Lightbulb) + const spy = vi.spyOn(Accessory, 'serialize') + + const json: SerializedPlatformAccessory = PlatformAccessory.serialize(accessory) + + expect(json.platform).toBe(accessory._associatedPlatform) + expect(json.plugin).toBe(accessory._associatedPlugin) + expect(json.context).toStrictEqual(accessory.context) + expect(spy).toHaveBeenCalledWith(accessory._associatedHAPAccessory) + }) + }) + + describe('platformAccessory.deserialize', () => { + it('should deserialize serialized accessory correctly', () => { + const accessory = createAccessory() + accessory.addService(Service.Lightbulb) + + const json = PlatformAccessory.serialize(accessory) + const reconstructed = PlatformAccessory.deserialize(json) + + expect(reconstructed._associatedPlugin).toBe(accessory._associatedPlugin) + expect(reconstructed._associatedPlatform).toBe(accessory._associatedPlatform) + expect(reconstructed.displayName).toBe(accessory.displayName) + expect(reconstructed.UUID).toBe(accessory.UUID) + expect(reconstructed.category).toBe(accessory.category) + expect(reconstructed.context).toBe(accessory.context) + }) + }) +}) diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index 43417cc43..5becd5bd5 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -1,115 +1,108 @@ -import { EventEmitter } from "events"; -import { - Accessory, - AccessoryEventTypes, - Categories, +import type { Controller, ControllerConstructor, SerializedAccessory, Service, VoidCallback, WithUUID, -} from "hap-nodejs"; -import { ConstructorArgs } from "hap-nodejs/dist/types"; -import { PlatformName, PluginIdentifier, PluginName } from "./api"; +} from 'hap-nodejs' +import type { ConstructorArgs } from 'hap-nodejs/dist/types.js' -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export type UnknownContext = Record; +import type { PlatformName, PluginIdentifier, PluginName } from './api.js' -export interface SerializedPlatformAccessory extends SerializedAccessory { +import { EventEmitter } from 'node:events' + +import { Accessory, AccessoryEventTypes, Categories } from 'hap-nodejs' - plugin: PluginName; - platform: PlatformName; - context: T; +export type UnknownContext = Record +export interface SerializedPlatformAccessory extends SerializedAccessory { + plugin: PluginName + platform: PlatformName + context: T } +// eslint-disable-next-line no-restricted-syntax export const enum PlatformAccessoryEvent { - IDENTIFY = "identify", + IDENTIFY = 'identify', } +// eslint-disable-next-line ts/no-unsafe-declaration-merging export declare interface PlatformAccessory { - - on(event: "identify", listener: () => void): this; - - emit(event: "identify"): boolean; - + on: (event: 'identify', listener: () => void) => this + emit: (event: 'identify') => boolean } - -export class PlatformAccessory extends EventEmitter { - +// eslint-disable-next-line ts/no-unsafe-declaration-merging +export class PlatformAccessory extends EventEmitter { // somewhat ugly way to inject custom Accessory object, while not changing the publicly exposed constructor signature - private static injectedAccessory?: Accessory; - - _associatedPlugin?: PluginIdentifier; // present as soon as it is registered - _associatedPlatform?: PlatformName; // not present for external accessories + private static injectedAccessory?: Accessory - _associatedHAPAccessory: Accessory; + _associatedPlugin?: PluginIdentifier // present as soon as it is registered + _associatedPlatform?: PlatformName // not present for external accessories + _associatedHAPAccessory: Accessory // ---------------- HAP Accessory mirror ---------------- - displayName: string; - UUID: string; - category: Categories; - services: Service[] = []; + displayName: string + UUID: string + category: Categories + services: Service[] = [] // ------------------------------------------------------ /** * This is a way for Plugin developers to store custom data with their accessory */ - public context: T = {} as T; // providing something to store + public context: T = {} as T // providing something to store constructor(displayName: string, uuid: string, category?: Categories) { // category is only useful for external accessories - super(); + super() this._associatedHAPAccessory = PlatformAccessory.injectedAccessory ? PlatformAccessory.injectedAccessory - : new Accessory(displayName, uuid); + : new Accessory(displayName, uuid) if (category) { - this._associatedHAPAccessory.category = category; + this._associatedHAPAccessory.category = category } - this.displayName = this._associatedHAPAccessory.displayName; - this.UUID = this._associatedHAPAccessory.UUID; - this.category = category || Categories.OTHER; - this.services = this._associatedHAPAccessory.services; + this.displayName = this._associatedHAPAccessory.displayName + this.UUID = this._associatedHAPAccessory.UUID + this.category = category || Categories.OTHER + this.services = this._associatedHAPAccessory.services // forward identify event this._associatedHAPAccessory.on(AccessoryEventTypes.IDENTIFY, (paired: boolean, callback: VoidCallback) => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - // eslint-disable-next-line @typescript-eslint/no-empty-function - this.emit(PlatformAccessoryEvent.IDENTIFY, paired, () => {}); // empty callback for backwards compatibility - callback(); - }); + // @ts-expect-error: empty callback for backwards compatibility + this.emit(PlatformAccessoryEvent.IDENTIFY, paired, () => {}) + callback() + }) } public updateDisplayName(name: string): void { if (name) { - this.displayName = name; - this._associatedHAPAccessory.displayName = name; + this.displayName = name + this._associatedHAPAccessory.displayName = name } } - public addService(service: Service): Service; - public addService(serviceConstructor: S, ...constructorArgs: ConstructorArgs): Service; - public addService(service: Service | typeof Service, ...constructorArgs: any[]): Service { // eslint-disable-line @typescript-eslint/no-explicit-any + public addService(service: Service): Service + public addService(serviceConstructor: S, ...constructorArgs: ConstructorArgs): Service + public addService(service: Service | typeof Service, ...constructorArgs: any[]): Service { // @ts-expect-error: while the HAP-NodeJS interface was refined, the underlying implementation // still only operates on an any[] array. Therefore, do not require any additional checks here // we force the parameter unpack with expecting a ts-error. - return this._associatedHAPAccessory.addService(service, ...constructorArgs); + return this._associatedHAPAccessory.addService(service, ...constructorArgs) } public removeService(service: Service): void { - this._associatedHAPAccessory.removeService(service); + this._associatedHAPAccessory.removeService(service) } public getService>(name: string | T): Service | undefined { - return this._associatedHAPAccessory.getService(name); + return this._associatedHAPAccessory.getService(name) } public getServiceById>(uuid: string | T, subType: string): Service | undefined { - return this._associatedHAPAccessory.getServiceById(uuid, subType); + return this._associatedHAPAccessory.getServiceById(uuid, subType) } /** @@ -119,7 +112,7 @@ export class PlatformAccessory exten * @param controller */ public configureController(controller: Controller | ControllerConstructor): void { - this._associatedHAPAccessory.configureController(controller); + this._associatedHAPAccessory.configureController(controller) } /** @@ -129,33 +122,32 @@ export class PlatformAccessory exten * @param controller */ public removeController(controller: Controller): void { - this._associatedHAPAccessory.removeController(controller); + this._associatedHAPAccessory.removeController(controller) } // private static serialize(accessory: PlatformAccessory): SerializedPlatformAccessory { - accessory._associatedHAPAccessory.displayName = accessory.displayName; + accessory._associatedHAPAccessory.displayName = accessory.displayName return { plugin: accessory._associatedPlugin!, platform: accessory._associatedPlatform!, context: accessory.context, ...Accessory.serialize(accessory._associatedHAPAccessory), - }; + } } static deserialize(json: SerializedPlatformAccessory): PlatformAccessory { - const accessory = Accessory.deserialize(json); + const accessory = Accessory.deserialize(json) - PlatformAccessory.injectedAccessory = accessory; - const platformAccessory = new PlatformAccessory(accessory.displayName, accessory.UUID); - PlatformAccessory.injectedAccessory = undefined; + PlatformAccessory.injectedAccessory = accessory + const platformAccessory = new PlatformAccessory(accessory.displayName, accessory.UUID) + PlatformAccessory.injectedAccessory = undefined - platformAccessory._associatedPlugin = json.plugin; - platformAccessory._associatedPlatform = json.platform; - platformAccessory.context = json.context; - platformAccessory.category = json.category; + platformAccessory._associatedPlugin = json.plugin + platformAccessory._associatedPlatform = json.platform + platformAccessory.context = json.context + platformAccessory.category = json.category - return platformAccessory; + return platformAccessory } - } diff --git a/src/plugin.ts b/src/plugin.ts index 6bba89b59..8e6d2300e 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -1,249 +1,236 @@ -import assert from "assert"; -import path from "path"; -import { pathToFileURL } from "url"; -import { satisfies } from "semver"; -import { +import type { AccessoryIdentifier, AccessoryName, AccessoryPluginConstructor, API, + DynamicPlatformPlugin, PlatformIdentifier, PlatformName, - DynamicPlatformPlugin, PlatformPluginConstructor, PluginIdentifier, PluginInitializer, PluginName, -} from "./api"; -import { Logger } from "./logger"; -import { PackageJSON, PluginManager } from "./pluginManager"; -import getVersion from "./version"; +} from './api.js' +import type { PackageJSON } from './pluginManager.js' + +import assert from 'node:assert' +import { join } from 'node:path' +import process from 'node:process' +import { pathToFileURL } from 'node:url' + +import { satisfies } from 'semver' -const log = Logger.internal; +import { Logger } from './logger.js' +import { PluginManager } from './pluginManager.js' +import getVersion from './version.js' -// Workaround for https://github.com/microsoft/TypeScript/issues/43329 -const _importDynamic = new Function("modulePath", "return import(modulePath)"); +const log = Logger.internal /** * Represents a loaded Homebridge plugin. */ export class Plugin { - - private readonly pluginName: PluginName; - private readonly scope?: string; // npm package scope - private readonly pluginPath: string; // like "/usr/local/lib/node_modules/homebridge-lockitron" - private readonly isESM: boolean; - - public disabled = false; // mark the plugin as disabled + private readonly pluginName: PluginName + private readonly scope?: string // npm package scope + private readonly pluginPath: string // like "/usr/local/lib/node_modules/homebridge-lockitron" + public disabled = false // mark the plugin as disabled // ------------------ package.json content ------------------ - readonly version: string; - private readonly main: string; + readonly version: string + private readonly main: string private loadContext?: { // used to store data for a limited time until the load method is called, will be reset afterward - engines?: Record; - dependencies?: Record; - }; + engines?: Record + dependencies?: Record + } // ---------------------------------------------------------- - private pluginInitializer?: PluginInitializer; // default exported function from the plugin that initializes it - - private readonly registeredAccessories: Map = new Map(); - private readonly registeredPlatforms: Map = new Map(); - - private readonly activeDynamicPlatforms: Map = new Map(); + private pluginInitializer?: PluginInitializer // default exported function from the plugin that initializes it + private readonly registeredAccessories: Map = new Map() + private readonly registeredPlatforms: Map = new Map() + private readonly activeDynamicPlatforms: Map = new Map() constructor(name: PluginName, path: string, packageJSON: PackageJSON, scope?: string) { - this.pluginName = name; - this.scope = scope; - this.pluginPath = path; - - this.version = packageJSON.version || "0.0.0"; - this.main = ""; + this.pluginName = name + this.scope = scope + this.pluginPath = path + this.version = packageJSON.version || '0.0.0' + this.main = '' // figure out the main module // exports is available - https://nodejs.org/dist/latest-v14.x/docs/api/packages.html#packages_package_entry_points if (packageJSON.exports) { // main entrypoint - https://nodejs.org/dist/latest-v14.x/docs/api/packages.html#packages_main_entry_point_export - if (typeof packageJSON.exports === "string") { - this.main = packageJSON.exports; + if (typeof packageJSON.exports === 'string') { + this.main = packageJSON.exports } else { // subpath export - https://nodejs.org/dist/latest-v14.x/docs/api/packages.html#packages_subpath_exports // conditional exports - https://nodejs.org/dist/latest-v14.x/docs/api/packages.html#packages_conditional_exports - const exports = packageJSON.exports.import || packageJSON.exports.require || packageJSON.exports.node || packageJSON.exports.default || packageJSON.exports["."]; + const exports = packageJSON.exports.import || packageJSON.exports.require || packageJSON.exports.node || packageJSON.exports.default || packageJSON.exports['.'] // check if conditional export is nested - if (typeof exports !== "string") { - if(exports.import) { - this.main = exports.import; + if (typeof exports !== 'string') { + if (exports.import) { + this.main = exports.import } else { - this.main = exports.require || exports.node || exports.default; + this.main = exports.require || exports.node || exports.default } } else { - this.main = exports; + this.main = exports } } } // exports search was not successful, fallback to package.main, using index.js as fallback if (!this.main) { - this.main = packageJSON.main || "./index.js"; + this.main = packageJSON.main || './index.js' } - // check if it is an ESM module - this.isESM = this.main.endsWith(".mjs") || (this.main.endsWith(".js") && packageJSON.type === "module"); - // very temporary fix for first wave of plugins if (packageJSON.peerDependencies && (!packageJSON.engines || !packageJSON.engines.homebridge)) { - packageJSON.engines = packageJSON.engines || {}; - packageJSON.engines.homebridge = packageJSON.peerDependencies.homebridge; + packageJSON.engines = packageJSON.engines || {} + packageJSON.engines.homebridge = packageJSON.peerDependencies.homebridge } this.loadContext = { engines: packageJSON.engines, dependencies: packageJSON.dependencies, - }; + } } public getPluginIdentifier(): PluginIdentifier { // return full plugin name with scope prefix - return (this.scope? this.scope + "/": "") + this.pluginName; + return (this.scope ? `${this.scope}/` : '') + this.pluginName } public getPluginPath(): string { - return this.pluginPath; + return this.pluginPath } public registerAccessory(name: AccessoryName, constructor: AccessoryPluginConstructor): void { if (this.registeredAccessories.has(name)) { - throw new Error(`Plugin '${this.getPluginIdentifier()}' tried to register an accessory '${name}' which has already been registered!`); + throw new Error(`Plugin '${this.getPluginIdentifier()}' tried to register an accessory '${name}' which has already been registered!`) } if (!this.disabled) { - log.info("Registering accessory '%s'", this.getPluginIdentifier() + "." + name); + log.info('Registering accessory \'%s\'', `${this.getPluginIdentifier()}.${name}`) } - this.registeredAccessories.set(name, constructor); + this.registeredAccessories.set(name, constructor) } public registerPlatform(name: PlatformName, constructor: PlatformPluginConstructor): void { if (this.registeredPlatforms.has(name)) { - throw new Error(`Plugin '${this.getPluginIdentifier()}' tried to register a platform '${name}' which has already been registered!`); + throw new Error(`Plugin '${this.getPluginIdentifier()}' tried to register a platform '${name}' which has already been registered!`) } if (!this.disabled) { - log.info("Registering platform '%s'", this.getPluginIdentifier() + "." + name); + log.info('Registering platform \'%s\'', `${this.getPluginIdentifier()}.${name}`) } - this.registeredPlatforms.set(name, constructor); + this.registeredPlatforms.set(name, constructor) } public getAccessoryConstructor(accessoryIdentifier: AccessoryIdentifier | AccessoryName): AccessoryPluginConstructor { - const name: AccessoryName = PluginManager.getAccessoryName(accessoryIdentifier); + const name: AccessoryName = PluginManager.getAccessoryName(accessoryIdentifier) - const constructor = this.registeredAccessories.get(name); + const constructor = this.registeredAccessories.get(name) if (!constructor) { - throw new Error(`The requested accessory '${name}' was not registered by the plugin '${this.getPluginIdentifier()}'.`); + throw new Error(`The requested accessory '${name}' was not registered by the plugin '${this.getPluginIdentifier()}'.`) } - return constructor; + return constructor } public getPlatformConstructor(platformIdentifier: PlatformIdentifier | PlatformName): PlatformPluginConstructor { - const name: PlatformName = PluginManager.getPlatformName(platformIdentifier); + const name: PlatformName = PluginManager.getPlatformName(platformIdentifier) - const constructor = this.registeredPlatforms.get(name); + const constructor = this.registeredPlatforms.get(name) if (!constructor) { - throw new Error(`The requested platform '${name}' was not registered by the plugin '${this.getPluginIdentifier()}'.`); + throw new Error(`The requested platform '${name}' was not registered by the plugin '${this.getPluginIdentifier()}'.`) } // If it's a dynamic platform plugin, ensure it's not enabled multiple times. if (this.activeDynamicPlatforms.has(name)) { - throw new Error("The dynamic platform " + name + " from the plugin " + this.getPluginIdentifier() + " is configured " + - "times in your config.json."); + throw new Error(`The dynamic platform ${name} from the plugin ${this.getPluginIdentifier()} is configured ` + + 'times in your config.json.') } - return constructor; + return constructor } public assignDynamicPlatform(platformIdentifier: PlatformIdentifier | PlatformName, platformPlugin: DynamicPlatformPlugin): void { - const name: PlatformName = PluginManager.getPlatformName(platformIdentifier); + const name: PlatformName = PluginManager.getPlatformName(platformIdentifier) - let platforms = this.activeDynamicPlatforms.get(name); + let platforms = this.activeDynamicPlatforms.get(name) if (!platforms) { - platforms = []; - this.activeDynamicPlatforms.set(name, platforms); + platforms = [] + this.activeDynamicPlatforms.set(name, platforms) } // the last platform published should be at the first position for easy access // we just try to mimic pre 1.0.0 behavior - platforms.unshift(platformPlugin); + platforms.unshift(platformPlugin) } public getActiveDynamicPlatform(platformName: PlatformName): DynamicPlatformPlugin | undefined { - const platforms = this.activeDynamicPlatforms.get(platformName); + const platforms = this.activeDynamicPlatforms.get(platformName) // we always use the last registered - return platforms && platforms[0]; + return platforms && platforms[0] } public async load(): Promise { - const context = this.loadContext!; - assert(context, "Reached illegal state. Plugin state is undefined!"); - this.loadContext = undefined; // free up memory + const context = this.loadContext! + assert(context, 'Reached illegal state. Plugin state is undefined!') + this.loadContext = undefined // free up memory - // pluck out the HomeBridge version requirement + // pluck out the Homebridge version requirement if (!context.engines || !context.engines.homebridge) { - throw new Error(`Plugin ${this.pluginPath} does not contain the 'homebridge' package in 'engines'.`); + throw new Error(`Plugin ${this.pluginPath} does not contain the 'homebridge' package in 'engines'.`) } - const versionRequired = context.engines.homebridge; - const nodeVersionRequired = context.engines.node; + const versionRequired = context.engines.homebridge + const nodeVersionRequired = context.engines.node - // make sure the version is satisfied by the currently running version of HomeBridge + // make sure the version is satisfied by the currently running version of Homebridge if (!satisfies(getVersion(), versionRequired, { includePrerelease: true })) { // TODO - change this back to an error - log.error(`The plugin "${this.pluginName}" requires a Homebridge version of ${versionRequired} which does \ -not satisfy the current Homebridge version of ${getVersion()}. You may need to update this plugin (or Homebridge) to a newer version. \ -You may face unexpected issues or stability problems running this plugin.`); + log.warn(`The plugin "${this.pluginName}" requires a Homebridge version of ${versionRequired} which does \ +not satisfy the current Homebridge version of v${getVersion()}. You may need to update this plugin (or Homebridge) to a newer version. \ +You may face unexpected issues or stability problems running this plugin.`) } // make sure the version is satisfied by the currently running version of Node if (nodeVersionRequired && !satisfies(process.version, nodeVersionRequired)) { - log.warn(`The plugin "${this.pluginName}" requires Node.js version of ${nodeVersionRequired} which does \ -not satisfy the current Node.js version of ${process.version}. You may need to upgrade your installation of Node.js - see https://homebridge.io/w/JTKEF`); + log.warn(`The plugin "${this.pluginName}" requires a Node.js version of ${nodeVersionRequired} which does \ +not satisfy the current Node.js version of ${process.version}. You may need to upgrade your installation of Node.js - see https://homebridge.io/w/JTKEF`) } - const dependencies = context.dependencies || {}; - if (dependencies.homebridge || dependencies["hap-nodejs"]) { + const dependencies = context.dependencies || {} + if (dependencies.homebridge || dependencies['hap-nodejs']) { log.error(`The plugin "${this.pluginName}" defines 'homebridge' and/or 'hap-nodejs' in their 'dependencies' section, \ meaning they carry an additional copy of homebridge and hap-nodejs. This not only wastes disk space, but also can cause \ -major incompatibility issues and thus is considered bad practice. Please inform the developer to update their plugin!`); +major incompatibility issues and thus is considered bad practice. Please inform the developer to update their plugin!`) } - const mainPath = path.join(this.pluginPath, this.main); - - // try to require() it and grab the exported initialization hook - // eslint-disable-next-line @typescript-eslint/no-var-requires + const mainPath = join(this.pluginPath, this.main) + // try to import it and grab the exported initialization hook // pathToFileURL(specifier).href to turn a path into a "file url" // see https://github.com/nodejs/node/issues/31710 + const pluginModules = (await import(pathToFileURL(mainPath).href)).default - // eslint-disable-next-line @typescript-eslint/no-require-imports - const pluginModules = this.isESM ? await _importDynamic(pathToFileURL(mainPath).href) : require(mainPath); - - if (typeof pluginModules === "function") { - this.pluginInitializer = pluginModules; - } else if (pluginModules && typeof pluginModules.default === "function") { - this.pluginInitializer = pluginModules.default; + if (typeof pluginModules === 'function') { + this.pluginInitializer = pluginModules + } else if (pluginModules && typeof pluginModules.default === 'function') { + this.pluginInitializer = pluginModules.default } else { - throw new Error(`Plugin ${this.pluginPath} does not export a initializer function from main.`); + throw new Error(`Plugin ${this.pluginPath} does not export a initializer function from main.`) } } public initialize(api: API): void | Promise { if (!this.pluginInitializer) { - throw new Error("Tried to initialize a plugin which hasn't been loaded yet!"); + throw new Error('Tried to initialize a plugin which hasn\'t been loaded yet!') } - return this.pluginInitializer(api); + return this.pluginInitializer(api) } - - } diff --git a/src/pluginManager.spec.ts b/src/pluginManager.spec.ts index d896a0ceb..e892f0b56 100644 --- a/src/pluginManager.spec.ts +++ b/src/pluginManager.spec.ts @@ -1,63 +1,52 @@ -import { PluginManager } from "./pluginManager"; - -describe("PluginManager", () => { - describe("PluginManager.isQualifiedPluginIdentifier", () => { - it("should match normal plugin names", () => { - expect(PluginManager.isQualifiedPluginIdentifier("homebridge-dummy-plugin")).toBeTruthy(); - }); - - it("should match scoped plugin names", () => { - expect(PluginManager.isQualifiedPluginIdentifier("@organisation/homebridge-dummy-plugin")).toBeTruthy(); - }); - - it("should match scoped plugin names with dots", () => { - expect(PluginManager.isQualifiedPluginIdentifier("@organisation.com/homebridge-dummy-plugin")).toBeTruthy(); - }); - }); - - describe("PluginManager.extractPluginName", () => { - it("should extract normal plugin names", function() { - expect(PluginManager.extractPluginName("homebridge-dummy-plugin")).toBe("homebridge-dummy-plugin"); - }); - - it("should extract scoped plugin names", function() { - expect(PluginManager.extractPluginName("@organisation/homebridge-dummy-plugin")).toBe("homebridge-dummy-plugin"); - }); - - it("should extract scoped plugin names with scopes with dots in their name", function() { - expect(PluginManager.extractPluginName("@organisation.com/homebridge-dummy-plugin")).toBe("homebridge-dummy-plugin"); - }); - }); - - describe("PluginManager.extractPluginScope", () => { - it("should extract undefined for normal plugin names", function() { - expect(PluginManager.extractPluginScope("homebridge-dummy-plugin")).toBeUndefined(); - }); - - it("should extract scope for scoped plugin names", function() { - expect(PluginManager.extractPluginScope("@organisation/homebridge-dummy-plugin")).toBe("@organisation"); - }); - - it("should extract scope for scoped plugin names with dots in their name", function() { - expect(PluginManager.extractPluginScope("@organisation.com/homebridge-dummy-plugin")).toBe("@organisation.com"); - }); - }); - - describe("...Name", () => { - it("should extract accessory name correctly", function() { - const accessoryId = "homebridge-example-accessory.example"; - expect(PluginManager.getAccessoryName(accessoryId)).toBe("example"); - }); - - it("should extract platform name correctly", function() { - const accessoryId = "homebridge-example-platform.example"; - expect(PluginManager.getPlatformName(accessoryId)).toBe("example"); - }); - - it("should extract plugin name correctly", function() { - const accessoryId = "homebridge-example-plugin.example"; - expect(PluginManager.getPluginIdentifier(accessoryId)).toBe("homebridge-example-plugin"); - }); - }); - -}); +import { describe, expect, it } from 'vitest' + +import { PluginManager } from './pluginManager.js' + +describe('pluginManager', () => { + describe('pluginManager.isQualifiedPluginIdentifier', () => { + it('should match normal plugin names', () => { + expect(PluginManager.isQualifiedPluginIdentifier('homebridge-dummy-plugin')).toBeTruthy() + }) + + it('should match scoped plugin names', () => { + expect(PluginManager.isQualifiedPluginIdentifier('@organisation/homebridge-dummy-plugin')).toBeTruthy() + }) + }) + + describe('pluginManager.extractPluginName', () => { + it('should extract normal plugin names', () => { + expect(PluginManager.extractPluginName('homebridge-dummy-plugin')).toBe('homebridge-dummy-plugin') + }) + + it('should extract scoped plugin names', () => { + expect(PluginManager.extractPluginName('@organisation/homebridge-dummy-plugin')).toBe('homebridge-dummy-plugin') + }) + }) + + describe('pluginManager.extractPluginScope', () => { + it('should extract undefined for normal plugin names', () => { + expect(PluginManager.extractPluginScope('homebridge-dummy-plugin')).toBeUndefined() + }) + + it('should extract scope for scoped plugin names', () => { + expect(PluginManager.extractPluginScope('@organisation/homebridge-dummy-plugin')).toBe('@organisation') + }) + }) + + describe('...Name', () => { + it('should extract accessory name correctly', () => { + const accessoryId = 'homebridge-example-accessory.example' + expect(PluginManager.getAccessoryName(accessoryId)).toBe('example') + }) + + it('should extract platform name correctly', () => { + const accessoryId = 'homebridge-example-platform.example' + expect(PluginManager.getPlatformName(accessoryId)).toBe('example') + }) + + it('should extract plugin name correctly', () => { + const accessoryId = 'homebridge-example-plugin.example' + expect(PluginManager.getPluginIdentifier(accessoryId)).toBe('homebridge-example-plugin') + }) + }) +}) diff --git a/src/pluginManager.ts b/src/pluginManager.ts index d9ce37764..89782b5cd 100644 --- a/src/pluginManager.ts +++ b/src/pluginManager.ts @@ -1,322 +1,324 @@ -import { execSync } from "child_process"; -import fs from "fs"; -import path from "path"; -import { +import type { AccessoryIdentifier, AccessoryName, AccessoryPluginConstructor, HomebridgeAPI, - InternalAPIEvent, PlatformIdentifier, PlatformName, PlatformPluginConstructor, PluginIdentifier, PluginName, -} from "./api"; -import { Logger } from "./logger"; -import { Plugin } from "./plugin"; +} from './api.js' -const log = Logger.internal; +import { execSync } from 'node:child_process' +import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs' +import { createRequire } from 'node:module' +import { delimiter, join, resolve } from 'node:path' +import process from 'node:process' + +import { InternalAPIEvent } from './api.js' +import { Logger } from './logger.js' +import { Plugin } from './plugin.js' + +const log = Logger.internal +const require = createRequire(import.meta.url) +const paths = require.resolve.paths('') export interface PackageJSON { // incomplete type for package.json (just stuff we use here) - name: string; - version: string; - keywords?: string[]; + name: string + version: string + keywords?: string[] // see https://nodejs.org/dist/latest-v14.x/docs/api/packages.html#packages_package_entry_points exports?: string | Record> - main?: string; + main?: string /** * When set as module, it marks .js file to be treated as ESM. * See https://nodejs.org/dist/latest-v14.x/docs/api/esm.html#esm_enabling */ - type?: "module" | "commonjs"; + type?: 'module' | 'commonjs' - engines?: Record; - dependencies?: Record; - devDependencies?: Record; - peerDependencies?: Record; + engines?: Record + dependencies?: Record + devDependencies?: Record + peerDependencies?: Record } export interface PluginManagerOptions { /** * Additional path to search for plugins in. Specified relative to the current working directory. */ - customPluginPath?: string; + customPluginPath?: string /** * If set, only load plugins from the customPluginPath, if set, otherwise only from the primary global node_modules. */ - strictPluginResolution?: boolean; + strictPluginResolution?: boolean /** * When defined, only plugins specified here will be initialized. */ - activePlugins?: PluginIdentifier[]; + activePlugins?: PluginIdentifier[] /** * Plugins that are marked as disabled and whose corresponding config blocks should be ignored */ - disabledPlugins?: PluginIdentifier[]; + disabledPlugins?: PluginIdentifier[] } /** * Utility which exposes methods to search for installed Homebridge plugins */ export class PluginManager { - // name must be prefixed with 'homebridge-' or '@scope/homebridge-' - private static readonly PLUGIN_IDENTIFIER_PATTERN = /^((@[\w-]+(\.[\w-]+)*)\/)?(homebridge-[\w-]+)$/; + private static readonly PLUGIN_IDENTIFIER_PATTERN = /^((@[\w-]+(\.[\w-]+)*)\/)?(homebridge-[\w-]+)$/ - private readonly api: HomebridgeAPI; + private readonly api: HomebridgeAPI - private readonly searchPaths: Set = new Set(); // unique set of search paths we will use to discover installed plugins - private readonly strictPluginResolution: boolean = false; - private readonly activePlugins?: PluginIdentifier[]; - private readonly disabledPlugins?: PluginIdentifier[]; + private readonly searchPaths: Set = new Set() // unique set of search paths we will use to discover installed plugins + private readonly strictPluginResolution: boolean = false + private readonly activePlugins?: PluginIdentifier[] + private readonly disabledPlugins?: PluginIdentifier[] - private readonly plugins: Map = new Map(); + private readonly plugins: Map = new Map() // we have some plugins which simply pass a wrong or misspelled plugin name to the api calls, this translation tries to mitigate this - private readonly pluginIdentifierTranslation: Map = new Map(); - private readonly accessoryToPluginMap: Map = new Map(); - private readonly platformToPluginMap: Map = new Map(); + private readonly pluginIdentifierTranslation: Map = new Map() + private readonly accessoryToPluginMap: Map = new Map() + private readonly platformToPluginMap: Map = new Map() - private currentInitializingPlugin?: Plugin; // used to match registering plugins, see handleRegisterAccessory and handleRegisterPlatform + private currentInitializingPlugin?: Plugin // used to match registering plugins, see handleRegisterAccessory and handleRegisterPlatform constructor(api: HomebridgeAPI, options?: PluginManagerOptions) { - this.api = api; + this.api = api if (options) { if (options.customPluginPath) { - this.searchPaths.add(path.resolve(process.cwd(), options.customPluginPath)); + this.searchPaths.add(resolve(process.cwd(), options.customPluginPath)) } - this.strictPluginResolution = options.strictPluginResolution || false; + this.strictPluginResolution = options.strictPluginResolution || false - this.activePlugins = options.activePlugins; - this.disabledPlugins = Array.isArray(options.disabledPlugins) ? options.disabledPlugins : undefined; + this.activePlugins = options.activePlugins + this.disabledPlugins = Array.isArray(options.disabledPlugins) ? options.disabledPlugins : undefined } - this.api.on(InternalAPIEvent.REGISTER_ACCESSORY, this.handleRegisterAccessory.bind(this)); - this.api.on(InternalAPIEvent.REGISTER_PLATFORM, this.handleRegisterPlatform.bind(this)); + this.api.on(InternalAPIEvent.REGISTER_ACCESSORY, this.handleRegisterAccessory.bind(this)) + this.api.on(InternalAPIEvent.REGISTER_PLATFORM, this.handleRegisterPlatform.bind(this)) } public static isQualifiedPluginIdentifier(identifier: string): boolean { - return PluginManager.PLUGIN_IDENTIFIER_PATTERN.test(identifier); + return PluginManager.PLUGIN_IDENTIFIER_PATTERN.test(identifier) } public static extractPluginName(name: string): PluginName { // extract plugin name without @scope/ prefix - return name.match(PluginManager.PLUGIN_IDENTIFIER_PATTERN)![4]; + return name.match(PluginManager.PLUGIN_IDENTIFIER_PATTERN)![4] } public static extractPluginScope(name: string): string { // extract the "@scope" of a npm module name - return name.match(PluginManager.PLUGIN_IDENTIFIER_PATTERN)![2]; + return name.match(PluginManager.PLUGIN_IDENTIFIER_PATTERN)![2] } public static getAccessoryName(identifier: AccessoryIdentifier): AccessoryName { - if (identifier.indexOf(".") === -1) { - return identifier; + if (!identifier.includes('.')) { + return identifier } - return identifier.split(".")[1]; + return identifier.split('.')[1] } public static getPlatformName(identifier: PlatformIdentifier): PlatformIdentifier { - if (identifier.indexOf(".") === -1) { - return identifier; + if (!identifier.includes('.')) { + return identifier } - return identifier.split(".")[1]; + return identifier.split('.')[1] } public static getPluginIdentifier(identifier: AccessoryIdentifier | PlatformIdentifier): PluginIdentifier { - return identifier.split(".")[0]; + return identifier.split('.')[0] } public async initializeInstalledPlugins(): Promise { - log.info("---"); + log.info('---') - this.loadInstalledPlugins(); + this.loadInstalledPlugins() - for(const [identifier, plugin] of this.plugins) { + for (const [identifier, plugin] of this.plugins) { try { - await plugin.load(); - } catch (error) { - log.error("===================="); - log.error(`ERROR LOADING PLUGIN ${identifier}:`); - log.error(error.stack); - log.error("===================="); - - this.plugins.delete(identifier); - continue; + await plugin.load() + } catch (error: any) { + log.error('====================') + log.error(`ERROR LOADING PLUGIN ${identifier}:`) + log.error(error.stack) + log.error('====================') + + this.plugins.delete(identifier) + continue } if (this.disabledPlugins && this.disabledPlugins.includes(plugin.getPluginIdentifier())) { - plugin.disabled = true; + plugin.disabled = true } if (plugin.disabled) { - log.warn(`Disabled plugin: ${identifier}@${plugin.version}`); + log.warn(`Disabled plugin: ${identifier}@${plugin.version}`) } else { - log.info(`Loaded plugin: ${identifier}@${plugin.version}`); + log.info(`Loaded plugin: ${identifier}@${plugin.version}`) } - await this.initializePlugin(plugin, identifier); + await this.initializePlugin(plugin, identifier) - log.info("---"); + log.info('---') } - this.currentInitializingPlugin = undefined; + this.currentInitializingPlugin = undefined } public async initializePlugin(plugin: Plugin, identifier: string): Promise { try { - this.currentInitializingPlugin = plugin; - await plugin.initialize(this.api); // call the plugin's initializer and pass it our API instance - } catch (error) { - log.error("===================="); - log.error(`ERROR INITIALIZING PLUGIN ${identifier}:`); - log.error(error.stack); - log.error("===================="); - - this.plugins.delete(identifier); - return; + this.currentInitializingPlugin = plugin + await plugin.initialize(this.api) // call the plugin's initializer and pass it our API instance + } catch (error: any) { + log.error('====================') + log.error(`ERROR INITIALIZING PLUGIN ${identifier}:`) + log.error(error.stack) + log.error('====================') + + this.plugins.delete(identifier) } } private handleRegisterAccessory(name: AccessoryName, constructor: AccessoryPluginConstructor, pluginIdentifier?: PluginIdentifier): void { if (!this.currentInitializingPlugin) { - throw new Error(`Unexpected accessory registration. Plugin ${pluginIdentifier? `'${pluginIdentifier}' `: ""}tried to register outside the initializer function!`); + throw new Error(`Unexpected accessory registration. Plugin ${pluginIdentifier ? `'${pluginIdentifier}' ` : ''}tried to register outside the initializer function!`) } if (pluginIdentifier && pluginIdentifier !== this.currentInitializingPlugin.getPluginIdentifier()) { - log.info(`Plugin '${this.currentInitializingPlugin.getPluginIdentifier()}' tried to register with an incorrect plugin identifier: '${pluginIdentifier}'. Please report this to the developer!`); - this.pluginIdentifierTranslation.set(pluginIdentifier, this.currentInitializingPlugin.getPluginIdentifier()); + log.info(`Plugin '${this.currentInitializingPlugin.getPluginIdentifier()}' tried to register with an incorrect plugin identifier: '${pluginIdentifier}'. Please report this to the developer!`) + this.pluginIdentifierTranslation.set(pluginIdentifier, this.currentInitializingPlugin.getPluginIdentifier()) } - this.currentInitializingPlugin.registerAccessory(name, constructor); + this.currentInitializingPlugin.registerAccessory(name, constructor) - let plugins = this.accessoryToPluginMap.get(name); + let plugins = this.accessoryToPluginMap.get(name) if (!plugins) { - plugins = []; - this.accessoryToPluginMap.set(name, plugins); + plugins = [] + this.accessoryToPluginMap.set(name, plugins) } - plugins.push(this.currentInitializingPlugin); + plugins.push(this.currentInitializingPlugin) } private handleRegisterPlatform(name: PlatformName, constructor: PlatformPluginConstructor, pluginIdentifier?: PluginIdentifier): void { if (!this.currentInitializingPlugin) { - throw new Error(`Unexpected platform registration. Plugin ${pluginIdentifier? `'${pluginIdentifier}' `: ""}tried to register outside the initializer function!`); + throw new Error(`Unexpected platform registration. Plugin ${pluginIdentifier ? `'${pluginIdentifier}' ` : ''}tried to register outside the initializer function!`) } if (pluginIdentifier && pluginIdentifier !== this.currentInitializingPlugin.getPluginIdentifier()) { - log.debug(`Plugin '${this.currentInitializingPlugin.getPluginIdentifier()}' tried to register with an incorrect plugin identifier: '${pluginIdentifier}'. Please report this to the developer!`); - this.pluginIdentifierTranslation.set(pluginIdentifier, this.currentInitializingPlugin.getPluginIdentifier()); + log.debug(`Plugin '${this.currentInitializingPlugin.getPluginIdentifier()}' tried to register with an incorrect plugin identifier: '${pluginIdentifier}'. Please report this to the developer!`) + this.pluginIdentifierTranslation.set(pluginIdentifier, this.currentInitializingPlugin.getPluginIdentifier()) } - this.currentInitializingPlugin.registerPlatform(name, constructor); + this.currentInitializingPlugin.registerPlatform(name, constructor) - let plugins = this.platformToPluginMap.get(name); + let plugins = this.platformToPluginMap.get(name) if (!plugins) { - plugins = []; - this.platformToPluginMap.set(name, plugins); + plugins = [] + this.platformToPluginMap.set(name, plugins) } - plugins.push(this.currentInitializingPlugin); + plugins.push(this.currentInitializingPlugin) } public getPluginForAccessory(accessoryIdentifier: AccessoryIdentifier | AccessoryName): Plugin { - let plugin: Plugin; - if (accessoryIdentifier.indexOf(".") === -1) { // see if it matches exactly one accessory - let found = this.accessoryToPluginMap.get(accessoryIdentifier); + let plugin: Plugin + if (!accessoryIdentifier.includes('.')) { // see if it matches exactly one accessory + let found = this.accessoryToPluginMap.get(accessoryIdentifier) if (!found) { - throw new Error(`No plugin was found for the accessory "${accessoryIdentifier}" in your config.json. Please make sure the corresponding plugin is installed correctly.`); + throw new Error(`No plugin was found for the accessory "${accessoryIdentifier}" in your config.json. Please make sure the corresponding plugin is installed correctly.`) } if (found.length > 1) { - const options = found.map(plugin => plugin.getPluginIdentifier() + "." + accessoryIdentifier).join(", "); + const options = found.map(plugin => `${plugin.getPluginIdentifier()}.${accessoryIdentifier}`).join(', ') // check if only one of the multiple platforms is not disabled - found = found.filter(plugin => !plugin.disabled); + found = found.filter(plugin => !plugin.disabled) if (found.length !== 1) { - throw new Error(`The requested accessory '${accessoryIdentifier}' has been registered multiple times. Please be more specific by writing one of: ${options}`); + throw new Error(`The requested accessory '${accessoryIdentifier}' has been registered multiple times. Please be more specific by writing one of: ${options}`) } } - plugin = found[0]; - accessoryIdentifier = plugin.getPluginIdentifier() + "." + accessoryIdentifier; - + plugin = found[0] + accessoryIdentifier = `${plugin.getPluginIdentifier()}.${accessoryIdentifier}` } else { - const pluginIdentifier = PluginManager.getPluginIdentifier(accessoryIdentifier); + const pluginIdentifier = PluginManager.getPluginIdentifier(accessoryIdentifier) if (!this.hasPluginRegistered(pluginIdentifier)) { - throw new Error(`The requested plugin '${pluginIdentifier}' was not registered.`); + throw new Error(`The requested plugin '${pluginIdentifier}' was not registered.`) } - plugin = this.getPlugin(pluginIdentifier)!; + plugin = this.getPlugin(pluginIdentifier)! } - return plugin; + return plugin } public getPluginForPlatform(platformIdentifier: PlatformIdentifier | PlatformName): Plugin { - let plugin: Plugin; - if (platformIdentifier.indexOf(".") === -1) { // see if it matches exactly one platform - let found = this.platformToPluginMap.get(platformIdentifier); + let plugin: Plugin + if (!platformIdentifier.includes('.')) { // see if it matches exactly one platform + let found = this.platformToPluginMap.get(platformIdentifier) - if(!found) { - throw new Error(`No plugin was found for the platform "${platformIdentifier}" in your config.json. Please make sure the corresponding plugin is installed correctly.`); + if (!found) { + throw new Error(`No plugin was found for the platform "${platformIdentifier}" in your config.json. Please make sure the corresponding plugin is installed correctly.`) } if (found.length > 1) { - const options = found.map(plugin => plugin.getPluginIdentifier() + "." + platformIdentifier).join(", "); + const options = found.map(plugin => `${plugin.getPluginIdentifier()}.${platformIdentifier}`).join(', ') // check if only one of the multiple platforms is not disabled - found = found.filter(plugin => !plugin.disabled); + found = found.filter(plugin => !plugin.disabled) if (found.length !== 1) { - throw new Error(`The requested platform '${platformIdentifier}' has been registered multiple times. Please be more specific by writing one of: ${options}`); + throw new Error(`The requested platform '${platformIdentifier}' has been registered multiple times. Please be more specific by writing one of: ${options}`) } } - plugin = found[0]; - platformIdentifier = plugin.getPluginIdentifier() + "." + platformIdentifier; - + plugin = found[0] + platformIdentifier = `${plugin.getPluginIdentifier()}.${platformIdentifier}` } else { - const pluginIdentifier = PluginManager.getPluginIdentifier(platformIdentifier); + const pluginIdentifier = PluginManager.getPluginIdentifier(platformIdentifier) if (!this.hasPluginRegistered(pluginIdentifier)) { - throw new Error(`The requested plugin '${pluginIdentifier}' was not registered.`); + throw new Error(`The requested plugin '${pluginIdentifier}' was not registered.`) } - plugin = this.getPlugin(pluginIdentifier)!; + plugin = this.getPlugin(pluginIdentifier)! } - return plugin; + return plugin } public hasPluginRegistered(pluginIdentifier: PluginIdentifier): boolean { - return this.plugins.has(pluginIdentifier) || this.pluginIdentifierTranslation.has(pluginIdentifier); + return this.plugins.has(pluginIdentifier) || this.pluginIdentifierTranslation.has(pluginIdentifier) } public getPlugin(pluginIdentifier: PluginIdentifier): Plugin | undefined { - const plugin = this.plugins.get(pluginIdentifier); + const plugin = this.plugins.get(pluginIdentifier) if (plugin) { - return plugin; + return plugin } else { - const translation = this.pluginIdentifierTranslation.get(pluginIdentifier); + const translation = this.pluginIdentifierTranslation.get(pluginIdentifier) if (translation) { - return this.plugins.get(translation); + return this.plugins.get(translation) } } - return undefined; + return undefined } public getPluginByActiveDynamicPlatform(platformName: PlatformName): Plugin | undefined { const found = (this.platformToPluginMap.get(platformName) || []) - .filter(plugin => !!plugin.getActiveDynamicPlatform(platformName)); + .filter(plugin => !!plugin.getActiveDynamicPlatform(platformName)) if (found.length === 0) { - return undefined; + return undefined } else if (found.length > 1) { - const plugins = found.map(plugin => plugin.getPluginIdentifier()).join(", "); - throw new Error(`'${platformName}' is an ambiguous platform name. It was registered by multiple plugins: ${plugins}`); + const plugins = found.map(plugin => plugin.getPluginIdentifier()).join(', ') + throw new Error(`'${platformName}' is an ambiguous platform name. It was registered by multiple plugins: ${plugins}`) } else { - return found[0]; + return found[0] } } @@ -324,116 +326,114 @@ export class PluginManager { * Gets all plugins installed on the local system */ private loadInstalledPlugins(): void { - this.loadDefaultPaths(); + this.loadDefaultPaths() - this.searchPaths.forEach(searchPath => { // search for plugins among all known paths - if (!fs.existsSync(searchPath)) { // just because this path is in require.main.paths doesn't mean it necessarily exists! - return; + this.searchPaths.forEach((searchPath) => { // search for plugins among all known paths + if (!existsSync(searchPath)) { // just because this path is in require.main.paths doesn't mean it necessarily exists! + return } - if (fs.existsSync(path.join(searchPath, "package.json"))) { // does this path point inside a single plugin and not a directory containing plugins? + if (existsSync(join(searchPath, 'package.json'))) { // does this path point inside a single plugin and not a directory containing plugins? try { - this.loadPlugin(searchPath); - } catch (error) { - log.warn(error.message); - return; + this.loadPlugin(searchPath) + } catch (error: any) { + log.warn(error.message) } } else { // read through each directory in this node_modules folder - const relativePluginPaths = fs.readdirSync(searchPath) // search for directories only - .filter(relativePath => { + const relativePluginPaths = readdirSync(searchPath) // search for directories only + .filter((relativePath) => { try { - return fs.statSync(path.resolve(searchPath, relativePath)).isDirectory(); - } catch (e) { - log.debug(`Ignoring path ${path.resolve(searchPath, relativePath)} - ${e.message}`); - return false; + return statSync(resolve(searchPath, relativePath)).isDirectory() + } catch (error: any) { + log.debug(`Ignoring path ${resolve(searchPath, relativePath)} - ${error.message}`) + return false } - }); + }) // expand out @scoped plugins relativePluginPaths.slice() - .filter(path => path.charAt(0) === "@") // is it a scope directory? - .forEach(scopeDirectory => { + .filter(path => path.charAt(0) === '@') // is it a scope directory? + .forEach((scopeDirectory) => { // remove scopeDirectory from the path list - const index = relativePluginPaths.indexOf(scopeDirectory); - relativePluginPaths.splice(index, 1); + const index = relativePluginPaths.indexOf(scopeDirectory) + relativePluginPaths.splice(index, 1) - const absolutePath = path.join(searchPath, scopeDirectory); - fs.readdirSync(absolutePath) + const absolutePath = join(searchPath, scopeDirectory) + readdirSync(absolutePath) .filter(name => PluginManager.isQualifiedPluginIdentifier(name)) - .filter(name => { + .filter((name) => { try { - return fs.statSync(path.resolve(absolutePath, name)).isDirectory(); - } catch (e) { - log.debug(`Ignoring path ${path.resolve(absolutePath, name)} - ${e.message}`); - return false; + return statSync(resolve(absolutePath, name)).isDirectory() + } catch (error: any) { + log.debug(`Ignoring path ${resolve(absolutePath, name)} - ${error.message}`) + return false } }) - .forEach(name => relativePluginPaths.push(scopeDirectory + "/" + name)); - }); + .forEach(name => relativePluginPaths.push(`${scopeDirectory}/${name}`)) + }) relativePluginPaths - .filter(pluginIdentifier => { + .filter((pluginIdentifier) => { return PluginManager.isQualifiedPluginIdentifier(pluginIdentifier) // needs to be a valid homebridge plugin name - && (!this.activePlugins || this.activePlugins.includes(pluginIdentifier)); // check if activePlugins is restricted and if so is the plugin is contained + && (!this.activePlugins || this.activePlugins.includes(pluginIdentifier)) // check if activePlugins is restricted and if so is the plugin is contained }) - .forEach(pluginIdentifier => { + .forEach((pluginIdentifier) => { try { - const absolutePath = path.resolve(searchPath, pluginIdentifier); - this.loadPlugin(absolutePath); - } catch (error) { - log.warn(error.message); - return; + const absolutePath = resolve(searchPath, pluginIdentifier) + this.loadPlugin(absolutePath) + } catch (error: any) { + log.warn(error.message) } - }); + }) } - }); + }) if (this.plugins.size === 0) { - log.warn("No plugins found."); + log.warn('No plugins found.') } } public loadPlugin(absolutePath: string): Plugin { - const packageJson: PackageJSON = PluginManager.loadPackageJSON(absolutePath); + const packageJson: PackageJSON = PluginManager.loadPackageJSON(absolutePath) - const identifier: PluginIdentifier = packageJson.name; - const name: PluginName = PluginManager.extractPluginName(identifier); - const scope = PluginManager.extractPluginScope(identifier); // possibly undefined + const identifier: PluginIdentifier = packageJson.name + const name: PluginName = PluginManager.extractPluginName(identifier) + const scope = PluginManager.extractPluginScope(identifier) // possibly undefined - const alreadyInstalled = this.plugins.get(identifier); // check if there is already a plugin with the same Identifier + const alreadyInstalled = this.plugins.get(identifier) // check if there is already a plugin with the same Identifier if (alreadyInstalled) { - throw new Error(`Warning: skipping plugin found at '${absolutePath}' since we already loaded the same plugin from '${alreadyInstalled.getPluginPath()}'.`); + throw new Error(`Warning: skipping plugin found at '${absolutePath}' since we already loaded the same plugin from '${alreadyInstalled.getPluginPath()}'.`) } - const plugin = new Plugin(name, absolutePath, packageJson, scope); - this.plugins.set(identifier, plugin); - return plugin; + const plugin = new Plugin(name, absolutePath, packageJson, scope) + this.plugins.set(identifier, plugin) + return plugin } private static loadPackageJSON(pluginPath: string): PackageJSON { - const packageJsonPath = path.join(pluginPath, "package.json"); - let packageJson: PackageJSON; + const packageJsonPath = join(pluginPath, 'package.json') + let packageJson: PackageJSON - if (!fs.existsSync(packageJsonPath)) { - throw new Error(`Plugin ${pluginPath} does not contain a package.json.`); + if (!existsSync(packageJsonPath)) { + throw new Error(`Plugin ${pluginPath} does not contain a package.json.`) } try { - packageJson = JSON.parse(fs.readFileSync(packageJsonPath, { encoding: "utf8" })); // attempt to parse package.json - } catch (err) { - throw new Error(`Plugin ${pluginPath} contains an invalid package.json. Error: ${err}`); + packageJson = JSON.parse(readFileSync(packageJsonPath, { encoding: 'utf8' })) // attempt to parse package.json + } catch (error: any) { + throw new Error(`Plugin ${pluginPath} contains an invalid package.json. Error: ${error}`) } if (!packageJson.name || !PluginManager.isQualifiedPluginIdentifier(packageJson.name)) { - throw new Error(`Plugin ${pluginPath} does not have a package name that begins with 'homebridge-' or '@scope/homebridge-.`); + throw new Error(`Plugin ${pluginPath} does not have a package name that begins with 'homebridge-' or '@scope/homebridge-.`) } // verify that it's tagged with the correct keyword - if (!packageJson.keywords || !packageJson.keywords.includes("homebridge-plugin")) { - throw new Error(`Plugin ${pluginPath} package.json does not contain the keyword 'homebridge-plugin'.`); + if (!packageJson.keywords || !packageJson.keywords.includes('homebridge-plugin')) { + throw new Error(`Plugin ${pluginPath} package.json does not contain the keyword 'homebridge-plugin'.`) } - return packageJson; + return packageJson } private loadDefaultPaths(): void { @@ -442,14 +442,14 @@ export class PluginManager { // * only use custom plugin path, if set; // * otherwise add the current npm global prefix (e.g. /usr/local/lib/node_modules) if (this.searchPaths.size === 0) { - this.addNpmPrefixToSearchPaths(); + this.addNpmPrefixToSearchPaths() } - return; + return } - if (require.main) { + if (paths) { // add the paths used by require() - require.main.paths.forEach(path => this.searchPaths.add(path)); + paths.forEach(path => this.searchPaths.add(path)) } // THIS SECTION FROM: https://github.com/yeoman/environment/blob/master/lib/resolver.js @@ -459,31 +459,31 @@ export class PluginManager { // because of bugs in the parsable implementation of `ls` command and mostly // performance issues. So, we go with our best bet for now. if (process.env.NODE_PATH) { - process.env.NODE_PATH - .split(path.delimiter) + process.env + .NODE_PATH + .split(delimiter) .filter(path => !!path) // trim out empty values - .forEach(path => this.searchPaths.add(path)); + .forEach(path => this.searchPaths.add(path)) } else { // Default paths for non-windows systems - if (process.platform !== "win32") { - this.searchPaths.add("/usr/local/lib/node_modules"); - this.searchPaths.add("/usr/lib/node_modules"); + if (process.platform !== 'win32') { + this.searchPaths.add('/usr/local/lib/node_modules') + this.searchPaths.add('/usr/lib/node_modules') } - this.addNpmPrefixToSearchPaths(); + this.addNpmPrefixToSearchPaths() } } private addNpmPrefixToSearchPaths(): void { - if (process.platform === "win32") { - this.searchPaths.add(path.join(process.env.APPDATA!, "npm/node_modules")); + if (process.platform === 'win32') { + this.searchPaths.add(join(process.env.APPDATA!, 'npm/node_modules')) } else { - this.searchPaths.add(execSync("/bin/echo -n \"$(npm -g prefix)/lib/node_modules\"", { + this.searchPaths.add(execSync('/bin/echo -n "$(npm -g prefix)/lib/node_modules"', { env: Object.assign({ - npm_config_loglevel: "silent", - npm_update_notifier: "false", + npm_config_loglevel: 'silent', + npm_update_notifier: 'false', }, process.env), - }).toString("utf8")); + }).toString('utf8')) } } - } diff --git a/src/server.spec.ts b/src/server.spec.ts index a17230f3f..9c1e2f121 100644 --- a/src/server.spec.ts +++ b/src/server.spec.ts @@ -1,63 +1,71 @@ -import path from "path"; -import fs from "fs-extra"; -import { HAPStorage } from "hap-nodejs"; -import { Server } from "./server"; -import { User } from "./user"; - -describe("Server", () => { - const homebridgeStorageFolder = path.resolve(__dirname, "../mock"); - const configPath = path.resolve(homebridgeStorageFolder, "config.json"); - let consoleErrorSpy: jest.SpyInstance; - let consoleLogSpy: jest.SpyInstance; +import type { MockInstance } from 'vitest' + +import path, { dirname } from 'node:path' +import { fileURLToPath } from 'node:url' + +import fs from 'fs-extra' +import { HAPStorage } from 'hap-nodejs' +import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest' + +import { Server } from './server.js' +import { User } from './user.js' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = dirname(__filename) + +describe('server', () => { + const homebridgeStorageFolder = path.resolve(__dirname, '../mock') + const configPath = path.resolve(homebridgeStorageFolder, 'config.json') + let consoleErrorSpy: MockInstance + let consoleLogSpy: MockInstance const mockConfig = { bridge: { - username: "CC:22:3D:E3:CE:30", - pin: "031-45-154", - name: "Homebridge", + username: 'CC:22:3D:E3:CE:30', + pin: '031-45-154', + name: 'Homebridge', + advertiser: 'ciao', }, accessories: [], platforms: [], - }; + } beforeAll(async () => { - consoleErrorSpy = jest.spyOn(console, "error").mockImplementation(() => {}); - consoleLogSpy = jest.spyOn(console, "log").mockImplementation(() => {}); - await fs.ensureDir(homebridgeStorageFolder); - await fs.writeJson(configPath, mockConfig); - User.setStoragePath(homebridgeStorageFolder); - HAPStorage.setCustomStoragePath(User.persistPath()); - }); - - afterAll(async () => { - await fs.remove(homebridgeStorageFolder); - consoleErrorSpy.mockRestore(); - consoleLogSpy.mockRestore(); - }); + consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) + consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {}) + await fs.ensureDir(homebridgeStorageFolder) + await fs.writeJson(configPath, mockConfig) + User.setStoragePath(homebridgeStorageFolder) + HAPStorage.setCustomStoragePath(User.persistPath()) + }) beforeEach(() => { - jest.resetAllMocks(); - jest.mock("./bridgeService"); - }); + vi.resetAllMocks() + }) + + afterAll(async () => { + await fs.remove(homebridgeStorageFolder) + consoleErrorSpy.mockRestore() + consoleLogSpy.mockRestore() + }) - it("creates an instance of the server without errors", async () => { + it('creates an instance of the server without errors', async () => { const server = new Server({ customStoragePath: homebridgeStorageFolder, hideQRCode: true, - }); + }) - expect(server).toBeInstanceOf(Server); - }); + expect(server).toBeInstanceOf(Server) + }) - it("starts without errors", async () => { + it('starts without errors', async () => { const server = new Server({ customStoragePath: homebridgeStorageFolder, hideQRCode: true, - }); - - await server.start(); + }) - expect(server).toBeInstanceOf(Server); - }); + await server.start() -}); + expect(server).toBeInstanceOf(Server) + }) +}) diff --git a/src/server.ts b/src/server.ts index e35f2e507..6ca29df85 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,92 +1,95 @@ -import fs from "fs"; -import chalk from "chalk"; -import { AccessoryEventTypes, MacAddress, MDNSAdvertiser } from "hap-nodejs"; -import qrcode from "qrcode-terminal"; -import { +import type { MacAddress } from 'hap-nodejs' + +import type { AccessoryIdentifier, AccessoryName, AccessoryPlugin, AccessoryPluginConstructor, - HomebridgeAPI, PlatformIdentifier, PlatformName, PlatformPlugin, PlatformPluginConstructor, - PluginType, -} from "./api"; -import { - BridgeService, - BridgeConfiguration, - HomebridgeConfig, - BridgeOptions, -} from "./bridgeService"; -import { ChildBridgeService } from "./childBridgeService"; -import { ExternalPortService } from "./externalPortService"; -import { IpcIncomingEvent, IpcOutgoingEvent, IpcService } from "./ipcService"; -import { Logger } from "./logger"; -import { Plugin } from "./plugin"; -import { PluginManager, PluginManagerOptions } from "./pluginManager"; -import { User } from "./user"; -import * as mac from "./util/mac"; - -const log = Logger.internal; +} from './api.js' +import type { BridgeConfiguration, BridgeOptions, HomebridgeConfig } from './bridgeService.js' +import type { Plugin } from './plugin.js' +import type { PluginManagerOptions } from './pluginManager.js' + +import { existsSync, readFileSync } from 'node:fs' +import process from 'node:process' + +import chalk from 'chalk' +import { AccessoryEventTypes, MDNSAdvertiser } from 'hap-nodejs' +import qrcode from 'qrcode-terminal' + +import { HomebridgeAPI, PluginType } from './api.js' +import { BridgeService } from './bridgeService.js' +import { ChildBridgeService } from './childBridgeService.js' +import { ExternalPortService } from './externalPortService.js' +import { IpcIncomingEvent, IpcOutgoingEvent, IpcService } from './ipcService.js' +import { Logger } from './logger.js' +import { PluginManager } from './pluginManager.js' +import { User } from './user.js' +import { validMacAddress } from './util/mac.js' + +const log = Logger.internal export interface HomebridgeOptions { - keepOrphanedCachedAccessories?: boolean; - hideQRCode?: boolean; - insecureAccess?: boolean; - customPluginPath?: string; - noLogTimestamps?: boolean; - debugModeEnabled?: boolean; - forceColourLogging?: boolean; - customStoragePath?: string; - strictPluginResolution?: boolean; + keepOrphanedCachedAccessories?: boolean + hideQRCode?: boolean + insecureAccess?: boolean + customPluginPath?: string + noLogTimestamps?: boolean + debugModeEnabled?: boolean + forceColourLogging?: boolean + customStoragePath?: string + strictPluginResolution?: boolean } +// eslint-disable-next-line no-restricted-syntax export const enum ServerStatus { /** * When the server is starting up */ - PENDING = "pending", + PENDING = 'pending', /** * When the server is online and has published the main bridge */ - OK = "ok", + OK = 'ok', /** * When the server is shutting down */ - DOWN = "down", + DOWN = 'down', } export class Server { - private readonly api: HomebridgeAPI; - private readonly pluginManager: PluginManager; - private readonly bridgeService: BridgeService; - private readonly ipcService: IpcService; - private readonly externalPortService: ExternalPortService; + private readonly api: HomebridgeAPI + private readonly pluginManager: PluginManager + private readonly bridgeService: BridgeService + private readonly ipcService: IpcService + private readonly externalPortService: ExternalPortService - private readonly config: HomebridgeConfig; + private readonly config: HomebridgeConfig // used to keep track of child bridges - private readonly childBridges: Map = new Map(); + private readonly childBridges: Map = new Map() // current server status - private serverStatus: ServerStatus = ServerStatus.PENDING; + private serverStatus: ServerStatus = ServerStatus.PENDING constructor( private options: HomebridgeOptions = {}, ) { - this.config = Server.loadConfig(); + this.config = Server.loadConfig() // object we feed to Plugins and BridgeService - this.api = new HomebridgeAPI(); - this.ipcService = new IpcService(); - this.externalPortService = new ExternalPortService(this.config.ports); + this.api = new HomebridgeAPI() + this.ipcService = new IpcService() + this.externalPortService = new ExternalPortService(this.config.ports) // set status to pending - this.setServerStatus(ServerStatus.PENDING); + this.setServerStatus(ServerStatus.PENDING) // create new plugin manager const pluginManagerOptions: PluginManagerOptions = { @@ -94,17 +97,17 @@ export class Server { disabledPlugins: this.config.disabledPlugins, customPluginPath: options.customPluginPath, strictPluginResolution: options.strictPluginResolution, - }; - this.pluginManager = new PluginManager(this.api, pluginManagerOptions); + } + this.pluginManager = new PluginManager(this.api, pluginManagerOptions) // create new bridge service const bridgeConfig: BridgeOptions = { cachedAccessoriesDir: User.cachedAccessoryPath(), - cachedAccessoriesItemName: "cachedAccessories", - }; + cachedAccessoriesItemName: 'cachedAccessories', + } // shallow copy the homebridge options to the bridge options object - Object.assign(bridgeConfig, this.options); + Object.assign(bridgeConfig, this.options) this.bridgeService = new BridgeService( this.api, @@ -113,22 +116,22 @@ export class Server { bridgeConfig, this.config.bridge, this.config, - ); + ) // watch bridge events to check when server is online this.bridgeService.bridge.on(AccessoryEventTypes.ADVERTISED, () => { - this.setServerStatus(ServerStatus.OK); - }); + this.setServerStatus(ServerStatus.OK) + }) // watch for the paired event to update the server status this.bridgeService.bridge.on(AccessoryEventTypes.PAIRED, () => { - this.setServerStatus(this.serverStatus); - }); + this.setServerStatus(this.serverStatus) + }) // watch for the unpaired event to update the server status this.bridgeService.bridge.on(AccessoryEventTypes.UNPAIRED, () => { - this.setServerStatus(this.serverStatus); - }); + this.setServerStatus(this.serverStatus) + }) } /** @@ -136,7 +139,7 @@ export class Server { * @param status */ private setServerStatus(status: ServerStatus) { - this.serverStatus = status; + this.serverStatus = status this.ipcService.sendMessage(IpcOutgoingEvent.SERVER_STATUS_UPDATE, { status: this.serverStatus, paired: this.bridgeService?.bridge?._accessoryInfo?.paired() ?? null, @@ -144,128 +147,120 @@ export class Server { name: this.bridgeService?.bridge?.displayName || this.config.bridge.name, username: this.config.bridge.username, pin: this.config.bridge.pin, - }); + }) } public async start(): Promise { if (this.config.bridge.disableIpc !== true) { - this.initializeIpcEventHandlers(); + this.initializeIpcEventHandlers() } - const promises: Promise[] = []; + const promises: Promise[] = [] // load the cached accessories - await this.bridgeService.loadCachedPlatformAccessoriesFromDisk(); + await this.bridgeService.loadCachedPlatformAccessoriesFromDisk() // initialize plugins - await this.pluginManager.initializeInstalledPlugins(); + await this.pluginManager.initializeInstalledPlugins() if (this.config.platforms.length > 0) { - promises.push(...this.loadPlatforms()); + promises.push(...this.loadPlatforms()) } if (this.config.accessories.length > 0) { - this.loadAccessories(); + this.loadAccessories() } // start child bridges for (const childBridge of this.childBridges.values()) { - childBridge.start(); + childBridge.start() } // restore cached accessories - this.bridgeService.restoreCachedPlatformAccessories(); + this.bridgeService.restoreCachedPlatformAccessories() - this.api.signalFinished(); + this.api.signalFinished() // wait for all platforms to publish their accessories before we publish the bridge - await Promise.all(promises).then(() => { - log.warn( - "\n\nNOTICE TO USERS AND PLUGIN DEVELOPERS" - + "\n> Homebridge v2.0 is on the way and brings some breaking changes to existing plugins.\n" - + "> Please visit the following link to learn more about the changes and how to prepare:\n" - + "> https://github.com/homebridge/homebridge/wiki/Updating-To-Homebridge-v2.0\n" - + "> Homebridge v2.0 will also drop support for Node.js v18, so now is a good time to update to v20 or v22.\n", - ); - this.publishBridge(); - }); + await Promise.all(promises) + .then(() => this.publishBridge()) } public teardown(): void { - this.bridgeService.teardown(); - this.setServerStatus(ServerStatus.DOWN); + this.bridgeService.teardown() + this.setServerStatus(ServerStatus.DOWN) } private publishBridge(): void { - this.bridgeService.publishBridge(); - this.printSetupInfo(this.config.bridge.pin); + this.bridgeService.publishBridge() + this.printSetupInfo(this.config.bridge.pin) } private static loadConfig(): HomebridgeConfig { // Look for the configuration file - const configPath = User.configPath(); + const configPath = User.configPath() const defaultBridge: BridgeConfiguration = { - name: "Homebridge", - username: "CC:22:3D:E3:CE:30", - pin: "031-45-154", - }; + name: 'Homebridge', + username: 'CC:22:3D:E3:CE:30', + pin: '031-45-154', + } - if (!fs.existsSync(configPath)) { - log.warn("config.json (%s) not found.", configPath); + if (!existsSync(configPath)) { + log.warn('config.json (%s) not found.', configPath) return { // return a default configuration bridge: defaultBridge, accessories: [], platforms: [], - }; + } } - let config: Partial; + let config: Partial try { - config = JSON.parse(fs.readFileSync(configPath, { encoding: "utf8" })); - } catch (err) { - log.error("There was a problem reading your config.json file."); - log.error("Please try pasting your config.json file here to validate it: https://jsonlint.com"); - log.error(""); - throw err; + config = JSON.parse(readFileSync(configPath, { encoding: 'utf8' })) + } catch (error: any) { + log.error('There was a problem reading your config.json file.') + log.error('Please try pasting your config.json file here to validate it: https://jsonlint.com') + log.error('') + throw error } if (config.ports !== undefined) { if (config.ports.start && config.ports.end) { if (config.ports.start > config.ports.end) { - log.error("Invalid port pool configuration. End should be greater than or equal to start."); - config.ports = undefined; + log.error('Invalid port pool configuration. End should be greater than or equal to start.') + config.ports = undefined } } else { - log.error("Invalid configuration for 'ports'. Missing 'start' and 'end' properties! Ignoring it!"); - config.ports = undefined; + log.error('Invalid configuration for \'ports\'. Missing \'start\' and \'end\' properties! Ignoring it!') + config.ports = undefined } } - const bridge: BridgeConfiguration = config.bridge || defaultBridge; - bridge.name = bridge.name || defaultBridge.name; - bridge.username = bridge.username || defaultBridge.username; - bridge.pin = bridge.pin || defaultBridge.pin; - config.bridge = bridge; + const bridge: BridgeConfiguration = config.bridge || defaultBridge + bridge.name = bridge.name || defaultBridge.name + bridge.username = bridge.username || defaultBridge.username + bridge.pin = bridge.pin || defaultBridge.pin + config.bridge = bridge - const username = config.bridge.username; - if (!mac.validMacAddress(username)) { - throw new Error(`Not a valid username: ${username}. Must be 6 pairs of colon-separated hexadecimal chars (A-F 0-9), like a MAC address.`); + const username = config.bridge.username + if (!validMacAddress(username)) { + throw new Error(`Not a valid username: ${username}. Must be 6 pairs of colon-separated hexadecimal chars (A-F 0-9), like a MAC address.`) } - config.accessories = config.accessories || []; - config.platforms = config.platforms || []; + config.accessories = config.accessories || [] + config.platforms = config.platforms || [] if (!Array.isArray(config.accessories)) { - log.error("Value provided for accessories must be an array[]"); - config.accessories = []; + log.error('Value provided for accessories must be an array[]') + config.accessories = [] } if (!Array.isArray(config.platforms)) { - log.error("Value provided for platforms must be an array[]"); - config.platforms = []; + log.error('Value provided for platforms must be an array[]') + config.platforms = [] } - log.info("Loaded config.json with %s accessories and %s platforms.", config.accessories.length, config.platforms.length); + log.info('Loaded config.json with %s accessories and %s platforms.', config.accessories.length, config.platforms.length) if (config.bridge.advertiser) { if (![ @@ -274,78 +269,78 @@ export class Server { MDNSAdvertiser.AVAHI, MDNSAdvertiser.RESOLVED, ].includes(config.bridge.advertiser)) { - config.bridge.advertiser = undefined; - log.error("Value provided in bridge.advertiser is not valid, reverting to platform default."); + config.bridge.advertiser = undefined + log.error('Value provided in bridge.advertiser is not valid, reverting to platform default.') } } else { - config.bridge.advertiser = undefined; + config.bridge.advertiser = undefined } - return config as HomebridgeConfig; + return config as HomebridgeConfig } private loadAccessories(): void { - log.info("Loading " + this.config.accessories.length + " accessories..."); + log.info(`Loading ${this.config.accessories.length} accessories...`) this.config.accessories.forEach((accessoryConfig, index) => { if (!accessoryConfig.accessory) { - log.warn("Your config.json contains an illegal accessory configuration object at position %d. " + - "Missing property 'accessory'. Skipping entry...", index + 1); // we rather count from 1 for the normal people? - return; + log.warn('Your config.json contains an illegal accessory configuration object at position %d. ' + + 'Missing property \'accessory\'. Skipping entry...', index + 1) // we rather count from 1 for the normal people? + return } - const accessoryIdentifier: AccessoryName | AccessoryIdentifier = accessoryConfig.accessory; - const displayName = accessoryConfig.name; + const accessoryIdentifier: AccessoryName | AccessoryIdentifier = accessoryConfig.accessory + const displayName = accessoryConfig.name if (!displayName) { - log.warn("Could not load accessory %s at position %d as it is missing the required 'name' property!", accessoryIdentifier, index + 1); - return; + log.warn('Could not load accessory %s at position %d as it is missing the required \'name\' property!', accessoryIdentifier, index + 1) + return } - let plugin: Plugin; - let constructor: AccessoryPluginConstructor; + let plugin: Plugin + let constructor: AccessoryPluginConstructor try { - plugin = this.pluginManager.getPluginForAccessory(accessoryIdentifier); - } catch (error) { - log.error(error.message); - return; + plugin = this.pluginManager.getPluginForAccessory(accessoryIdentifier) + } catch (error: any) { + log.error(error.message) + return } // check the plugin is not disabled if (plugin.disabled) { - log.warn(`Ignoring config for the accessory "${accessoryIdentifier}" in your config.json as the plugin "${plugin.getPluginIdentifier()}" has been disabled.`); - return; + log.warn(`Ignoring config for the accessory "${accessoryIdentifier}" in your config.json as the plugin "${plugin.getPluginIdentifier()}" has been disabled.`) + return } try { - constructor = plugin.getAccessoryConstructor(accessoryIdentifier); - } catch (error) { - log.error(`Error loading the accessory "${accessoryIdentifier}" requested in your config.json at position ${index + 1} - this is likely an issue with the "${plugin.getPluginIdentifier()}" plugin.`); - log.error(error); // error message contains more information and full stack trace - return; + constructor = plugin.getAccessoryConstructor(accessoryIdentifier) + } catch (error: any) { + log.error(`Error loading the accessory "${accessoryIdentifier}" requested in your config.json at position ${index + 1} - this is likely an issue with the "${plugin.getPluginIdentifier()}" plugin.`) + log.error(error) // error message contains more information and full stack trace + return } - const logger = Logger.withPrefix(displayName); - logger("Initializing %s accessory...", accessoryIdentifier); + const logger = Logger.withPrefix(displayName) + logger('Initializing %s accessory...', accessoryIdentifier) if (accessoryConfig._bridge) { // ensure the username is always uppercase - accessoryConfig._bridge.username = accessoryConfig._bridge.username.toUpperCase(); + accessoryConfig._bridge.username = accessoryConfig._bridge.username.toUpperCase() try { - this.validateChildBridgeConfig(PluginType.ACCESSORY, accessoryIdentifier, accessoryConfig._bridge); - } catch (error) { - log.error(error.message); - return; + this.validateChildBridgeConfig(PluginType.ACCESSORY, accessoryIdentifier, accessoryConfig._bridge) + } catch (error: any) { + log.error(error.message) + return } - let childBridge: ChildBridgeService; + let childBridge: ChildBridgeService if (this.childBridges.has(accessoryConfig._bridge.username)) { - childBridge = this.childBridges.get(accessoryConfig._bridge.username)!; - logger(`Adding to existing child bridge ${accessoryConfig._bridge.username}`); + childBridge = this.childBridges.get(accessoryConfig._bridge.username)! + logger(`Adding to existing child bridge ${accessoryConfig._bridge.username}`) } else { - logger(`Initializing child bridge ${accessoryConfig._bridge.username}`); + logger(`Initializing child bridge ${accessoryConfig._bridge.username}`) childBridge = new ChildBridgeService( PluginType.ACCESSORY, accessoryIdentifier, @@ -356,93 +351,92 @@ export class Server { this.api, this.ipcService, this.externalPortService, - ); + ) - this.childBridges.set(accessoryConfig._bridge.username, childBridge); + this.childBridges.set(accessoryConfig._bridge.username, childBridge) } // add config to child bridge service - childBridge.addConfig(accessoryConfig); + childBridge.addConfig(accessoryConfig) - return; + return } - const accessoryInstance: AccessoryPlugin = new constructor(logger, accessoryConfig, this.api); + const accessoryInstance: AccessoryPlugin = new constructor(logger, accessoryConfig, this.api) - //pass accessoryIdentifier for UUID generation, and optional parameter uuid_base which can be used instead of displayName for UUID generation - const accessory = this.bridgeService.createHAPAccessory(plugin, accessoryInstance, displayName, accessoryIdentifier, accessoryConfig.uuid_base); + // pass accessoryIdentifier for UUID generation, and optional parameter uuid_base which can be used instead of displayName for UUID generation + const accessory = this.bridgeService.createHAPAccessory(plugin, accessoryInstance, displayName, accessoryIdentifier, accessoryConfig.uuid_base) if (accessory) { try { - this.bridgeService.bridge.addBridgedAccessory(accessory); - } catch (e) { - logger.error(`Error loading the accessory "${accessoryIdentifier}" from "${plugin.getPluginIdentifier()}" requested in your config.json:`, e.message); - return; + this.bridgeService.bridge.addBridgedAccessory(accessory) + } catch (error: any) { + logger.error(`Error loading the accessory "${accessoryIdentifier}" from "${plugin.getPluginIdentifier()}" requested in your config.json:`, error.message) } } else { - logger.info("Accessory %s returned empty set of services; not adding it to the bridge.", accessoryIdentifier); + logger.info('Accessory %s returned empty set of services; not adding it to the bridge.', accessoryIdentifier) } - }); + }) } private loadPlatforms(): Promise[] { - log.info("Loading " + this.config.platforms.length + " platforms..."); + log.info(`Loading ${this.config.platforms.length} platforms...`) - const promises: Promise[] = []; + const promises: Promise[] = [] this.config.platforms.forEach((platformConfig, index) => { if (!platformConfig.platform) { - log.warn("Your config.json contains an illegal platform configuration object at position %d. " + - "Missing property 'platform'. Skipping entry...", index + 1); // we rather count from 1 for the normal people? - return; + log.warn('Your config.json contains an illegal platform configuration object at position %d. ' + + 'Missing property \'platform\'. Skipping entry...', index + 1) // we rather count from 1 for the normal people? + return } - const platformIdentifier: PlatformName | PlatformIdentifier = platformConfig.platform; - const displayName = platformConfig.name || platformIdentifier; + const platformIdentifier: PlatformName | PlatformIdentifier = platformConfig.platform + const displayName = platformConfig.name || platformIdentifier - let plugin: Plugin; - let constructor: PlatformPluginConstructor; + let plugin: Plugin + let constructor: PlatformPluginConstructor // do not load homebridge-config-ui-x when running in service mode - if (platformIdentifier === "config" && process.env.UIX_SERVICE_MODE === "1") { - return; + if (platformIdentifier === 'config' && process.env.UIX_SERVICE_MODE === '1') { + return } try { - plugin = this.pluginManager.getPluginForPlatform(platformIdentifier); - } catch (error) { - log.error(error.message); - return; + plugin = this.pluginManager.getPluginForPlatform(platformIdentifier) + } catch (error: any) { + log.error(error.message) + return } // check the plugin is not disabled if (plugin.disabled) { - log.warn(`Ignoring config for the platform "${platformIdentifier}" in your config.json as the plugin "${plugin.getPluginIdentifier()}" has been disabled.`); - return; + log.warn(`Ignoring config for the platform "${platformIdentifier}" in your config.json as the plugin "${plugin.getPluginIdentifier()}" has been disabled.`) + return } try { - constructor = plugin.getPlatformConstructor(platformIdentifier); - } catch (error) { - log.error(`Error loading the platform "${platformIdentifier}" requested in your config.json at position ${index + 1} - this is likely an issue with the "${plugin.getPluginIdentifier()}" plugin.`); - log.error(error); // error message contains more information and full stack trace - return; + constructor = plugin.getPlatformConstructor(platformIdentifier) + } catch (error: any) { + log.error(`Error loading the platform "${platformIdentifier}" requested in your config.json at position ${index + 1} - this is likely an issue with the "${plugin.getPluginIdentifier()}" plugin.`) + log.error(error) // error message contains more information and full stack trace + return } - const logger = Logger.withPrefix(displayName); - logger("Initializing %s platform...", platformIdentifier); + const logger = Logger.withPrefix(displayName) + logger('Initializing %s platform...', platformIdentifier) if (platformConfig._bridge) { // ensure the username is always uppercase - platformConfig._bridge.username = platformConfig._bridge.username.toUpperCase(); + platformConfig._bridge.username = platformConfig._bridge.username.toUpperCase() try { - this.validateChildBridgeConfig(PluginType.PLATFORM, platformIdentifier, platformConfig._bridge); - } catch (error) { - log.error(error.message); - return; + this.validateChildBridgeConfig(PluginType.PLATFORM, platformIdentifier, platformConfig._bridge) + } catch (error: any) { + log.error(error.message) + return } - logger(`Initializing child bridge ${platformConfig._bridge.username}`); + logger(`Initializing child bridge ${platformConfig._bridge.username}`) const childBridge = new ChildBridgeService( PluginType.PLATFORM, platformIdentifier, @@ -453,63 +447,63 @@ export class Server { this.api, this.ipcService, this.externalPortService, - ); + ) - this.childBridges.set(platformConfig._bridge.username, childBridge); + this.childBridges.set(platformConfig._bridge.username, childBridge) // add config to child bridge service - childBridge.addConfig(platformConfig); - return; + childBridge.addConfig(platformConfig) + return } - const platform: PlatformPlugin = new constructor(logger, platformConfig, this.api); + const platform: PlatformPlugin = new constructor(logger, platformConfig, this.api) if (HomebridgeAPI.isDynamicPlatformPlugin(platform)) { - plugin.assignDynamicPlatform(platformIdentifier, platform); + plugin.assignDynamicPlatform(platformIdentifier, platform) } else if (HomebridgeAPI.isStaticPlatformPlugin(platform)) { // Plugin 1.0, load accessories - promises.push(this.bridgeService.loadPlatformAccessories(plugin, platform, platformIdentifier, logger)); + promises.push(this.bridgeService.loadPlatformAccessories(plugin, platform, platformIdentifier, logger)) } else { // otherwise it's a IndependentPlatformPlugin which doesn't expose any methods at all. // We just call the constructor and let it be enabled. } - }); + }) - return promises; + return promises } /** * Validate an external bridge config */ private validateChildBridgeConfig(type: PluginType, identifier: string, bridgeConfig: BridgeConfiguration): void { - if (!mac.validMacAddress(bridgeConfig.username)) { + if (!validMacAddress(bridgeConfig.username)) { throw new Error( - `Error loading the ${type} "${identifier}" requested in your config.json - ` + - `not a valid username in _bridge.username: "${bridgeConfig.username}". Must be 6 pairs of colon-separated hexadecimal chars (A-F 0-9), like a MAC address.`, - ); + `Error loading the ${type} "${identifier}" requested in your config.json - ` + + `not a valid username in _bridge.username: "${bridgeConfig.username}". Must be 6 pairs of colon-separated hexadecimal chars (A-F 0-9), like a MAC address.`, + ) } if (this.childBridges.has(bridgeConfig.username)) { - const childBridge = this.childBridges.get(bridgeConfig.username); + const childBridge = this.childBridges.get(bridgeConfig.username) if (type === PluginType.PLATFORM) { // only a single platform can exist on one child bridge throw new Error( - `Error loading the ${type} "${identifier}" requested in your config.json - ` + - `Duplicate username found in _bridge.username: "${bridgeConfig.username}". Each platform child bridge must have it's own unique username.`, - ); + `Error loading the ${type} "${identifier}" requested in your config.json - ` + + `Duplicate username found in _bridge.username: "${bridgeConfig.username}". Each platform child bridge must have it's own unique username.`, + ) } else if (childBridge?.identifier !== identifier) { // only accessories of the same type can be added to the same child bridge throw new Error( - `Error loading the ${type} "${identifier}" requested in your config.json - ` + - `Duplicate username found in _bridge.username: "${bridgeConfig.username}". You can only group accessories of the same type in a child bridge.`, - ); + `Error loading the ${type} "${identifier}" requested in your config.json - ` + + `Duplicate username found in _bridge.username: "${bridgeConfig.username}". You can only group accessories of the same type in a child bridge.`, + ) } } if (bridgeConfig.username === this.config.bridge.username.toUpperCase()) { throw new Error( - `Error loading the ${type} "${identifier}" requested in your config.json - ` + - `Username found in _bridge.username: "${bridgeConfig.username}" is the same as the main bridge. Each child bridge platform/accessory must have it's own unique username.`, - ); + `Error loading the ${type} "${identifier}" requested in your config.json - ` + + `Username found in _bridge.username: "${bridgeConfig.username}" is the same as the main bridge. Each child bridge platform/accessory must have it's own unique username.`, + ) } } @@ -518,58 +512,62 @@ export class Server { */ private initializeIpcEventHandlers() { // start ipc service - this.ipcService.start(); + this.ipcService.start() // handle restart child bridge event this.ipcService.on(IpcIncomingEvent.RESTART_CHILD_BRIDGE, (username) => { - if (typeof username === "string") { - const childBridge = this.childBridges.get(username.toUpperCase()); - childBridge?.restartChildBridge(); + // noinspection SuspiciousTypeOfGuard + if (typeof username === 'string') { + const childBridge = this.childBridges.get(username.toUpperCase()) + childBridge?.restartChildBridge() } - }); + }) // handle stop child bridge event this.ipcService.on(IpcIncomingEvent.STOP_CHILD_BRIDGE, (username) => { - if (typeof username === "string") { - const childBridge = this.childBridges.get(username.toUpperCase()); - childBridge?.stopChildBridge(); + // noinspection SuspiciousTypeOfGuard + if (typeof username === 'string') { + const childBridge = this.childBridges.get(username.toUpperCase()) + childBridge?.stopChildBridge() } - }); + }) // handle start child bridge event this.ipcService.on(IpcIncomingEvent.START_CHILD_BRIDGE, (username) => { - if (typeof username === "string") { - const childBridge = this.childBridges.get(username.toUpperCase()); - childBridge?.startChildBridge(); + // noinspection SuspiciousTypeOfGuard + if (typeof username === 'string') { + const childBridge = this.childBridges.get(username.toUpperCase()) + childBridge?.startChildBridge() } - }); + }) this.ipcService.on(IpcIncomingEvent.CHILD_BRIDGE_METADATA_REQUEST, () => { this.ipcService.sendMessage( IpcOutgoingEvent.CHILD_BRIDGE_METADATA_RESPONSE, Array.from(this.childBridges.values()).map(x => x.getMetadata()), - ); - }); + ) + }) } private printSetupInfo(pin: string): void { - console.log("Setup Payload:"); - console.log(this.bridgeService.bridge.setupURI()); - - if(!this.options.hideQRCode) { - console.log("Scan this code with your HomeKit app on your iOS device to pair with Homebridge:"); - qrcode.setErrorLevel("M"); // HAP specifies level M or higher for ECC - qrcode.generate(this.bridgeService.bridge.setupURI()); - console.log("Or enter this code with your HomeKit app on your iOS device to pair with Homebridge:"); + /* eslint-disable no-console */ + console.log('Setup Payload:') + console.log(this.bridgeService.bridge.setupURI()) + + if (!this.options.hideQRCode) { + console.log('Scan this code with your HomeKit app on your iOS device to pair with Homebridge:') + qrcode.setErrorLevel('M') // HAP specifies level M or higher for ECC + qrcode.generate(this.bridgeService.bridge.setupURI()) + console.log('Or enter this code with your HomeKit app on your iOS device to pair with Homebridge:') } else { - console.log("Enter this code with your HomeKit app on your iOS device to pair with Homebridge:"); + console.log('Enter this code with your HomeKit app on your iOS device to pair with Homebridge:') } - console.log(chalk.black.bgWhite(" ")); - console.log(chalk.black.bgWhite(" ┌────────────┐ ")); - console.log(chalk.black.bgWhite(" │ " + pin + " │ ")); - console.log(chalk.black.bgWhite(" └────────────┘ ")); - console.log(chalk.black.bgWhite(" ")); + console.log(chalk.black.bgWhite(' ')) + console.log(chalk.black.bgWhite(' ┌────────────┐ ')) + console.log(chalk.black.bgWhite(` │ ${pin} │ `)) + console.log(chalk.black.bgWhite(' └────────────┘ ')) + console.log(chalk.black.bgWhite(' ')) + /* eslint-enable no-console */ } - } diff --git a/src/storageService.ts b/src/storageService.ts index 985673d7f..1e9235181 100644 --- a/src/storageService.ts +++ b/src/storageService.ts @@ -1,5 +1,6 @@ -import * as path from "path"; -import * as fs from "fs-extra"; +import { resolve } from 'node:path' + +import fs from 'fs-extra' export class StorageService { constructor( @@ -7,48 +8,46 @@ export class StorageService { ) {} public initSync(): void { - return fs.ensureDirSync(this.baseDirectory); + return fs.ensureDirSync(this.baseDirectory) } public getItemSync(itemName: string): T | null { - const filePath = path.resolve(this.baseDirectory, itemName); + const filePath = resolve(this.baseDirectory, itemName) if (!fs.pathExistsSync(filePath)) { - return null; + return null } - return fs.readJsonSync(filePath); + return fs.readJsonSync(filePath) } public async getItem(itemName: string): Promise { - const filePath = path.resolve(this.baseDirectory, itemName); + const filePath = resolve(this.baseDirectory, itemName) if (!await fs.pathExists(filePath)) { - return null; + return null } - return await fs.readJson(filePath); + return await fs.readJson(filePath) } - // eslint-disable-next-line @typescript-eslint/no-explicit-any public setItemSync(itemName: string, data: Record | Array): void { - return fs.writeJsonSync(path.resolve(this.baseDirectory, itemName), data); + return fs.writeJsonSync(resolve(this.baseDirectory, itemName), data) } - // eslint-disable-next-line @typescript-eslint/no-explicit-any public setItem(itemName: string, data: Record | Array): Promise { - return fs.writeJson(path.resolve(this.baseDirectory, itemName), data); + return fs.writeJson(resolve(this.baseDirectory, itemName), data) } public copyItem(srcItemName: string, destItemName: string): Promise { - return fs.copyFile(path.resolve(this.baseDirectory, srcItemName), path.resolve(this.baseDirectory, destItemName)); + return fs.copyFile(resolve(this.baseDirectory, srcItemName), resolve(this.baseDirectory, destItemName)) } public copyItemSync(srcItemName: string, destItemName: string): void { - return fs.copyFileSync(path.resolve(this.baseDirectory, srcItemName), path.resolve(this.baseDirectory, destItemName)); + return fs.copyFileSync(resolve(this.baseDirectory, srcItemName), resolve(this.baseDirectory, destItemName)) } public removeItemSync(itemName: string): void { - return fs.removeSync(path.resolve(this.baseDirectory, itemName)); + return fs.removeSync(resolve(this.baseDirectory, itemName)) } -} \ No newline at end of file +} diff --git a/src/types/qrcode-terminal.d.ts b/src/types/qrcode-terminal.d.ts index 14055cd71..5f5419859 100644 --- a/src/types/qrcode-terminal.d.ts +++ b/src/types/qrcode-terminal.d.ts @@ -1,12 +1,10 @@ -declare module "qrcode-terminal" { - - export type GenerateOptions = { - small?: boolean; // default false +declare module 'qrcode-terminal' { + export interface GenerateOptions { + small?: boolean // default false } - export function generate(input: string, callback?: (output: string) => void): void; - export function generate(input: string, options: GenerateOptions, callback?: (output: string) => void): void; - - export function setErrorLevel(error: "L" | "M" | "Q" | "H"): void; + export function generate(input: string, callback?: (output: string) => void): void + export function generate(input: string, options: GenerateOptions, callback?: (output: string) => void): void + export function setErrorLevel(error: 'L' | 'M' | 'Q' | 'H'): void } diff --git a/src/user.spec.ts b/src/user.spec.ts index 0f7c7dbe8..5c67b328e 100644 --- a/src/user.spec.ts +++ b/src/user.spec.ts @@ -1,36 +1,37 @@ -import path from "path"; -import { User } from "./user"; +import { basename } from 'node:path' -describe("User", () => { // these tests are mainly here to ensure default locations won't get bricked in the future +import { describe, expect, it } from 'vitest' - describe("User.storagePath", () => { - it("should have valid default path", function() { - expect(path.basename(User.storagePath())).toEqual(".homebridge"); - }); - }); +import { User } from './user.js' - describe("User.cachedAccessoryPath", () => { - it("should have valid default path", function() { - expect(path.basename(User.cachedAccessoryPath())).toEqual("accessories"); - }); - }); +describe('user', () => { // these tests are mainly here to ensure default locations won't get bricked in the future + describe('user.storagePath', () => { + it('should have valid default path', () => { + expect(basename(User.storagePath())).toEqual('.homebridge') + }) + }) - describe("User.persistPath", () => { - it("should have valid default path", function() { - expect(path.basename(User.persistPath())).toEqual("persist"); - }); - }); + describe('user.cachedAccessoryPath', () => { + it('should have valid default path', () => { + expect(basename(User.cachedAccessoryPath())).toEqual('accessories') + }) + }) - describe("User.configPath", () => { - it("should have valid default path", function() { - expect(path.basename(User.configPath())).toEqual("config.json"); - }); - }); + describe('user.persistPath', () => { + it('should have valid default path', () => { + expect(basename(User.persistPath())).toEqual('persist') + }) + }) - describe("User.setStoragePath", () => { - it("should fail to be overwritten after paths were already accessed", function() { - expect(() => User.setStoragePath("otherDir")).toThrow(Error); - }); - }); + describe('user.configPath', () => { + it('should have valid default path', () => { + expect(basename(User.configPath())).toEqual('config.json') + }) + }) -}); + describe('user.setStoragePath', () => { + it('should fail to be overwritten after paths were already accessed', () => { + expect(() => User.setStoragePath('otherDir')).toThrow(Error) + }) + }) +}) diff --git a/src/user.ts b/src/user.ts index 87b2a47cf..779bc3336 100644 --- a/src/user.ts +++ b/src/user.ts @@ -1,38 +1,36 @@ -import os from "os"; -import path from "path"; +import { homedir } from 'node:os' +import { join, resolve } from 'node:path' /** * Manages user settings and storage locations. */ export class User { - - private static customStoragePath?: string; - private static storageAccessed = false; + private static customStoragePath?: string + private static storageAccessed = false static configPath(): string { - return path.join(User.storagePath(), "config.json"); + return join(User.storagePath(), 'config.json') } static persistPath(): string { - return path.join(User.storagePath(), "persist"); // hap-nodejs data is stored here + return join(User.storagePath(), 'persist') // hap-nodejs data is stored here } static cachedAccessoryPath(): string { - return path.join(User.storagePath(), "accessories"); + return join(User.storagePath(), 'accessories') } static storagePath(): string { - User.storageAccessed = true; + User.storageAccessed = true - return User.customStoragePath ? User.customStoragePath : path.join(os.homedir(), ".homebridge"); + return User.customStoragePath ? User.customStoragePath : join(homedir(), '.homebridge') } public static setStoragePath(...storagePathSegments: string[]): void { if (User.storageAccessed) { - throw new Error("Storage path was already accessed and cannot be changed anymore. Try initializing your custom storage path earlier!"); + throw new Error('Storage path was already accessed and cannot be changed anymore. Try initializing your custom storage path earlier!') } - User.customStoragePath = path.resolve(...storagePathSegments); + User.customStoragePath = resolve(...storagePathSegments) } - } diff --git a/src/util/mac.spec.ts b/src/util/mac.spec.ts index 1fe51c6af..96d010751 100644 --- a/src/util/mac.spec.ts +++ b/src/util/mac.spec.ts @@ -1,37 +1,41 @@ -import crypto from "crypto"; -import { generate, validMacAddress } from "./mac"; +import { randomBytes } from 'node:crypto' -describe("mac", () => { - describe("validMacAddress", () => { - it("should verify a valid mac address", function() { - expect(validMacAddress("61:67:0F:6E:B0:48")).toBeTruthy(); - }); +import { describe, expect, it } from 'vitest' - it("should reject a lower case valid mac address", function() { - const macAddress = "0E:80:9C:B4:E4:C5"; - expect(validMacAddress(macAddress)).toBeTruthy(); - expect(validMacAddress(macAddress.toLowerCase())).toBeFalsy(); - }); +import { generate, validMacAddress } from './mac.js' - it("should reject too short mac address", function() { - expect(validMacAddress("25:22:04:2B:3A")).toBeFalsy(); - }); +describe('mac', () => { + describe('validMacAddress', () => { + it('should verify a valid mac address', () => { + expect(validMacAddress('61:67:0F:6E:B0:48')).toBeTruthy() + }) - it("should reject too long mac address", function() { - expect(validMacAddress("7F:9A:58:0E:87:23:AA")).toBeFalsy(); - }); - }); + it('should reject a lower case valid mac address', () => { + const macAddress = '0E:80:9C:B4:E4:C5' + expect(validMacAddress(macAddress)).toBeTruthy() + expect(validMacAddress(macAddress.toLowerCase())).toBeFalsy() + }) - describe("generate", () => { - it("should generate a valid mac address", function() { - const seed = crypto.randomBytes(4); - const generated = generate(crypto.randomBytes(4)); + it('should reject too short mac address', () => { + expect(validMacAddress('25:22:04:2B:3A')).toBeFalsy() + }) + + it('should reject too long mac address', () => { + expect(validMacAddress('7F:9A:58:0E:87:23:AA')).toBeFalsy() + }) + }) + + describe('generate', () => { + it('should generate a valid mac address', () => { + const seed = randomBytes(4) + const generated = generate(randomBytes(4)) try { - expect(validMacAddress(generated)).toBeTruthy(); - } catch (error) { - console.log(`Invalid mac address generated '${generated}' for seed '${seed.toString("hex")}'`); - throw error; + expect(validMacAddress(generated)).toBeTruthy() + } catch (error: any) { + // eslint-disable-next-line no-console + console.log(`Invalid mac address generated '${generated}' for seed '${seed.toString('hex')}'`) + throw error } - }); - }); -}); + }) + }) +}) diff --git a/src/util/mac.ts b/src/util/mac.ts index 8164d3d28..def8bf04c 100644 --- a/src/util/mac.ts +++ b/src/util/mac.ts @@ -1,18 +1,21 @@ -import crypto from "crypto"; +import type { Buffer } from 'node:buffer' -const validMac = /^([0-9A-F]{2}:){5}([0-9A-F]{2})$/; +/* global NodeJS */ +import { createHash } from 'node:crypto' -export type MacAddress = string; +const validMac = /^(?:[0-9A-F]{2}:){5}[0-9A-F]{2}$/ + +export type MacAddress = string export function validMacAddress(address: string): boolean { - return validMac.test(address); + return validMac.test(address) } export function generate(data: string | Buffer | NodeJS.TypedArray | DataView): MacAddress { - const sha1sum = crypto.createHash("sha1"); - sha1sum.update(data); - const s = sha1sum.digest("hex"); + const sha1sum = createHash('sha1') + sha1sum.update(data) + const s = sha1sum.digest('hex') - let i = 0; - return "xx:xx:xx:xx:xx:xx".replace(/x/g, () => s[i++]).toUpperCase(); + let i = 0 + return 'xx:xx:xx:xx:xx:xx'.replace(/x/g, () => s[i++]).toUpperCase() } diff --git a/src/version.spec.ts b/src/version.spec.ts index 27946c68a..0704012ee 100644 --- a/src/version.spec.ts +++ b/src/version.spec.ts @@ -1,59 +1,24 @@ -import fs, { PathLike } from "fs"; -import path from "path"; -import getVersion, { getRequiredNodeVersion } from "./version"; - -describe("version", () => { - describe("getVersion", () => { - it("should read correct version from package.json", function() { - const expectedVersion = "1.1.28"; - const expectedPath = path.resolve(__dirname, "../package.json"); - - const mock = jest.spyOn(fs, "readFileSync"); - // mock only once, otherwise we break the whole test runner - mock.mockImplementationOnce((path: PathLike | number, options?: { encoding?: string | null; flag?: string } | string | null) => { - expect(path).toBe(expectedPath); - expect(options).toBeDefined(); - expect(typeof options).toBe("object"); - const opt = options as {encoding: string}; - expect(opt.encoding).toBe("utf8"); - - const fakeJson = { - version: expectedVersion, - }; - - return JSON.stringify(fakeJson, null, 4); // pretty print - }); - - const version = getVersion(); - expect(version).toBe(expectedVersion); - }); - }); - - describe("getRequiredNodeVersion", () => { - it("should read correct node version from package.json", function() { - const expectedVersion = ">=10.17.0"; - const expectedPath = path.resolve(__dirname, "../package.json"); - - const mock = jest.spyOn(fs, "readFileSync"); - // mock only once, otherwise we break the whole test runner - mock.mockImplementationOnce((path: PathLike | number, options?: { encoding?: string | null; flag?: string } | string | null) => { - expect(path).toBe(expectedPath); - expect(options).toBeDefined(); - expect(typeof options).toBe("object"); - const opt = options as {encoding: string}; - expect(opt.encoding).toBe("utf8"); - - const fakeJson = { - engines: { - node: expectedVersion, - }, - }; - - return JSON.stringify(fakeJson, null, 4); // pretty print - }); - - const version = getRequiredNodeVersion(); - expect(version).toBe(expectedVersion); - }); - }); -}); +import { resolve } from 'node:path' + +import { readJsonSync } from 'fs-extra' +import { describe, expect, it } from 'vitest' + +import getVersion, { getRequiredNodeVersion } from './version.js' + +const realPackageJson = readJsonSync(resolve(__dirname, '../package.json')) + +describe('version', () => { + describe('getVersion', () => { + it('should read correct version from package.json', () => { + const version = getVersion() + expect(version).toBe(realPackageJson.version) + }) + }) + + describe('getRequiredNodeVersion', () => { + it('should read correct node version from package.json', () => { + const version = getRequiredNodeVersion() + expect(version).toBe(realPackageJson.engines.node) + }) + }) +}) diff --git a/src/version.ts b/src/version.ts index 78959037d..818f7a362 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1,16 +1,19 @@ -import fs from "fs"; -import path from "path"; +import { readFileSync } from 'node:fs' +import { dirname, join } from 'node:path' +import { fileURLToPath } from 'node:url' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = dirname(__filename) -// eslint-disable-next-line @typescript-eslint/no-explicit-any function loadPackageJson(): any { - const packageJSONPath = path.join(__dirname, "../package.json"); - return JSON.parse(fs.readFileSync(packageJSONPath, { encoding: "utf8" })); + const packageJSONPath = join(__dirname, '../package.json') + return JSON.parse(readFileSync(packageJSONPath, { encoding: 'utf8' })) } export default function getVersion(): string { - return loadPackageJson().version; + return loadPackageJson().version } export function getRequiredNodeVersion(): string { - return loadPackageJson().engines.node; + return loadPackageJson().engines.node } diff --git a/tsconfig.json b/tsconfig.json index e6937dda1..a902743ed 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,27 +1,20 @@ { "compilerOptions": { - "target": "ES2022", - "module": "commonjs", + "target": "ESNext", "lib": [ - "es2015", - "es2016", - "es2017", - "es2018", - "es2019", - "es2020", - "es2021", - "es2022" + "ESNext" ], + "rootDir": "./src", + "module": "ESNext", + "moduleResolution": "node", + "strict": true, "declaration": true, "declarationMap": true, + "outDir": "./dist", + "preserveConstEnums": true, "sourceMap": true, - "outDir": "./lib", - "rootDir": "./src", - "strict": true, "esModuleInterop": true, - "preserveConstEnums": true, - "skipLibCheck": true, - "useUnknownInCatchVariables": false + "skipLibCheck": true }, "include": [ "src/" diff --git a/vitest.config.js b/vitest.config.js new file mode 100644 index 000000000..1ce24f9ca --- /dev/null +++ b/vitest.config.js @@ -0,0 +1,11 @@ +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + test: { + coverage: { + include: ['src/**'], + }, + pool: 'threads', + testTimeout: 10000, + }, +}) From 4a1e19748ad564ca4b2df0d992aa218370e3cd16 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Sun, 8 Jun 2025 00:52:47 +0100 Subject: [PATCH 3/4] remove deprecated `--remove-orphans` flag --- CHANGELOG.md | 4 ++++ src/bridgeService.ts | 2 -- src/cli.ts | 4 ---- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d201fb190..46ba7792d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,10 @@ All notable changes to `homebridge` will be documented in this file. This projec - migrate from `jest` to `vitest` for testing - ⚠️ drop support for node `v18` +### Removed + +- remove deprecated `--remove-orphans` flag + ### Homebridge Dependencies - `hap-nodejs` @ `v2.0.0-beta` diff --git a/src/bridgeService.ts b/src/bridgeService.ts index 53028ccb7..b5ee0813d 100644 --- a/src/bridgeService.ts +++ b/src/bridgeService.ts @@ -192,7 +192,6 @@ export class BridgeService { log.success('Homebridge v%s (HAP v%s) (%s) is running on port %s.', getVersion(), HAPLibraryVersion(), bridgeConfig.name, port) }) - // noinspection JSDeprecatedSymbols const publishInfo: PublishInfo = { username: bridgeConfig.username, port: bridgeConfig.port, @@ -434,7 +433,6 @@ export class BridgeService { log.info('Please add [%s] manually in Home app. Setup Code: %s', hapAccessory.displayName, accessoryPin) }) - // noinspection JSDeprecatedSymbols const publishInfo: PublishInfo = { username: advertiseAddress, pincode: accessoryPin, diff --git a/src/cli.ts b/src/cli.ts index a3c9b9791..f17c4bc16 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -47,10 +47,6 @@ export default function cli(): void { .option('-I, --insecure', 'allow unauthenticated requests (for easier hacking)', () => insecureAccess = true) .option('-P, --plugin-path [path]', 'look for plugins installed at [path] as well as the default locations ([path] can also point to a single plugin)', path => customPluginPath = path) .option('-Q, --no-qrcode', 'do not issue QRcode in logging', () => hideQRCode = true) - .option('-R, --remove-orphans', 'remove cached accessories for which plugin is not loaded (deprecated)', () => { - console.warn('The cli option \'-R\' or \'--remove-orphans\' is deprecated and has no effect anymore. ' - + 'Removing orphans is now the default behavior and can be turned off by supplying \'-K\' or \'--keep-orphans\'.') - }) .option('-K, --keep-orphans', 'keep cached accessories for which the associated plugin is not loaded', () => keepOrphans = true) .option('-T, --no-timestamp', 'do not issue timestamps in logging', () => noLogTimestamps = true) .option('-U, --user-storage-path [path]', 'look for homebridge user files at [path] instead of the default location (~/.homebridge)', path => customStoragePath = path) From f8c552e3ac8515072687b54dc3ff88b07c638b04 Mon Sep 17 00:00:00 2001 From: Ben <43026681+bwp91@users.noreply.github.com> Date: Sun, 8 Jun 2025 01:11:34 +0100 Subject: [PATCH 4/4] set debug `-D` setting per child bridge --- CHANGELOG.md | 4 ++++ src/bridgeService.ts | 1 + src/childBridgeService.ts | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 46ba7792d..28ab92463 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,10 @@ All notable changes to `homebridge` will be documented in this file. This projec - Please visit the following link to learn more about the changes and how to prepare: - [Updating-To-Homebridge-v2.0](https://github.com/homebridge/homebridge/wiki/Updating-To-Homebridge-v2.0) +### Added + +- set debug `-D` setting per child bridge + ### Changed - Address legacy deprecation cleanup (#3648) (@hjdhjd) diff --git a/src/bridgeService.ts b/src/bridgeService.ts index b5ee0813d..a89b43591 100644 --- a/src/bridgeService.ts +++ b/src/bridgeService.ts @@ -61,6 +61,7 @@ export interface BridgeConfiguration { disableIpc?: boolean firmwareRevision?: string serialNumber?: string + debugModeEnabled?: boolean env?: { DEBUG?: string NODE_OPTIONS?: string diff --git a/src/childBridgeService.ts b/src/childBridgeService.ts index ac92411e0..603daa28f 100644 --- a/src/childBridgeService.ts +++ b/src/childBridgeService.ts @@ -336,7 +336,7 @@ export class ChildBridgeService { * These will be passed through to the forked process */ private setProcessFlags(): void { - if (this.homebridgeOptions.debugModeEnabled) { + if (this.bridgeConfig.debugModeEnabled) { this.args.push('-D') }