diff --git a/.eslintrc.common.cjs b/.eslintrc.common.cjs deleted file mode 100644 index 275db296..00000000 --- a/.eslintrc.common.cjs +++ /dev/null @@ -1,31 +0,0 @@ -module.exports = { - root: true, - env: { - es2021: true, - }, - extends: [ - "plugin:@typescript-eslint/eslint-recommended", - "plugin:@typescript-eslint/recommended-type-checked", - ], - plugins: ["@typescript-eslint", "import"], - ignorePatterns: ["/.eslintrc.cjs", "/lib", "/dist"], - rules: { - "no-console": "warn", - "@typescript-eslint/prefer-nullish-coalescing": "error", - curly: ["warn", "multi-line", "consistent"], - "spaced-comment": ["warn", "always", { markers: ["/"] }], - "no-debugger": "warn", - "@typescript-eslint/no-non-null-assertion": "error", - "import/extensions": [ - "error", - "always", - { - js: "ignorePackages", - jsx: "never", - ts: "never", - tsx: "never", - }, - ], - "@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }], - }, -}; diff --git a/demo/.eslintrc.cjs b/demo/.eslintrc.cjs deleted file mode 100644 index 27c710b8..00000000 --- a/demo/.eslintrc.cjs +++ /dev/null @@ -1,29 +0,0 @@ -module.exports = { - env: { es2020: true }, - parser: "@typescript-eslint/parser", - parserOptions: { - ecmaVersion: "latest", - sourceType: "module", - ecmaFeatures: { - jsx: true, - }, - project: ["tsconfig.json", "tsconfig.node.json"], - tsconfigRootDir: __dirname, - }, - plugins: ["react", "react-hooks", "react-refresh"], - extends: [ - "../.eslintrc.common.cjs", - "plugin:react/recommended", - "plugin:react/jsx-runtime", - "plugin:react-hooks/recommended", - ], - ignorePatterns: ["public/*"], - rules: { - "import/extensions": "off", - }, - settings: { - react: { - version: "detect", - }, - }, -}; diff --git a/demo/eslint.config.js b/demo/eslint.config.js new file mode 100644 index 00000000..43ad213e --- /dev/null +++ b/demo/eslint.config.js @@ -0,0 +1,35 @@ +// @ts-check + +import { CommonConfig } from "../eslint.common.config.js"; +import tsEslint from "typescript-eslint"; +import reactRefresh from "eslint-plugin-react-refresh"; +import reactHooks from "eslint-plugin-react-hooks"; +import reactPlugin from "eslint-plugin-react"; + +export default tsEslint.config( + ...CommonConfig, + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error + reactPlugin.configs.flat?.recommended, // This is not a plugin object, but a shareable config object + reactPlugin.configs.flat?.["jsx-runtime"], // Add this if you are using React 17+ + { + plugins: { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + "react-hooks": reactHooks, + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + "react-refresh": reactRefresh, + }, + rules: { + .../** @type {Record} */ ( + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + reactHooks.configs.recommended.rules + ), + "import/extensions": "off", + }, + settings: { + react: { + version: "detect", + }, + }, + }, +); diff --git a/demo/package.json b/demo/package.json index a6e8f309..8ec2b6be 100644 --- a/demo/package.json +++ b/demo/package.json @@ -6,7 +6,7 @@ "scripts": { "dev": "vite", "build": "vite build", - "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", + "lint": "eslint src --report-unused-disable-directives --max-warnings 0", "preview": "vite preview", "prettier": "prettier --write .", "type-check": "npx tsc --noEmit", diff --git a/demo/src/App.tsx b/demo/src/App.tsx index 1ed66282..dec425f9 100644 --- a/demo/src/App.tsx +++ b/demo/src/App.tsx @@ -1,7 +1,7 @@ import "./app.css"; import { P2PVideoDemo } from "p2p-media-loader-demo"; -function App() { +export function App() { return ( ); } - -export default App; diff --git a/demo/src/main.tsx b/demo/src/main.tsx index 2be325ed..2a5307a5 100644 --- a/demo/src/main.tsx +++ b/demo/src/main.tsx @@ -1,8 +1,9 @@ import React from "react"; import ReactDOM from "react-dom/client"; -import App from "./App"; +import { App } from "./App"; -ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( +// eslint-disable-next-line @typescript-eslint/no-non-null-assertion +ReactDOM.createRoot(document.getElementById("root")!).render( , diff --git a/demo/tsconfig.node.json b/demo/tsconfig.node.json index 89e24dbf..9f46520a 100644 --- a/demo/tsconfig.node.json +++ b/demo/tsconfig.node.json @@ -4,5 +4,5 @@ "module": "NodeNext", "moduleResolution": "NodeNext" }, - "include": ["vite.config.ts"] + "include": ["vite.config.ts", "eslint.config.js"] } diff --git a/eslint.common.config.js b/eslint.common.config.js new file mode 100644 index 00000000..2db9c5fa --- /dev/null +++ b/eslint.common.config.js @@ -0,0 +1,82 @@ +// @ts-check + +import globals from "globals"; +import eslint from "@eslint/js"; +import tsEslint from "typescript-eslint"; +import { flatConfigs as importPlugin } from "eslint-plugin-import"; + +export const CommonConfig = + /** @type {(typeof tsEslint.configs.eslintRecommended)[]} */ ([ + eslint.configs.recommended, + importPlugin.recommended, + tsEslint.configs.eslintRecommended, + ...tsEslint.configs.strictTypeChecked, + ...tsEslint.configs.stylisticTypeChecked, + { + languageOptions: { + globals: { + ...globals.browser, + }, + + ecmaVersion: 2022, + sourceType: "module", + + parserOptions: { + project: ["tsconfig.json", "tsconfig.node.json"], + }, + }, + + rules: { + "@typescript-eslint/consistent-type-definitions": "off", + "@typescript-eslint/no-unused-vars": [ + "warn", + { argsIgnorePattern: "^_" }, + ], + "@typescript-eslint/restrict-template-expressions": [ + "error", + { allowNumber: true }, + ], + "@typescript-eslint/no-confusing-void-expression": [ + "error", + { ignoreArrowShorthand: true }, + ], + "@typescript-eslint/no-unnecessary-condition": [ + "error", + { allowConstantLoopConditions: true }, + ], + + "no-var": "error", + "no-alert": "warn", + "prefer-const": "error", + "prefer-spread": "error", + "no-multi-assign": "error", + "prefer-template": "error", + "object-shorthand": "error", + "no-nested-ternary": "error", + "no-array-constructor": "error", + "prefer-object-spread": "error", + "prefer-arrow-callback": "error", + "prefer-destructuring": ["error", { object: true, array: false }], + "no-console": "warn", + curly: ["warn", "multi-line", "consistent"], + "no-debugger": "warn", + "spaced-comment": ["warn", "always", { markers: ["/"] }], + + "import/no-unresolved": "off", + "import/named": "off", + "import/no-named-as-default": "off", + "import/namespace": "off", + "import/no-named-as-default-member": "off", + "import/extensions": [ + "error", + "always", + { + js: "ignorePackages", + jsx: "never", + ts: "never", + tsx: "never", + }, + ], + }, + }, + ]); diff --git a/package.json b/package.json index 77e0d6a1..0e48067d 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "p2p-media-loader", "version": "1.0.0", "private": true, + "type": "module", "scripts": { "build": "pnpm --recursive build", "build:es": "pnpm --filter './packages/**' build:es", @@ -17,8 +18,10 @@ "create-doc": "pnpm typedoc" }, "devDependencies": { - "eslint": "^8.57.1", + "@types/eslint__js": "^8.42.3", + "eslint": "^9.14.0", "eslint-plugin-import": "^2.31.0", + "globals": "^15.12.0", "prettier": "^3.3.3", "rimraf": "^6.0.1", "typedoc": "^0.26.11", diff --git a/packages/p2p-media-loader-core/.eslintrc.cjs b/packages/p2p-media-loader-core/.eslintrc.cjs deleted file mode 100644 index 3b4d6c85..00000000 --- a/packages/p2p-media-loader-core/.eslintrc.cjs +++ /dev/null @@ -1,12 +0,0 @@ -module.exports = { - root: true, - extends: ["../../.eslintrc.common.cjs"], - parser: "@typescript-eslint/parser", - parserOptions: { - tsconfigRootDir: __dirname, - project: ["tsconfig.json", "tsconfig.node.json"], - ecmaVersion: "latest", - sourceType: "module", - }, - ignorePatterns: ["test/**/*"], -}; diff --git a/packages/p2p-media-loader-core/eslint.config.js b/packages/p2p-media-loader-core/eslint.config.js new file mode 100644 index 00000000..9ebad9c7 --- /dev/null +++ b/packages/p2p-media-loader-core/eslint.config.js @@ -0,0 +1,6 @@ +// @ts-check + +import { CommonConfig } from "../../eslint.common.config.js"; +import tsEslint from "typescript-eslint"; + +export default tsEslint.config(...CommonConfig); diff --git a/packages/p2p-media-loader-core/package.json b/packages/p2p-media-loader-core/package.json index 926f6e91..ace97c40 100644 --- a/packages/p2p-media-loader-core/package.json +++ b/packages/p2p-media-loader-core/package.json @@ -47,7 +47,7 @@ "build:esm-min": "vite build --mode esm-min", "build:es": "tsc", "prettier": "prettier --write .", - "lint": "eslint . --ext .ts --report-unused-disable-directives --max-warnings 0", + "lint": "eslint src --report-unused-disable-directives --max-warnings 0", "clean": "rimraf lib dist build p2p-media-loader-core-*.tgz", "clean-with-modules": "rimraf node_modules && pnpm clean", "type-check": "npx tsc --noEmit", diff --git a/packages/p2p-media-loader-core/src/core.ts b/packages/p2p-media-loader-core/src/core.ts index 54aad8a8..e0064cdd 100644 --- a/packages/p2p-media-loader-core/src/core.ts +++ b/packages/p2p-media-loader-core/src/core.ts @@ -112,13 +112,13 @@ export class Core { this.mainStreamConfig = mergeAndFilterConfig({ defaultConfig: Core.DEFAULT_STREAM_CONFIG, baseConfig: filteredConfig, - specificStreamConfig: filteredConfig?.mainStream, + specificStreamConfig: filteredConfig.mainStream, }); this.secondaryStreamConfig = mergeAndFilterConfig({ defaultConfig: Core.DEFAULT_STREAM_CONFIG, baseConfig: filteredConfig, - specificStreamConfig: filteredConfig?.secondaryStream, + specificStreamConfig: filteredConfig.secondaryStream, }); } @@ -381,7 +381,7 @@ export class Core { private async initializeSegmentStorage() { if (this.segmentStorage) return; - const isLive = this.streamDetails.isLive; + const { isLive } = this.streamDetails; const createCustomStorage = this.commonCoreConfig.customSegmentStorageFactory; diff --git a/packages/p2p-media-loader-core/src/http-loader.ts b/packages/p2p-media-loader-core/src/http-loader.ts index a7190bd6..a8d9038c 100644 --- a/packages/p2p-media-loader-core/src/http-loader.ts +++ b/packages/p2p-media-loader-core/src/http-loader.ts @@ -1,9 +1,13 @@ -import { CoreConfig, CoreEventMap } from "./types.js"; +import { + CoreConfig, + CoreEventMap, + RequestError, + HttpRequestErrorType, +} from "./types.js"; import { Request as SegmentRequest, RequestControls, } from "./requests/request.js"; -import { RequestError, HttpRequestErrorType } from "./types.js"; import { EventTarget } from "./utils/event-target.js"; type HttpConfig = Pick< @@ -191,10 +195,10 @@ async function* readStream( } } +const rangeHeaderRegex = /^bytes (?:(?:(\d+)|)-(?:(\d+)|)|\*)\/(?:(\d+)|\*)$/; + function parseContentRangeHeader(headerValue: string) { - const match = headerValue - .trim() - .match(/^bytes (?:(?:(\d+)|)-(?:(\d+)|)|\*)\/(?:(\d+)|\*)$/); + const match = rangeHeaderRegex.exec(headerValue.trim()); if (!match) return; const [, from, to, total] = match; diff --git a/packages/p2p-media-loader-core/src/hybrid-loader.ts b/packages/p2p-media-loader-core/src/hybrid-loader.ts index 069a1bbb..e703bb81 100644 --- a/packages/p2p-media-loader-core/src/hybrid-loader.ts +++ b/packages/p2p-media-loader-core/src/hybrid-loader.ts @@ -59,10 +59,6 @@ export class HybridLoader { this.eventTarget, ); - if (!this.segmentStorage) { - throw new Error("Segment storage is not initialized."); - } - this.p2pLoaders = new P2PLoadersContainer( this.streamManifestUrl, this.lastRequestedSegment.stream, @@ -193,7 +189,7 @@ export class HybridLoader { } break; - case "succeed": + case "succeed": { if (!request.data || !type) break; if (type === "http") { this.p2pLoaders.currentLoader.broadcastAnnouncement(); @@ -221,7 +217,7 @@ export class HybridLoader { this.streamDetails.isLive, ); break; - + } case "failed": if (type === "http" && !isHandledByProcessQueue) { this.p2pLoaders.currentLoader.broadcastAnnouncement(); @@ -347,11 +343,14 @@ export class HybridLoader { if (this.requests.executingP2PCount < simultaneousP2PDownloads) { this.loadThroughP2P(segment); } else if ( - this.p2pLoaders.currentLoader.isSegmentLoadedBySomeone(segment) && - this.abortLastP2PLoadingInQueueAfterItem(queue, segment) && - this.requests.executingP2PCount < simultaneousP2PDownloads + this.p2pLoaders.currentLoader.isSegmentLoadedBySomeone(segment) ) { - this.loadThroughP2P(segment); + if ( + this.abortLastP2PLoadingInQueueAfterItem(queue, segment) && + this.requests.executingP2PCount < simultaneousP2PDownloads + ) { + this.loadThroughP2P(segment); + } } } } @@ -424,7 +423,7 @@ export class HybridLoader { request && (request.status === "loading" || request.status === "succeed" || - (request.failedAttempts.httpAttemptsCount ?? 0) >= httpErrorRetries) + request.failedAttempts.httpAttemptsCount >= httpErrorRetries) ) { continue; } @@ -543,7 +542,7 @@ export class HybridLoader { queue, queueSegmentIds, maxPossibleLength, - alreadyLoadedCount: alreadyLoadedCount, + alreadyLoadedCount, queueDownloadRatio: maxPossibleLength !== 0 ? alreadyLoadedCount / maxPossibleLength : 0, }; @@ -600,7 +599,7 @@ export class HybridLoader { this.engineRequest?.markAsShouldBeStartedImmediately(); } this.segmentStorage.onPlaybackUpdated(position, rate); - void this.requestProcessQueueMicrotask(isPositionSignificantlyChanged); + this.requestProcessQueueMicrotask(isPositionSignificantlyChanged); } updateStream(stream: StreamWithSegments) { diff --git a/packages/p2p-media-loader-core/src/p2p/commands/binary-command-creator.ts b/packages/p2p-media-loader-core/src/p2p/commands/binary-command-creator.ts index c45aeaeb..fefcf60b 100644 --- a/packages/p2p-media-loader-core/src/p2p/commands/binary-command-creator.ts +++ b/packages/p2p-media-loader-core/src/p2p/commands/binary-command-creator.ts @@ -11,7 +11,7 @@ const endFrames = [commandFrameEnd, commandDivFrameEnd]; const commandFramesLength = commandFrameStart.length + commandFrameEnd.length; export function isCommandChunk(buffer: Uint8Array) { - const length = commandFrameStart.length; + const { length } = commandFrameStart; const bufferEndingToCompare = buffer.slice(-length); return ( startFrames.some((frame) => @@ -154,8 +154,7 @@ export class BinaryCommandCreator { export function deserializeCommand(bytes: Uint8Array): PeerCommand { const [commandCode] = bytes; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const deserializedCommand: { [key: string]: any } = { + const deserializedCommand: Record = { c: commandCode, }; diff --git a/packages/p2p-media-loader-core/src/p2p/commands/binary-serialization.ts b/packages/p2p-media-loader-core/src/p2p/commands/binary-serialization.ts index 2456e6fd..ee0bd4c0 100644 --- a/packages/p2p-media-loader-core/src/p2p/commands/binary-serialization.ts +++ b/packages/p2p-media-loader-core/src/p2p/commands/binary-serialization.ts @@ -182,7 +182,7 @@ export class ResizableUint8Array { this.bytes[position === "start" ? "unshift" : "push"](bytesToAdd); } - getBytesChunks(): ReadonlyArray { + getBytesChunks(): readonly Uint8Array[] { return this.bytes; } diff --git a/packages/p2p-media-loader-core/src/p2p/loader.ts b/packages/p2p-media-loader-core/src/p2p/loader.ts index d39d77a7..4afc0d3b 100644 --- a/packages/p2p-media-loader-core/src/p2p/loader.ts +++ b/packages/p2p-media-loader-core/src/p2p/loader.ts @@ -12,9 +12,8 @@ import * as Utils from "../utils/utils.js"; import { EventTarget } from "../utils/event-target.js"; import { SegmentStorage } from "../segment-storage/index.js"; -export type EventTargetMap = { - [key in `onStorageUpdated-${string}`]: () => void; -} & CoreEventMap; +export type EventTargetMap = Record<`onStorageUpdated-${string}`, () => void> & + CoreEventMap; export class P2PLoader { private readonly trackerClient: P2PTrackerClient; @@ -67,8 +66,8 @@ export class P2PLoader { } } + if (peersWithSegment.length === 0) return; const peer = Utils.getRandomItem(peersWithSegment); - if (!peer) return; const request = this.requests.getOrCreateRequest(segment); peer.downloadSegment(request); diff --git a/packages/p2p-media-loader-core/src/p2p/loaders-container.ts b/packages/p2p-media-loader-core/src/p2p/loaders-container.ts index 285f17d1..df3536dd 100644 --- a/packages/p2p-media-loader-core/src/p2p/loaders-container.ts +++ b/packages/p2p-media-loader-core/src/p2p/loaders-container.ts @@ -21,7 +21,7 @@ type P2PLoaderContainerItem = { export class P2PLoadersContainer { private readonly loaders = new Map(); - private _currentLoaderItem!: P2PLoaderContainerItem; + private _currentLoaderItem: P2PLoaderContainerItem; private readonly logger = debug("p2pml-core:p2p-loaders-container"); constructor( @@ -33,7 +33,10 @@ export class P2PLoadersContainer { private readonly eventTarget: EventTarget, private onSegmentAnnouncement: () => void, ) { - this.changeCurrentLoader(stream); + this._currentLoaderItem = this.findOrCreateLoaderForStream(stream); + this.logger( + `set current p2p loader: ${LoggerUtils.getStreamString(stream)}`, + ); } private createLoader(stream: StreamWithSegments): P2PLoaderContainerItem { @@ -62,30 +65,31 @@ export class P2PLoadersContainer { }; } - changeCurrentLoader(stream: StreamWithSegments) { + private findOrCreateLoaderForStream(stream: StreamWithSegments) { const loaderItem = this.loaders.get(stream.runtimeId); - if (this._currentLoaderItem) { - const swarmId = this.config.swarmId ?? this.streamManifestUrl; - const streamSwarmId = StreamUtils.getStreamSwarmId( - swarmId, - this._currentLoaderItem.stream, - ); - const ids = this.segmentStorage.getStoredSegmentIds( - swarmId, - streamSwarmId, - ); - if (!ids.length) this.destroyAndRemoveLoader(this._currentLoaderItem); - else this.setLoaderDestroyTimeout(this._currentLoaderItem); - } if (loaderItem) { - this._currentLoaderItem = loaderItem; clearTimeout(loaderItem.destroyTimeoutId); loaderItem.destroyTimeoutId = undefined; + return loaderItem; } else { const loader = this.createLoader(stream); this.loaders.set(stream.runtimeId, loader); - this._currentLoaderItem = loader; + return loader; } + } + + changeCurrentLoader(stream: StreamWithSegments) { + const swarmId = this.config.swarmId ?? this.streamManifestUrl; + const streamSwarmId = StreamUtils.getStreamSwarmId( + swarmId, + this._currentLoaderItem.stream, + ); + const ids = this.segmentStorage.getStoredSegmentIds(swarmId, streamSwarmId); + if (!ids.length) this.destroyAndRemoveLoader(this._currentLoaderItem); + else this.setLoaderDestroyTimeout(this._currentLoaderItem); + + this._currentLoaderItem = this.findOrCreateLoaderForStream(stream); + this.logger( `change current p2p loader: ${LoggerUtils.getStreamString(stream)}`, ); diff --git a/packages/p2p-media-loader-core/src/p2p/peer-protocol.ts b/packages/p2p-media-loader-core/src/p2p/peer-protocol.ts index 32673e56..1ce149b1 100644 --- a/packages/p2p-media-loader-core/src/p2p/peer-protocol.ts +++ b/packages/p2p-media-loader-core/src/p2p/peer-protocol.ts @@ -70,7 +70,7 @@ export class PeerProtocol { throw new Error(`Some segment data is already uploading.`); } const chunks = getBufferChunks(data, this.peerConfig.webRtcMaxMessageSize); - const { promise, resolve, reject } = Utils.getControlledPromise(); + const { promise, resolve, reject } = Utils.getControlledPromise(); let isUploadingSegmentData = false; diff --git a/packages/p2p-media-loader-core/src/p2p/peer.ts b/packages/p2p-media-loader-core/src/p2p/peer.ts index 7b6763b9..8bb7e4e3 100644 --- a/packages/p2p-media-loader-core/src/p2p/peer.ts +++ b/packages/p2p-media-loader-core/src/p2p/peer.ts @@ -134,7 +134,7 @@ export class Peer { break; case PeerCommandType.SegmentDataSendingCompleted: { - const downloadingContext = this.downloadingContext; + const { downloadingContext } = this; if (!downloadingContext?.isSegmentDataCommandReceived) return; @@ -165,7 +165,7 @@ export class Peer { (await this.peerConfig.validateP2PSegment?.( request.segment.url, request.segment.byteRange, - request.data + request.data, )) ?? true; if (this.downloadingContext !== downloadingContext) return; @@ -186,20 +186,21 @@ export class Peer { case PeerCommandType.SegmentAbsent: if ( this.downloadingContext?.request.segment.externalId === command.i && - this.downloadingContext?.requestId === command.r + this.downloadingContext.requestId === command.r ) { this.cancelSegmentDownloading("peer-segment-absent"); this.loadedSegments.delete(command.i); } break; - case PeerCommandType.CancelSegmentRequest: + case PeerCommandType.CancelSegmentRequest: { const uploadingRequestId = this.peerProtocol.getUploadingRequestId(); if (uploadingRequestId !== command.r) break; this.peerProtocol.stopUploadingSegmentData(); break; + } } }; @@ -353,7 +354,7 @@ export class Peer { error, }); - const code = (error as { code?: string }).code; + const { code } = error as { code?: string }; if (code === "ERR_DATA_CHANNEL") { this.destroy(); diff --git a/packages/p2p-media-loader-core/src/p2p/tracker-client.ts b/packages/p2p-media-loader-core/src/p2p/tracker-client.ts index 7d42ec1b..7e2cee37 100644 --- a/packages/p2p-media-loader-core/src/p2p/tracker-client.ts +++ b/packages/p2p-media-loader-core/src/p2p/tracker-client.ts @@ -102,7 +102,7 @@ export class P2PTrackerClient { } peerConnection.on("connect", () => { - if (!peerItem || peerItem.peer) return; + if (peerItem.peer) return; for (const connection of peerItem.potentialConnections) { if (connection !== peerConnection) connection.destroy(); @@ -148,7 +148,7 @@ export class P2PTrackerClient { *peers() { for (const peerItem of this._peers.values()) { - if (peerItem?.peer) yield peerItem.peer; + if (peerItem.peer) yield peerItem.peer; } } diff --git a/packages/p2p-media-loader-core/src/requests/request.ts b/packages/p2p-media-loader-core/src/requests/request.ts index 181c2bc0..4b9ede76 100644 --- a/packages/p2p-media-loader-core/src/requests/request.ts +++ b/packages/p2p-media-loader-core/src/requests/request.ts @@ -309,7 +309,7 @@ export class Request { if (!this.currentAttempt || !this.progress) return; this.notReceivingBytesTimeout.restart(); - const byteLength = chunk.byteLength; + const { byteLength } = chunk; const { all: allBC, http: httpBC } = this.bandwidthCalculators; allBC.addBytes(byteLength); if (this.currentAttempt.downloadSource === "http") { diff --git a/packages/p2p-media-loader-core/src/segment-storage/segment-memory-storage.ts b/packages/p2p-media-loader-core/src/segment-storage/segment-memory-storage.ts index 9b1605f2..3760bf17 100644 --- a/packages/p2p-media-loader-core/src/segment-storage/segment-memory-storage.ts +++ b/packages/p2p-media-loader-core/src/segment-storage/segment-memory-storage.ts @@ -269,7 +269,7 @@ export class SegmentMemoryStorage implements SegmentStorage { } private setMemoryStorageLimit() { - if (this.coreConfig && this.coreConfig.segmentMemoryStorageLimit) { + if (this.coreConfig?.segmentMemoryStorageLimit) { this.segmentMemoryStorageLimit = this.coreConfig.segmentMemoryStorageLimit; return; diff --git a/packages/p2p-media-loader-core/src/utils/event-target.ts b/packages/p2p-media-loader-core/src/utils/event-target.ts index ec30815b..9934b36d 100644 --- a/packages/p2p-media-loader-core/src/utils/event-target.ts +++ b/packages/p2p-media-loader-core/src/utils/event-target.ts @@ -1,6 +1,6 @@ export class EventTarget< // eslint-disable-next-line @typescript-eslint/no-explicit-any - EventTypesMap extends { [key: string]: (...args: any[]) => unknown }, + EventTypesMap extends Record unknown>, > { private events = new Map< keyof EventTypesMap, diff --git a/packages/p2p-media-loader-core/src/utils/stream.ts b/packages/p2p-media-loader-core/src/utils/stream.ts index 232a1d11..da1ea866 100644 --- a/packages/p2p-media-loader-core/src/utils/stream.ts +++ b/packages/p2p-media-loader-core/src/utils/stream.ts @@ -53,7 +53,7 @@ export function getStreamId(stream: Stream) { export function getSegmentAvgDuration(stream: StreamWithSegments) { const { segments } = stream; let sumDuration = 0; - const size = segments.size; + const { size } = segments; for (const segment of segments.values()) { const duration = segment.endTime - segment.startTime; sumDuration += duration; diff --git a/packages/p2p-media-loader-core/src/utils/utils.ts b/packages/p2p-media-loader-core/src/utils/utils.ts index 14a2ed07..d11862dd 100644 --- a/packages/p2p-media-loader-core/src/utils/utils.ts +++ b/packages/p2p-media-loader-core/src/utils/utils.ts @@ -1,6 +1,6 @@ import { CommonCoreConfig, CoreConfig, StreamConfig } from "../types.js"; -export function getControlledPromise() { +export function getControlledPromise() { let resolve: (value: T) => void; let reject: (reason?: unknown) => void; const promise = new Promise((res, rej) => { @@ -122,7 +122,7 @@ type RecursivePartial = { export function overrideConfig( target: T, - updates: RecursivePartial, + updates: RecursivePartial | null, defaults: RecursivePartial = {} as RecursivePartial, ): T { if ( @@ -134,7 +134,7 @@ export function overrideConfig( return target; } - (Object.keys(updates) as Array).forEach((key) => { + (Object.keys(updates) as (keyof T)[]).forEach((key) => { if (key === "__proto__" || key === "constructor" || key === "prototype") { throw new Error(`Attempt to modify restricted property '${String(key)}'`); } @@ -163,7 +163,8 @@ type MergeConfigsToTypeOptions = { specificStreamConfig?: Partial; }; -export function mergeAndFilterConfig(options: MergeConfigsToTypeOptions): T { +// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters +export function mergeAndFilterConfig(options: MergeConfigsToTypeOptions) { const { defaultConfig, baseConfig = {}, specificStreamConfig = {} } = options; const mergedConfig = deepCopy({ @@ -172,7 +173,7 @@ export function mergeAndFilterConfig(options: MergeConfigsToTypeOptions): T { ...specificStreamConfig, }); - const keysOfT = Object.keys(defaultConfig) as Array; + const keysOfT = Object.keys(defaultConfig) as (keyof T)[]; const filteredConfig: Partial = {}; keysOfT.forEach((key) => { diff --git a/packages/p2p-media-loader-core/tsconfig.node.json b/packages/p2p-media-loader-core/tsconfig.node.json index 39bd5857..96596de2 100644 --- a/packages/p2p-media-loader-core/tsconfig.node.json +++ b/packages/p2p-media-loader-core/tsconfig.node.json @@ -4,5 +4,5 @@ "module": "ESNext", "moduleResolution": "Bundler" }, - "include": ["vite.config.ts"] + "include": ["vite.config.ts", "eslint.config.js"] } diff --git a/packages/p2p-media-loader-demo/.eslintrc.cjs b/packages/p2p-media-loader-demo/.eslintrc.cjs deleted file mode 100644 index 01279b4a..00000000 --- a/packages/p2p-media-loader-demo/.eslintrc.cjs +++ /dev/null @@ -1,24 +0,0 @@ -module.exports = { - root: true, - parser: "@typescript-eslint/parser", - parserOptions: { - tsconfigRootDir: __dirname, - project: ["tsconfig.json"], - ecmaVersion: "latest", - sourceType: "module", - }, - extends: [ - "../../.eslintrc.common.cjs", - "eslint:recommended", - "plugin:@typescript-eslint/recommended", - "plugin:react-hooks/recommended", - ], - plugins: ["react-refresh"], - rules: { - "react-refresh/only-export-components": [ - "warn", - { allowConstantExport: true }, - ], - "import/extensions": "off", - }, -}; diff --git a/packages/p2p-media-loader-demo/eslint.config.js b/packages/p2p-media-loader-demo/eslint.config.js new file mode 100644 index 00000000..739db964 --- /dev/null +++ b/packages/p2p-media-loader-demo/eslint.config.js @@ -0,0 +1,35 @@ +// @ts-check + +import { CommonConfig } from "../../eslint.common.config.js"; +import tsEslint from "typescript-eslint"; +import reactRefresh from "eslint-plugin-react-refresh"; +import reactHooks from "eslint-plugin-react-hooks"; +import reactPlugin from "eslint-plugin-react"; + +export default tsEslint.config( + ...CommonConfig, + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error + reactPlugin.configs.flat?.recommended, // This is not a plugin object, but a shareable config object + reactPlugin.configs.flat?.["jsx-runtime"], // Add this if you are using React 17+ + { + plugins: { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + "react-hooks": reactHooks, + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + "react-refresh": reactRefresh, + }, + rules: { + .../** @type {Record} */ ( + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + reactHooks.configs.recommended.rules + ), + "import/extensions": "off", + }, + settings: { + react: { + version: "detect", + }, + }, + }, +); diff --git a/packages/p2p-media-loader-demo/package.json b/packages/p2p-media-loader-demo/package.json index 31937a35..1b0edd5a 100644 --- a/packages/p2p-media-loader-demo/package.json +++ b/packages/p2p-media-loader-demo/package.json @@ -41,7 +41,7 @@ "scripts": { "build": "rimraf lib build && tsc && pnpm copy-css", "copy-css": "cpy \"src/**/*.css\" \"./lib/\" --parents", - "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", + "lint": "eslint src --report-unused-disable-directives --max-warnings 0", "type-check": "tsc --noEmit", "clean": "rimraf lib dist build p2p-media-loader-demo-*.tgz", "clean-with-modules": "rimraf node_modules && pnpm clean" diff --git a/packages/p2p-media-loader-demo/src/components/P2PVideoDemo.tsx b/packages/p2p-media-loader-demo/src/components/P2PVideoDemo.tsx index be662d36..b80506c6 100644 --- a/packages/p2p-media-loader-demo/src/components/P2PVideoDemo.tsx +++ b/packages/p2p-media-loader-demo/src/components/P2PVideoDemo.tsx @@ -54,7 +54,7 @@ const playerComponents = { mediaElement_hls: HlsjsMediaElement, plyr_shaka: ShakaPlyr, vidstack_hls: HlsjsVidstack, -}; +} as const; export const P2PVideoDemo = ({ streamUrl, @@ -117,7 +117,9 @@ export const P2PVideoDemo = ({ }; const renderPlayer = () => { - const PlayerComponent = playerComponents[queryParams.player as PlayerKey]; + const PlayerComponent = playerComponents[ + queryParams.player as PlayerKey + ] as (typeof playerComponents)[PlayerKey] | undefined; return PlayerComponent ? ( { const maxP2PUploadValue = d3.min(data, (d) => d.p2pUploaded); const defaultDomain = [0, 1]; - const extentDomain = d3.extent(data, (d) => d.seconds) as [number, number]; + const extentDomain = d3.extent(data, (d) => d.seconds); const xScale = d3 .scaleLinear() diff --git a/packages/p2p-media-loader-demo/src/components/players/hlsjs/HlsjsPlyr.tsx b/packages/p2p-media-loader-demo/src/components/players/hlsjs/HlsjsPlyr.tsx index 95b4b558..caee5b32 100644 --- a/packages/p2p-media-loader-demo/src/components/players/hlsjs/HlsjsPlyr.tsx +++ b/packages/p2p-media-loader-demo/src/components/players/hlsjs/HlsjsPlyr.tsx @@ -53,7 +53,7 @@ export const HlsjsPlyr = ({ }); hls.on(Hls.Events.MANIFEST_PARSED, () => { - const levels = hls.levels; + const { levels } = hls; const quality: Options["quality"] = { default: levels[levels.length - 1].height, diff --git a/packages/p2p-media-loader-demo/src/components/players/hlsjs/HlsjsVidstackIndexedDB.tsx b/packages/p2p-media-loader-demo/src/components/players/hlsjs/HlsjsVidstackIndexedDB.tsx index 88923d32..abe1a96d 100644 --- a/packages/p2p-media-loader-demo/src/components/players/hlsjs/HlsjsVidstackIndexedDB.tsx +++ b/packages/p2p-media-loader-demo/src/components/players/hlsjs/HlsjsVidstackIndexedDB.tsx @@ -82,10 +82,11 @@ export const HlsjsVidstackIndexedDB = ({

Note: Clearing of stored video segments is not implemented in this example. To remove cached segments, please clear - your browser's IndexedDB manually.{" "} + your browser's IndexedDB manually.{" "} View Source Code diff --git a/packages/p2p-media-loader-demo/src/components/players/shaka/ShakaClappr.tsx b/packages/p2p-media-loader-demo/src/components/players/shaka/ShakaClappr.tsx index d04f33cc..a98ecd06 100644 --- a/packages/p2p-media-loader-demo/src/components/players/shaka/ShakaClappr.tsx +++ b/packages/p2p-media-loader-demo/src/components/players/shaka/ShakaClappr.tsx @@ -33,9 +33,11 @@ export const ShakaClappr = ({ const checkClapprLoaded = () => { if ( + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition window.Clappr && window.LevelSelector && window.DashShakaPlayback && + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition window.shaka.Player ) { if (intervalId) clearInterval(intervalId); @@ -47,7 +49,8 @@ export const ShakaClappr = ({ intervalId = setInterval(checkClapprLoaded, 200); return () => { - if (intervalId) clearInterval(intervalId); + clearInterval(intervalId); + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (window.shaka) ShakaP2PEngine.unregisterPlugins(); }; }, []); diff --git a/packages/p2p-media-loader-demo/src/components/players/shaka/ShakaPlyr.tsx b/packages/p2p-media-loader-demo/src/components/players/shaka/ShakaPlyr.tsx index 04ef9624..939f753d 100644 --- a/packages/p2p-media-loader-demo/src/components/players/shaka/ShakaPlyr.tsx +++ b/packages/p2p-media-loader-demo/src/components/players/shaka/ShakaPlyr.tsx @@ -44,7 +44,7 @@ export const ShakaPlyr = ({ isCleanedUp = true; shakaP2PEngine?.destroy(); void playerShaka?.destroy(); - void plyrPlayer?.destroy(); + plyrPlayer?.destroy(); videoContainer.remove(); }; diff --git a/packages/p2p-media-loader-demo/src/custom-segment-storage-example/indexed-db-wrapper.ts b/packages/p2p-media-loader-demo/src/custom-segment-storage-example/indexed-db-wrapper.ts index c384e3af..c5861dee 100644 --- a/packages/p2p-media-loader-demo/src/custom-segment-storage-example/indexed-db-wrapper.ts +++ b/packages/p2p-media-loader-demo/src/custom-segment-storage-example/indexed-db-wrapper.ts @@ -39,7 +39,7 @@ export class IndexedDbWrapper { ); } - async put(storeName: string, item: T): Promise { + async put(storeName: string, item: unknown): Promise { await this.performTransaction(storeName, "readwrite", (store) => store.put(item), ); diff --git a/packages/p2p-media-loader-demo/src/hooks/useQueryParams.ts b/packages/p2p-media-loader-demo/src/hooks/useQueryParams.ts index fd042402..c9cddddb 100644 --- a/packages/p2p-media-loader-demo/src/hooks/useQueryParams.ts +++ b/packages/p2p-media-loader-demo/src/hooks/useQueryParams.ts @@ -7,10 +7,10 @@ function getInitialParams( searchParams: URLSearchParams, defaultParams: QueryParamsType, ): QueryParamsType { - return Object.keys(defaultParams).reduce((params, key) => { + return Object.keys(defaultParams).reduce((params, key) => { params[key] = searchParams.get(key) ?? defaultParams[key]; return params; - }, {} as QueryParamsType); + }, {}); } export function useQueryParams(streamUri?: string) { @@ -46,11 +46,7 @@ export function useQueryParams(streamUri?: string) { const searchParams = searchParamsRef.current; Object.entries(newParams).forEach(([key, value]) => { - if ( - value === null || - value === undefined || - value === defaultParams[key] - ) { + if (value == undefined || value === defaultParams[key]) { searchParams.delete(key); } else { searchParams.set(key, value); diff --git a/packages/p2p-media-loader-demo/tsconfig.json b/packages/p2p-media-loader-demo/tsconfig.json index 7e8a8f00..bfb757fd 100644 --- a/packages/p2p-media-loader-demo/tsconfig.json +++ b/packages/p2p-media-loader-demo/tsconfig.json @@ -6,5 +6,6 @@ "tsBuildInfoFile": "./build/.tsbuildinfo", "jsx": "react-jsx" }, - "include": ["src/**/*"] + "include": ["src/**/*"], + "references": [{ "path": "./tsconfig.node.json" }] } diff --git a/packages/p2p-media-loader-demo/tsconfig.node.json b/packages/p2p-media-loader-demo/tsconfig.node.json new file mode 100644 index 00000000..b153b442 --- /dev/null +++ b/packages/p2p-media-loader-demo/tsconfig.node.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "module": "ESNext", + "moduleResolution": "Bundler" + }, + "include": ["eslint.config.js"] +} diff --git a/packages/p2p-media-loader-hlsjs/.eslintrc.cjs b/packages/p2p-media-loader-hlsjs/.eslintrc.cjs deleted file mode 100644 index c7062f7a..00000000 --- a/packages/p2p-media-loader-hlsjs/.eslintrc.cjs +++ /dev/null @@ -1,11 +0,0 @@ -module.exports = { - root: true, - extends: ["../../.eslintrc.common.cjs"], - parser: "@typescript-eslint/parser", - parserOptions: { - tsconfigRootDir: __dirname, - project: ["tsconfig.json", "tsconfig.node.json"], - ecmaVersion: "latest", - sourceType: "module", - }, -}; diff --git a/packages/p2p-media-loader-hlsjs/eslint.config.js b/packages/p2p-media-loader-hlsjs/eslint.config.js new file mode 100644 index 00000000..9ebad9c7 --- /dev/null +++ b/packages/p2p-media-loader-hlsjs/eslint.config.js @@ -0,0 +1,6 @@ +// @ts-check + +import { CommonConfig } from "../../eslint.common.config.js"; +import tsEslint from "typescript-eslint"; + +export default tsEslint.config(...CommonConfig); diff --git a/packages/p2p-media-loader-hlsjs/package.json b/packages/p2p-media-loader-hlsjs/package.json index 8cfa5415..2d1f9ed0 100644 --- a/packages/p2p-media-loader-hlsjs/package.json +++ b/packages/p2p-media-loader-hlsjs/package.json @@ -45,7 +45,7 @@ "build:esm-min": "vite build --mode esm-min", "build:es": "tsc", "prettier": "prettier --write .", - "lint": "eslint . --ext .ts --report-unused-disable-directives --max-warnings 0", + "lint": "eslint src --report-unused-disable-directives --max-warnings 0", "clean": "rimraf lib dist build p2p-media-loader-hlsjs-*.tgz", "clean-with-modules": "rimraf node_modules && pnpm clean", "type-check": "npx tsc --noEmit" diff --git a/packages/p2p-media-loader-hlsjs/src/engine-static.ts b/packages/p2p-media-loader-hlsjs/src/engine-static.ts index f72364d6..95a5d000 100644 --- a/packages/p2p-media-loader-hlsjs/src/engine-static.ts +++ b/packages/p2p-media-loader-hlsjs/src/engine-static.ts @@ -18,11 +18,13 @@ export function injectMixin< // eslint-disable-next-line @typescript-eslint/no-explicit-any constructor(...args: any[]) { - const config = args[0] as { - p2p?: PartialHlsJsP2PEngineConfig & { - onHlsJsCreated?: (hls: InstanceType) => void; - }; - } & Record; + const config = args[0] as + | ({ + p2p?: PartialHlsJsP2PEngineConfig & { + onHlsJsCreated?: (hls: InstanceType) => void; + }; + } & Record) + | undefined; const { p2p, ...hlsJsConfig } = config ?? {}; diff --git a/packages/p2p-media-loader-hlsjs/src/engine.ts b/packages/p2p-media-loader-hlsjs/src/engine.ts index 46c5bcdb..995c2a18 100644 --- a/packages/p2p-media-loader-hlsjs/src/engine.ts +++ b/packages/p2p-media-loader-hlsjs/src/engine.ts @@ -5,8 +5,9 @@ import type { ManifestLoadedData, LevelSwitchingData, PlaylistLevelType, + HlsConfig, + Events, } from "hls.js"; -import type { HlsConfig, Events } from "hls.js"; import { FragmentLoaderBase } from "./fragment-loader.js"; import { PlaylistLoaderBase } from "./playlist-loader.js"; import { SegmentManager } from "./segment-mananger.js"; @@ -177,10 +178,10 @@ export class HlsJsP2PEngine { * provides the Hls.js P2P specific configuration for Hls.js loaders. * @returns An object with fragment loader (fLoader) and playlist loader (pLoader). */ - getConfigForHlsJs(): { fLoader: F; pLoader: P } { + getConfigForHlsJs(): { fLoader: unknown; pLoader: unknown } { return { - fLoader: this.createFragmentLoaderClass() as F, - pLoader: this.createPlaylistLoaderClass() as P, + fLoader: this.createFragmentLoaderClass(), + pLoader: this.createPlaylistLoaderClass(), }; } @@ -286,6 +287,7 @@ export class HlsJsP2PEngine { }; private handleManifestLoaded = (event: string, data: ManifestLoadedData) => { + // eslint-disable-next-line prefer-destructuring const networkDetails: unknown = data.networkDetails; if (networkDetails instanceof XMLHttpRequest) { this.core.setManifestResponseUrl(networkDetails.responseURL); @@ -348,7 +350,7 @@ export class HlsJsP2PEngine { }; private createFragmentLoaderClass() { - const core = this.core; + const { core } = this; // eslint-disable-next-line @typescript-eslint/no-this-alias const engine = this; diff --git a/packages/p2p-media-loader-hlsjs/src/fragment-loader.ts b/packages/p2p-media-loader-hlsjs/src/fragment-loader.ts index 97904ae8..237d8f12 100644 --- a/packages/p2p-media-loader-hlsjs/src/fragment-loader.ts +++ b/packages/p2p-media-loader-hlsjs/src/fragment-loader.ts @@ -49,7 +49,7 @@ export class FragmentLoaderBase implements Loader { this.context = context; this.config = config; this.#callbacks = callbacks; - const stats = this.stats; + const { stats } = this; const { rangeStart: start, rangeEnd: end } = context; const byteRange = Utils.getByteRange( @@ -64,11 +64,11 @@ export class FragmentLoaderBase implements Loader { if ( !this.#core.hasSegment(this.#segmentId) || - isSegmentDownloadableByP2PCore === false + !isSegmentDownloadableByP2PCore ) { this.#defaultLoader = this.#createDefaultLoader(); this.#defaultLoader.stats = this.stats; - this.#defaultLoader?.load(context, config, callbacks); + this.#defaultLoader.load(context, config, callbacks); return; } @@ -80,7 +80,8 @@ export class FragmentLoaderBase implements Loader { loadedBytes, performance.now(), ); - stats.total = stats.loaded = loadedBytes; + stats.total = loadedBytes; + stats.loaded = loadedBytes; if (callbacks.onProgress) { callbacks.onProgress( diff --git a/packages/p2p-media-loader-hlsjs/src/segment-mananger.ts b/packages/p2p-media-loader-hlsjs/src/segment-mananger.ts index 5992437b..5dd46f3e 100644 --- a/packages/p2p-media-loader-hlsjs/src/segment-mananger.ts +++ b/packages/p2p-media-loader-hlsjs/src/segment-mananger.ts @@ -37,7 +37,6 @@ export class SegmentManager { } updatePlaylist(data: LevelUpdatedData | AudioTrackLoadedData) { - if (!data.details) return; const { details: { url, fragments, live }, } = data; diff --git a/packages/p2p-media-loader-hlsjs/tsconfig.node.json b/packages/p2p-media-loader-hlsjs/tsconfig.node.json index 39bd5857..96596de2 100644 --- a/packages/p2p-media-loader-hlsjs/tsconfig.node.json +++ b/packages/p2p-media-loader-hlsjs/tsconfig.node.json @@ -4,5 +4,5 @@ "module": "ESNext", "moduleResolution": "Bundler" }, - "include": ["vite.config.ts"] + "include": ["vite.config.ts", "eslint.config.js"] } diff --git a/packages/p2p-media-loader-shaka/.eslintrc.cjs b/packages/p2p-media-loader-shaka/.eslintrc.cjs deleted file mode 100644 index c7062f7a..00000000 --- a/packages/p2p-media-loader-shaka/.eslintrc.cjs +++ /dev/null @@ -1,11 +0,0 @@ -module.exports = { - root: true, - extends: ["../../.eslintrc.common.cjs"], - parser: "@typescript-eslint/parser", - parserOptions: { - tsconfigRootDir: __dirname, - project: ["tsconfig.json", "tsconfig.node.json"], - ecmaVersion: "latest", - sourceType: "module", - }, -}; diff --git a/packages/p2p-media-loader-shaka/eslint.config.js b/packages/p2p-media-loader-shaka/eslint.config.js new file mode 100644 index 00000000..9ebad9c7 --- /dev/null +++ b/packages/p2p-media-loader-shaka/eslint.config.js @@ -0,0 +1,6 @@ +// @ts-check + +import { CommonConfig } from "../../eslint.common.config.js"; +import tsEslint from "typescript-eslint"; + +export default tsEslint.config(...CommonConfig); diff --git a/packages/p2p-media-loader-shaka/package.json b/packages/p2p-media-loader-shaka/package.json index f45624e9..17090d70 100644 --- a/packages/p2p-media-loader-shaka/package.json +++ b/packages/p2p-media-loader-shaka/package.json @@ -46,7 +46,7 @@ "build:esm-min": "vite build --mode esm-min", "build:es": "tsc", "prettier": "prettier --write .", - "lint": "eslint . --ext .ts --report-unused-disable-directives --max-warnings 0", + "lint": "eslint src --report-unused-disable-directives --max-warnings 0", "clean": "rimraf lib dist build p2p-media-loader-shaka-*.tgz", "clean-with-modules": "rimraf node_modules && pnpm clean", "type-check": "npx tsc --noEmit" diff --git a/packages/p2p-media-loader-shaka/src/loading-handler.ts b/packages/p2p-media-loader-shaka/src/loading-handler.ts index 4b92ae2a..899105a0 100644 --- a/packages/p2p-media-loader-shaka/src/loading-handler.ts +++ b/packages/p2p-media-loader-shaka/src/loading-handler.ts @@ -1,6 +1,5 @@ import * as Utils from "./stream-utils.js"; -import { StreamInfo } from "./types.js"; -import { Shaka, Stream } from "./types.js"; +import { StreamInfo, Shaka, Stream } from "./types.js"; import { Core, CoreRequestError, @@ -62,7 +61,7 @@ export class Loader { if ( !this.core.hasSegment(segmentRuntimeId) || - isSegmentDownloadableByP2PCore === false + !isSegmentDownloadableByP2PCore ) { return this.defaultLoad() as LoadingHandlerResult; } @@ -98,9 +97,10 @@ export class Loader { } }; - return new this.shaka.util.AbortableOperation(loadSegment(), () => - Promise.resolve(this.core.abortSegmentLoading(segmentRuntimeId)), - ); + return new this.shaka.util.AbortableOperation(loadSegment(), () => { + this.core.abortSegmentLoading(segmentRuntimeId); + return Promise.resolve(); + }); } private setManifestResponseUrl(responseUrl: string) { diff --git a/packages/p2p-media-loader-shaka/src/manifest-parser-decorator.ts b/packages/p2p-media-loader-shaka/src/manifest-parser-decorator.ts index 66415bba..8addae09 100644 --- a/packages/p2p-media-loader-shaka/src/manifest-parser-decorator.ts +++ b/packages/p2p-media-loader-shaka/src/manifest-parser-decorator.ts @@ -206,10 +206,10 @@ export class ManifestParserDecorator implements shaka.extern.ManifestParser { if (videoMap && audioMap) { for (const variant of variants) { const { video: videoStream, audio: audioStream } = variant; - if (videoStream && videoMap) { + if (videoStream) { (videoStream as HookedStream).mediaSequenceTimeMap = videoMap; } - if (audioStream && audioMap) { + if (audioStream) { (audioStream as HookedStream).mediaSequenceTimeMap = videoMap; } } diff --git a/packages/p2p-media-loader-shaka/src/stream-utils.ts b/packages/p2p-media-loader-shaka/src/stream-utils.ts index 0e1cfab7..8e364f1e 100644 --- a/packages/p2p-media-loader-shaka/src/stream-utils.ts +++ b/packages/p2p-media-loader-shaka/src/stream-utils.ts @@ -47,7 +47,7 @@ export function getSegmentRuntimeId( export function getByteRangeFromHeaderString( rangeStr: string | undefined, ): ByteRange | undefined { - if (!rangeStr || !rangeStr.includes("bytes=")) return undefined; + if (!rangeStr?.includes("bytes=")) return undefined; const range = rangeStr .split("=")[1] diff --git a/packages/p2p-media-loader-shaka/tsconfig.node.json b/packages/p2p-media-loader-shaka/tsconfig.node.json index 39bd5857..96596de2 100644 --- a/packages/p2p-media-loader-shaka/tsconfig.node.json +++ b/packages/p2p-media-loader-shaka/tsconfig.node.json @@ -4,5 +4,5 @@ "module": "ESNext", "moduleResolution": "Bundler" }, - "include": ["vite.config.ts"] + "include": ["vite.config.ts", "eslint.config.js"] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d167a57a..da8adf11 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,12 +8,18 @@ importers: .: devDependencies: + '@types/eslint__js': + specifier: ^8.42.3 + version: 8.42.3 eslint: - specifier: ^8.57.1 - version: 8.57.1 + specifier: ^9.14.0 + version: 9.14.0 eslint-plugin-import: specifier: ^2.31.0 - version: 2.31.0(@typescript-eslint/parser@8.14.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1) + version: 2.31.0(@typescript-eslint/parser@8.14.0(eslint@9.14.0)(typescript@5.6.3))(eslint@9.14.0) + globals: + specifier: ^15.12.0 + version: 15.12.0 prettier: specifier: ^3.3.3 version: 3.3.3 @@ -31,7 +37,7 @@ importers: version: 5.6.3 typescript-eslint: specifier: ^8.14.0 - version: 8.14.0(eslint@8.57.1)(typescript@5.6.3) + version: 8.14.0(eslint@9.14.0)(typescript@5.6.3) vite: specifier: ^5.4.11 version: 5.4.11(@types/node@22.9.0)(terser@5.36.0) @@ -68,13 +74,13 @@ importers: version: 4.3.3(vite@5.4.11(@types/node@22.9.0)(terser@5.36.0)) eslint-plugin-react: specifier: ^7.37.2 - version: 7.37.2(eslint@8.57.1) + version: 7.37.2(eslint@9.14.0) eslint-plugin-react-hooks: specifier: ^5.0.0 - version: 5.0.0(eslint@8.57.1) + version: 5.0.0(eslint@9.14.0) eslint-plugin-react-refresh: specifier: ^0.4.14 - version: 0.4.14(eslint@8.57.1) + version: 0.4.14(eslint@9.14.0) vite-plugin-node-polyfills: specifier: ^0.22.0 version: 0.22.0(rollup@4.27.2)(vite@5.4.11(@types/node@22.9.0)(terser@5.36.0)) @@ -160,13 +166,13 @@ importers: version: 5.0.0 eslint-plugin-react: specifier: ^7.37.2 - version: 7.37.2(eslint@8.57.1) + version: 7.37.2(eslint@9.14.0) eslint-plugin-react-hooks: specifier: ^5.0.0 - version: 5.0.0(eslint@8.57.1) + version: 5.0.0(eslint@9.14.0) eslint-plugin-react-refresh: specifier: ^0.4.14 - version: 0.4.14(eslint@8.57.1) + version: 0.4.14(eslint@9.14.0) react: specifier: ^18.3.1 version: 18.3.1 @@ -433,13 +439,29 @@ packages: resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/eslintrc@2.1.4': - resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/config-array@0.18.0': + resolution: {integrity: sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@8.57.1': - resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/core@0.7.0': + resolution: {integrity: sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.2.0': + resolution: {integrity: sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.14.0': + resolution: {integrity: sha512-pFoEtFWCPyDOl+C6Ift+wC7Ro89otjigCf5vcuWqWgqNSQbRrpjSvdeE6ofLz4dHmyxD5f7gIdGT4+p36L6Twg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.4': + resolution: {integrity: sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.2.3': + resolution: {integrity: sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@floating-ui/core@1.6.8': resolution: {integrity: sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==} @@ -450,18 +472,25 @@ packages: '@floating-ui/utils@0.2.8': resolution: {integrity: sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==} - '@humanwhocodes/config-array@0.13.0': - resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} - engines: {node: '>=10.10.0'} - deprecated: Use @eslint/config-array instead + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.6': + resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==} + engines: {node: '>=18.18.0'} '@humanwhocodes/module-importer@1.0.1': resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} - '@humanwhocodes/object-schema@2.0.3': - resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} - deprecated: Use @eslint/object-schema instead + '@humanwhocodes/retry@0.3.1': + resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} + engines: {node: '>=18.18'} + + '@humanwhocodes/retry@0.4.1': + resolution: {integrity: sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==} + engines: {node: '>=18.18'} '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} @@ -755,6 +784,12 @@ packages: '@types/dplayer@1.25.5': resolution: {integrity: sha512-p/7O94dHDo0Irn2KWIqFE+fBCA4DS7QL3jfCOjCUPBAOgppyyTjmNZjKEfiJa1M3n1oVQqG7xnPwhiIuCqOzkQ==} + '@types/eslint@9.6.1': + resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} + + '@types/eslint__js@8.42.3': + resolution: {integrity: sha512-alfG737uhmPdnvkrLdZLcEKJ/B8s9Y4hrZ+YAdzUeoArBlSUERA2E87ROfOaS4jd/C45fzOoZzidLc1IPwLqOw==} + '@types/estree@1.0.6': resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} @@ -764,6 +799,9 @@ packages: '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} @@ -1134,8 +1172,9 @@ packages: chrome-dgram@3.0.6: resolution: {integrity: sha512-bqBsUuaOiXiqxXt/zA/jukNJJ4oaOtc7ciwqJpZVEaaXwwxqgI2/ZdG02vXYWUhHGziDlvGMQWk0qObgJwVYKA==} - cipher-base@1.0.4: - resolution: {integrity: sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==} + cipher-base@1.0.5: + resolution: {integrity: sha512-xq7ICKB4TMHUx7Tz1L9O2SGKOhYMOTR32oir45Bq28/AQTpHogKgHcoYFSdRbMtddl+ozNXfXY9jWcgYKmde0w==} + engines: {node: '>= 0.10'} clean-stack@4.2.0: resolution: {integrity: sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==} @@ -1440,10 +1479,6 @@ packages: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} - doctrine@3.0.0: - resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} - engines: {node: '>=6.0.0'} - dom-walk@0.1.2: resolution: {integrity: sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==} @@ -1587,23 +1622,31 @@ packages: peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 - eslint-scope@7.2.2: - resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + eslint-scope@8.2.0: + resolution: {integrity: sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} eslint-visitor-keys@3.4.3: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - eslint@8.57.1: - resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. + eslint-visitor-keys@4.2.0: + resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@9.14.0: + resolution: {integrity: sha512-c2FHsVBr87lnUtjP4Yhvk4yEhKrQavGafRA/Se1ouse8PfbfC/Qh9Mxa00yWsZRlqeUB9raXip0aiiUZkgnr9g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true - espree@9.6.1: - resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + espree@10.3.0: + resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} esquery@1.6.0: resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} @@ -1669,9 +1712,9 @@ packages: resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} engines: {node: ^12.20 || >= 14.13} - file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} @@ -1681,9 +1724,9 @@ packages: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} - flat-cache@3.2.0: - resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} - engines: {node: ^10.12.0 || >=12.0.0} + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} flatted@3.3.1: resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} @@ -1715,9 +1758,6 @@ packages: fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} - fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -1761,10 +1801,6 @@ packages: engines: {node: 20 || >=22} hasBin: true - glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported - global@4.4.0: resolution: {integrity: sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==} @@ -1772,9 +1808,13 @@ packages: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} - globals@13.24.0: - resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} - engines: {node: '>=8'} + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globals@15.12.0: + resolution: {integrity: sha512-1+gLErljJFhbOVyaetcwJiJ4+eLe45S2E7P5UiZ9xGfeq3ATQf5DOv9G7MH3gGbKQLkzmNh2DxfZwLdw+j6oTQ==} + engines: {node: '>=18'} globalthis@1.0.4: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} @@ -1880,10 +1920,6 @@ packages: resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} engines: {node: '>=12'} - inflight@1.0.6: - resolution: {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. - inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -1983,10 +2019,6 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} - is-path-inside@3.0.3: - resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} - engines: {node: '>=8'} - is-regex@1.1.4: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} engines: {node: '>= 0.4'} @@ -2391,10 +2423,6 @@ packages: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} - path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -2497,8 +2525,8 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - qs@6.13.0: - resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} + qs@6.13.1: + resolution: {integrity: sha512-EJPeIn0CYrGu+hli1xilKAPXODtJ12T0sP63Ijx2/khC2JtuaN3JyNIpvmnkmaEtha9ocbG4A4cMcr+TvqvwQg==} engines: {node: '>=0.6'} querystring-es3@0.2.1: @@ -2587,11 +2615,6 @@ packages: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true - rimraf@6.0.1: resolution: {integrity: sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==} engines: {node: 20 || >=22} @@ -2666,7 +2689,6 @@ packages: shaka-player@4.12.0: resolution: {integrity: sha512-Ih1kT/C+hC2kP+Jb9JQnQKhJFL4kLMLlJwQqDRr6IEgt1CIuVDDATUaNAKgvFdzdP/oRr9YTgkbZ1c+kySBz4g==} - engines: {node: '>=14'} shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} @@ -2883,10 +2905,6 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} - typed-array-buffer@1.0.2: resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} engines: {node: '>= 0.4'} @@ -3340,19 +3358,29 @@ snapshots: '@esbuild/win32-x64@0.21.5': optional: true - '@eslint-community/eslint-utils@4.4.1(eslint@8.57.1)': + '@eslint-community/eslint-utils@4.4.1(eslint@9.14.0)': dependencies: - eslint: 8.57.1 + eslint: 9.14.0 eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.1': {} - '@eslint/eslintrc@2.1.4': + '@eslint/config-array@0.18.0': + dependencies: + '@eslint/object-schema': 2.1.4 + debug: 4.3.7 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/core@0.7.0': {} + + '@eslint/eslintrc@3.2.0': dependencies: ajv: 6.12.6 debug: 4.3.7 - espree: 9.6.1 - globals: 13.24.0 + espree: 10.3.0 + globals: 14.0.0 ignore: 5.3.2 import-fresh: 3.3.0 js-yaml: 4.1.0 @@ -3361,7 +3389,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@8.57.1': {} + '@eslint/js@9.14.0': {} + + '@eslint/object-schema@2.1.4': {} + + '@eslint/plugin-kit@0.2.3': + dependencies: + levn: 0.4.1 '@floating-ui/core@1.6.8': dependencies: @@ -3374,17 +3408,18 @@ snapshots: '@floating-ui/utils@0.2.8': {} - '@humanwhocodes/config-array@0.13.0': + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.6': dependencies: - '@humanwhocodes/object-schema': 2.0.3 - debug: 4.3.7 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.3.1 '@humanwhocodes/module-importer@1.0.1': {} - '@humanwhocodes/object-schema@2.0.3': {} + '@humanwhocodes/retry@0.3.1': {} + + '@humanwhocodes/retry@0.4.1': {} '@isaacs/cliui@8.0.2': dependencies: @@ -3704,6 +3739,15 @@ snapshots: '@types/dplayer@1.25.5': {} + '@types/eslint@9.6.1': + dependencies: + '@types/estree': 1.0.6 + '@types/json-schema': 7.0.15 + + '@types/eslint__js@8.42.3': + dependencies: + '@types/eslint': 9.6.1 + '@types/estree@1.0.6': {} '@types/geojson@7946.0.14': {} @@ -3712,6 +3756,8 @@ snapshots: dependencies: '@types/unist': 3.0.3 + '@types/json-schema@7.0.15': {} + '@types/json5@0.0.29': {} '@types/mdast@4.0.4': @@ -3741,15 +3787,15 @@ snapshots: '@types/unist@3.0.3': {} - '@typescript-eslint/eslint-plugin@8.14.0(@typescript-eslint/parser@8.14.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/eslint-plugin@8.14.0(@typescript-eslint/parser@8.14.0(eslint@9.14.0)(typescript@5.6.3))(eslint@9.14.0)(typescript@5.6.3)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.14.0(eslint@8.57.1)(typescript@5.6.3) + '@typescript-eslint/parser': 8.14.0(eslint@9.14.0)(typescript@5.6.3) '@typescript-eslint/scope-manager': 8.14.0 - '@typescript-eslint/type-utils': 8.14.0(eslint@8.57.1)(typescript@5.6.3) - '@typescript-eslint/utils': 8.14.0(eslint@8.57.1)(typescript@5.6.3) + '@typescript-eslint/type-utils': 8.14.0(eslint@9.14.0)(typescript@5.6.3) + '@typescript-eslint/utils': 8.14.0(eslint@9.14.0)(typescript@5.6.3) '@typescript-eslint/visitor-keys': 8.14.0 - eslint: 8.57.1 + eslint: 9.14.0 graphemer: 1.4.0 ignore: 5.3.2 natural-compare: 1.4.0 @@ -3759,14 +3805,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.14.0(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/parser@8.14.0(eslint@9.14.0)(typescript@5.6.3)': dependencies: '@typescript-eslint/scope-manager': 8.14.0 '@typescript-eslint/types': 8.14.0 '@typescript-eslint/typescript-estree': 8.14.0(typescript@5.6.3) '@typescript-eslint/visitor-keys': 8.14.0 debug: 4.3.7 - eslint: 8.57.1 + eslint: 9.14.0 optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: @@ -3777,10 +3823,10 @@ snapshots: '@typescript-eslint/types': 8.14.0 '@typescript-eslint/visitor-keys': 8.14.0 - '@typescript-eslint/type-utils@8.14.0(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/type-utils@8.14.0(eslint@9.14.0)(typescript@5.6.3)': dependencies: '@typescript-eslint/typescript-estree': 8.14.0(typescript@5.6.3) - '@typescript-eslint/utils': 8.14.0(eslint@8.57.1)(typescript@5.6.3) + '@typescript-eslint/utils': 8.14.0(eslint@9.14.0)(typescript@5.6.3) debug: 4.3.7 ts-api-utils: 1.4.0(typescript@5.6.3) optionalDependencies: @@ -3806,13 +3852,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.14.0(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/utils@8.14.0(eslint@9.14.0)(typescript@5.6.3)': dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) + '@eslint-community/eslint-utils': 4.4.1(eslint@9.14.0) '@typescript-eslint/scope-manager': 8.14.0 '@typescript-eslint/types': 8.14.0 '@typescript-eslint/typescript-estree': 8.14.0(typescript@5.6.3) - eslint: 8.57.1 + eslint: 9.14.0 transitivePeerDependencies: - supports-color - typescript @@ -4104,7 +4150,7 @@ snapshots: browserify-aes@1.2.0: dependencies: buffer-xor: 1.0.3 - cipher-base: 1.0.4 + cipher-base: 1.0.5 create-hash: 1.2.0 evp_bytestokey: 1.0.3 inherits: 2.0.4 @@ -4118,7 +4164,7 @@ snapshots: browserify-des@1.0.2: dependencies: - cipher-base: 1.0.4 + cipher-base: 1.0.5 des.js: 1.1.0 inherits: 2.0.4 safe-buffer: 5.2.1 @@ -4211,7 +4257,7 @@ snapshots: inherits: 2.0.4 run-series: 1.1.9 - cipher-base@1.0.4: + cipher-base@1.0.5: dependencies: inherits: 2.0.4 safe-buffer: 5.2.1 @@ -4281,7 +4327,7 @@ snapshots: create-hash@1.2.0: dependencies: - cipher-base: 1.0.4 + cipher-base: 1.0.5 inherits: 2.0.4 md5.js: 1.3.5 ripemd160: 2.0.2 @@ -4289,7 +4335,7 @@ snapshots: create-hmac@1.1.7: dependencies: - cipher-base: 1.0.4 + cipher-base: 1.0.5 create-hash: 1.2.0 inherits: 2.0.4 ripemd160: 2.0.2 @@ -4563,10 +4609,6 @@ snapshots: dependencies: esutils: 2.0.3 - doctrine@3.0.0: - dependencies: - esutils: 2.0.3 - dom-walk@0.1.2: {} domain-browser@4.23.0: {} @@ -4744,17 +4786,17 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.14.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.14.0(eslint@9.14.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint@9.14.0): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.14.0(eslint@8.57.1)(typescript@5.6.3) - eslint: 8.57.1 + '@typescript-eslint/parser': 8.14.0(eslint@9.14.0)(typescript@5.6.3) + eslint: 9.14.0 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.14.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.14.0(eslint@9.14.0)(typescript@5.6.3))(eslint@9.14.0): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -4763,9 +4805,9 @@ snapshots: array.prototype.flatmap: 1.3.2 debug: 3.2.7 doctrine: 2.1.0 - eslint: 8.57.1 + eslint: 9.14.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.14.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.14.0(eslint@9.14.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint@9.14.0) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -4777,21 +4819,21 @@ snapshots: string.prototype.trimend: 1.0.8 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.14.0(eslint@8.57.1)(typescript@5.6.3) + '@typescript-eslint/parser': 8.14.0(eslint@9.14.0)(typescript@5.6.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-react-hooks@5.0.0(eslint@8.57.1): + eslint-plugin-react-hooks@5.0.0(eslint@9.14.0): dependencies: - eslint: 8.57.1 + eslint: 9.14.0 - eslint-plugin-react-refresh@0.4.14(eslint@8.57.1): + eslint-plugin-react-refresh@0.4.14(eslint@9.14.0): dependencies: - eslint: 8.57.1 + eslint: 9.14.0 - eslint-plugin-react@7.37.2(eslint@8.57.1): + eslint-plugin-react@7.37.2(eslint@9.14.0): dependencies: array-includes: 3.1.8 array.prototype.findlast: 1.2.5 @@ -4799,7 +4841,7 @@ snapshots: array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 es-iterator-helpers: 1.2.0 - eslint: 8.57.1 + eslint: 9.14.0 estraverse: 5.3.0 hasown: 2.0.2 jsx-ast-utils: 3.3.5 @@ -4813,61 +4855,60 @@ snapshots: string.prototype.matchall: 4.0.11 string.prototype.repeat: 1.0.0 - eslint-scope@7.2.2: + eslint-scope@8.2.0: dependencies: esrecurse: 4.3.0 estraverse: 5.3.0 eslint-visitor-keys@3.4.3: {} - eslint@8.57.1: + eslint-visitor-keys@4.2.0: {} + + eslint@9.14.0: dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) + '@eslint-community/eslint-utils': 4.4.1(eslint@9.14.0) '@eslint-community/regexpp': 4.12.1 - '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.57.1 - '@humanwhocodes/config-array': 0.13.0 + '@eslint/config-array': 0.18.0 + '@eslint/core': 0.7.0 + '@eslint/eslintrc': 3.2.0 + '@eslint/js': 9.14.0 + '@eslint/plugin-kit': 0.2.3 + '@humanfs/node': 0.16.6 '@humanwhocodes/module-importer': 1.0.1 - '@nodelib/fs.walk': 1.2.8 - '@ungap/structured-clone': 1.2.0 + '@humanwhocodes/retry': 0.4.1 + '@types/estree': 1.0.6 + '@types/json-schema': 7.0.15 ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.5 debug: 4.3.7 - 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 + eslint-scope: 8.2.0 + eslint-visitor-keys: 4.2.0 + espree: 10.3.0 esquery: 1.6.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 - file-entry-cache: 6.0.1 + file-entry-cache: 8.0.0 find-up: 5.0.0 glob-parent: 6.0.2 - globals: 13.24.0 - graphemer: 1.4.0 ignore: 5.3.2 imurmurhash: 0.1.4 is-glob: 4.0.3 - 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.4 - strip-ansi: 6.0.1 text-table: 0.2.0 transitivePeerDependencies: - supports-color - espree@9.6.1: + espree@10.3.0: dependencies: acorn: 8.14.0 acorn-jsx: 5.3.2(acorn@8.14.0) - eslint-visitor-keys: 3.4.3 + eslint-visitor-keys: 4.2.0 esquery@1.6.0: dependencies: @@ -4925,9 +4966,9 @@ snapshots: node-domexception: 1.0.0 web-streams-polyfill: 3.3.3 - file-entry-cache@6.0.1: + file-entry-cache@8.0.0: dependencies: - flat-cache: 3.2.0 + flat-cache: 4.0.1 fill-range@7.1.1: dependencies: @@ -4938,11 +4979,10 @@ snapshots: locate-path: 6.0.0 path-exists: 4.0.0 - flat-cache@3.2.0: + flat-cache@4.0.1: dependencies: flatted: 3.3.1 keyv: 4.5.4 - rimraf: 3.0.2 flatted@3.3.1: {} @@ -4969,8 +5009,6 @@ snapshots: fs-constants@1.0.0: {} - fs.realpath@1.0.0: {} - fsevents@2.3.3: optional: true @@ -5020,15 +5058,6 @@ snapshots: package-json-from-dist: 1.0.1 path-scurry: 2.0.0 - glob@7.2.3: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - global@4.4.0: dependencies: min-document: 2.19.0 @@ -5036,9 +5065,9 @@ snapshots: globals@11.12.0: {} - globals@13.24.0: - dependencies: - type-fest: 0.20.2 + globals@14.0.0: {} + + globals@15.12.0: {} globalthis@1.0.4: dependencies: @@ -5155,11 +5184,6 @@ snapshots: indent-string@5.0.0: {} - inflight@1.0.6: - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - inherits@2.0.4: {} ini@1.3.8: {} @@ -5249,8 +5273,6 @@ snapshots: is-number@7.0.0: {} - is-path-inside@3.0.3: {} - is-regex@1.1.4: dependencies: call-bind: 1.0.7 @@ -5670,8 +5692,6 @@ snapshots: path-exists@4.0.0: {} - path-is-absolute@1.0.1: {} - path-key@3.1.1: {} path-parse@1.0.7: {} @@ -5776,7 +5796,7 @@ snapshots: punycode@2.3.1: {} - qs@6.13.0: + qs@6.13.1: dependencies: side-channel: 1.0.6 @@ -5879,10 +5899,6 @@ snapshots: reusify@1.0.4: {} - rimraf@3.0.2: - dependencies: - glob: 7.2.3 - rimraf@6.0.1: dependencies: glob: 11.0.0 @@ -6227,8 +6243,6 @@ snapshots: dependencies: prelude-ls: 1.2.1 - type-fest@0.20.2: {} - typed-array-buffer@1.0.2: dependencies: call-bind: 1.0.7 @@ -6275,11 +6289,11 @@ snapshots: typescript: 5.6.3 yaml: 2.6.0 - typescript-eslint@8.14.0(eslint@8.57.1)(typescript@5.6.3): + typescript-eslint@8.14.0(eslint@9.14.0)(typescript@5.6.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.14.0(@typescript-eslint/parser@8.14.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3) - '@typescript-eslint/parser': 8.14.0(eslint@8.57.1)(typescript@5.6.3) - '@typescript-eslint/utils': 8.14.0(eslint@8.57.1)(typescript@5.6.3) + '@typescript-eslint/eslint-plugin': 8.14.0(@typescript-eslint/parser@8.14.0(eslint@9.14.0)(typescript@5.6.3))(eslint@9.14.0)(typescript@5.6.3) + '@typescript-eslint/parser': 8.14.0(eslint@9.14.0)(typescript@5.6.3) + '@typescript-eslint/utils': 8.14.0(eslint@9.14.0)(typescript@5.6.3) optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: @@ -6346,7 +6360,7 @@ snapshots: url@0.11.4: dependencies: punycode: 1.4.1 - qs: 6.13.0 + qs: 6.13.1 utf-8-validate@6.0.5: dependencies: