diff --git a/CHANGELOG.md b/CHANGELOG.md index d46a4aa3..78a2f3f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,14 @@ # Release Notes -## [Unreleased](https://github.com/laravel/echo/compare/v2.1.1...2.x) +## [Unreleased](https://github.com/laravel/echo/compare/v2.1.3...2.x) + +## [v2.1.3](https://github.com/laravel/echo/compare/v2.1.1...v2.1.3) - 2025-05-13 + +### What's Changed + +* Fix Reverb app key env name by [@joetannenbaum](https://github.com/joetannenbaum) in https://github.com/laravel/echo/pull/431 + +**Full Changelog**: https://github.com/laravel/echo/compare/v2.1.2...v2.1.3 ## [v2.1.1](https://github.com/laravel/echo/compare/v2.1.0...v2.1.1) - 2025-05-13 diff --git a/packages/laravel-echo/package.json b/packages/laravel-echo/package.json index e20582dc..bfb1a53f 100644 --- a/packages/laravel-echo/package.json +++ b/packages/laravel-echo/package.json @@ -1,6 +1,6 @@ { "name": "laravel-echo", - "version": "2.1.3", + "version": "2.1.4", "description": "Laravel Echo library for beautiful Pusher and Socket.IO integration", "keywords": [ "laravel", @@ -37,9 +37,11 @@ "@babel/plugin-transform-numeric-separator": "^7.25.9", "@babel/plugin-transform-object-assign": "^7.25.9", "@babel/preset-env": "^7.26.7", + "@types/jquery": "^3.5.32", "@types/node": "^20.0.0", "@typescript-eslint/eslint-plugin": "^8.21.0", "@typescript-eslint/parser": "^8.21.0", + "axios": "^1.9.0", "eslint": "^9.0.0", "prettier": "^3.5.3", "pusher-js": "^8.0", diff --git a/packages/laravel-echo/src/connector/connector.ts b/packages/laravel-echo/src/connector/connector.ts index 3eb2b50d..a4673b7f 100644 --- a/packages/laravel-echo/src/connector/connector.ts +++ b/packages/laravel-echo/src/connector/connector.ts @@ -1,3 +1,5 @@ +/// + import type { Channel, PresenceChannel } from "../channel"; import type { BroadcastDriver, EchoOptions } from "../echo"; @@ -88,29 +90,14 @@ export abstract class Connector< * Extract the CSRF token from the page. */ protected csrfToken(): null | string { - let selector; - - if ( - typeof window !== "undefined" && - typeof window.Laravel !== "undefined" && - window.Laravel.csrfToken - ) { - return window.Laravel.csrfToken; - } - - if (this.options.csrfToken) { - return this.options.csrfToken; - } - - if ( - typeof document !== "undefined" && - typeof document.querySelector === "function" && - (selector = document.querySelector('meta[name="csrf-token"]')) - ) { - return selector.getAttribute("content"); - } - - return null; + return ( + window?.Laravel?.csrfToken ?? + this.options.csrfToken ?? + document + ?.querySelector('meta[name="csrf-token"]') + ?.getAttribute("content") ?? + null + ); } /** diff --git a/packages/laravel-echo/src/connector/pusher-connector.ts b/packages/laravel-echo/src/connector/pusher-connector.ts index db495de3..6b50b227 100644 --- a/packages/laravel-echo/src/connector/pusher-connector.ts +++ b/packages/laravel-echo/src/connector/pusher-connector.ts @@ -42,7 +42,7 @@ export class PusherConnector< */ channels: Record = {}; - options: PusherOptions; + declare options: PusherOptions; /** * Create a fresh Pusher connection. diff --git a/packages/laravel-echo/src/echo.ts b/packages/laravel-echo/src/echo.ts index 8d6d7f01..28503d0e 100644 --- a/packages/laravel-echo/src/echo.ts +++ b/packages/laravel-echo/src/echo.ts @@ -1,3 +1,4 @@ +import type { InternalAxiosRequestConfig } from "axios"; import { Channel, NullChannel, @@ -179,7 +180,9 @@ export default class Echo { * send a connections socket id to a Laravel app with a X-Socket-Id header. */ registerInterceptors(): void { - if (typeof Vue === "function" && Vue.http) { + // TODO: This package is deprecated and we should remove it in a future version. + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + if (typeof Vue !== "undefined" && Vue?.http) { this.registerVueRequestInterceptor(); } @@ -200,12 +203,15 @@ export default class Echo { * Register a Vue HTTP interceptor to add the X-Socket-ID header. */ registerVueRequestInterceptor(): void { + // eslint-disable-next-line @typescript-eslint/no-unsafe-call Vue.http.interceptors.push( (request: Record, next: CallableFunction) => { if (this.socketId()) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-call request.headers.set("X-Socket-ID", this.socketId()); } + // eslint-disable-next-line @typescript-eslint/no-unsafe-call next(); }, ); @@ -215,13 +221,15 @@ export default class Echo { * Register an Axios HTTP interceptor to add the X-Socket-ID header. */ registerAxiosRequestInterceptor(): void { - axios.interceptors.request.use((config: Record) => { - if (this.socketId()) { - config.headers["X-Socket-Id"] = this.socketId(); - } + axios!.interceptors.request.use( + (config: InternalAxiosRequestConfig) => { + if (this.socketId()) { + config.headers["X-Socket-Id"] = this.socketId(); + } - return config; - }); + return config; + }, + ); } /** @@ -348,6 +356,7 @@ type GenericOptions = { host?: string | null; key?: string | null; namespace?: string | false; + withoutInterceptors?: boolean; [key: string]: any; }; diff --git a/packages/laravel-echo/tests/echo.test.ts b/packages/laravel-echo/tests/echo.test.ts index b31ffcf0..1dbf1f8b 100644 --- a/packages/laravel-echo/tests/echo.test.ts +++ b/packages/laravel-echo/tests/echo.test.ts @@ -4,36 +4,47 @@ import Echo from "../src/echo"; describe("Echo", () => { test("it will not throw error for supported driver", () => { - expect(() => new Echo({ broadcaster: "reverb" })).not.toThrow( - "Broadcaster string reverb is not supported.", - ); + expect( + () => + new Echo({ broadcaster: "reverb", withoutInterceptors: true }), + ).not.toThrow("Broadcaster string reverb is not supported."); - expect(() => new Echo({ broadcaster: "pusher" })).not.toThrow( - "Broadcaster string pusher is not supported.", - ); + expect( + () => + new Echo({ broadcaster: "pusher", withoutInterceptors: true }), + ).not.toThrow("Broadcaster string pusher is not supported."); - expect(() => new Echo({ broadcaster: "socket.io" })).not.toThrow( - "Broadcaster string socket.io is not supported.", - ); + expect( + () => + new Echo({ + broadcaster: "socket.io", + withoutInterceptors: true, + }), + ).not.toThrow("Broadcaster string socket.io is not supported."); - expect(() => new Echo({ broadcaster: "null" })).not.toThrow( - "Broadcaster string null is not supported.", - ); - expect(() => new Echo({ broadcaster: NullConnector })).not.toThrow(); - - // eslint-disable-next-line - // @ts-ignore - // eslint-disable-next-line @typescript-eslint/no-empty-function - expect(() => new Echo({ broadcaster: () => {} })).not.toThrow( - "Broadcaster function is not supported.", - ); + expect( + () => new Echo({ broadcaster: "null", withoutInterceptors: true }), + ).not.toThrow("Broadcaster string null is not supported."); + expect( + () => + new Echo({ + broadcaster: NullConnector, + withoutInterceptors: true, + }), + ).not.toThrow(); + expect( + () => + // @ts-ignore + // eslint-disable-next-line @typescript-eslint/no-empty-function + new Echo({ broadcaster: () => {}, withoutInterceptors: true }), + ).not.toThrow("Broadcaster function is not supported."); }); test("it will throw error for unsupported driver", () => { - // eslint-disable-next-line - // @ts-ignore - expect(() => new Echo({ broadcaster: "foo" })).toThrow( - "Broadcaster string foo is not supported.", - ); + expect( + // @ts-ignore + // eslint-disable-next-line + () => new Echo({ broadcaster: "foo", withoutInterceptors: true }), + ).toThrow("Broadcaster string foo is not supported."); }); }); diff --git a/packages/laravel-echo/tsconfig.json b/packages/laravel-echo/tsconfig.json index e96a3f49..f53d21f5 100644 --- a/packages/laravel-echo/tsconfig.json +++ b/packages/laravel-echo/tsconfig.json @@ -18,7 +18,7 @@ "emitDecoratorMetadata": true, "esModuleInterop": true, "strict": true, - "typeRoots": ["node_modules/@types"], + "typeRoots": ["node_modules/@types", "./typings"], "lib": ["dom", "es2020"] }, "include": ["./typings/**/*.ts", "./src/**/*.ts"], diff --git a/packages/laravel-echo/typings/window.d.ts b/packages/laravel-echo/typings/window.d.ts index b84c1f77..fdfb41e2 100644 --- a/packages/laravel-echo/typings/window.d.ts +++ b/packages/laravel-echo/typings/window.d.ts @@ -1,7 +1,7 @@ -import type { io } from "socket.io-client"; +import type { AxiosStatic } from "axios"; +import type { JQueryStatic } from "jquery"; import type Pusher from "pusher-js"; - -export {}; +import type { io } from "socket.io-client"; declare global { interface Window { @@ -10,7 +10,16 @@ declare global { }; io?: typeof io; - Pusher?: typeof Pusher; + + Vue?: any; + axios?: AxiosStatic; + jQuery?: JQueryStatic; + Turbo?: object; } + + const Vue: any | undefined; + const axios: AxiosStatic | undefined; + const jQuery: JQueryStatic | undefined; + const Turbo: object | undefined; } diff --git a/packages/laravel-echo/vite.config.ts b/packages/laravel-echo/vite.config.ts index 099ebdc7..f048f2bf 100644 --- a/packages/laravel-echo/vite.config.ts +++ b/packages/laravel-echo/vite.config.ts @@ -52,6 +52,10 @@ const config: UserConfig = (() => { emptyOutDir: true, ...common, }, + test: { + globals: true, + environment: "jsdom", + }, }; })(); diff --git a/packages/react/package.json b/packages/react/package.json index d157b30e..a80be836 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@laravel/echo-react", - "version": "2.1.3", + "version": "2.1.4", "description": "React hooks for seamless integration with Laravel Echo.", "keywords": [ "laravel", @@ -8,7 +8,7 @@ "ably", "react" ], - "homepage": "https://github.com/laravel/echotree/2.x/packages/react", + "homepage": "https://github.com/laravel/echo/tree/2.x/packages/react", "repository": { "type": "git", "url": "https://github.com/laravel/echo" diff --git a/packages/react/src/hooks/use-echo.ts b/packages/react/src/hooks/use-echo.ts index ca0bbd83..05ce47a0 100644 --- a/packages/react/src/hooks/use-echo.ts +++ b/packages/react/src/hooks/use-echo.ts @@ -51,7 +51,7 @@ const leaveChannel = (channel: Channel, leaveAll: boolean): void => { const resolveChannelSubscription = ( channel: Channel, -): Connection | void => { +): Connection => { if (channels[channel.id]) { channels[channel.id].count += 1; @@ -60,12 +60,6 @@ const resolveChannelSubscription = ( const channelSubscription = subscribeToChannel(channel); - if (!channelSubscription) { - // eslint-disable-next-line no-console - console.warn(`Failed to subscribe to channel: ${channel.id}`); - return; - } - channels[channel.id] = { count: 1, connection: channelSubscription, @@ -85,11 +79,6 @@ export const useEcho = < dependencies: any[] = [], visibility: TVisibility = "private" as TVisibility, ) => { - const callbackFunc = useCallback(callback, dependencies); - const subscription = useRef | null>(null); - const listening = useRef(false); - - const events = toArray(event); const channel: Channel = { name: channelName, id: ["private", "presence"].includes(visibility) @@ -98,13 +87,22 @@ export const useEcho = < visibility, }; + const callbackFunc = useCallback(callback, dependencies); + const listening = useRef(false); + const initialized = useRef(false); + const subscription = useRef>( + resolveChannelSubscription(channel), + ); + + const events = toArray(event); + const stopListening = useCallback(() => { if (!listening.current) { return; } events.forEach((e) => { - subscription.current!.stopListening(e, callbackFunc); + subscription.current.stopListening(e, callbackFunc); }); listening.current = false; @@ -116,7 +114,7 @@ export const useEcho = < } events.forEach((e) => { - subscription.current!.listen(e, callbackFunc); + subscription.current.listen(e, callbackFunc); }); listening.current = true; @@ -129,14 +127,11 @@ export const useEcho = < }, dependencies); useEffect(() => { - const channelSubscription = - resolveChannelSubscription(channel); - - if (!channelSubscription) { - return; + if (initialized.current) { + subscription.current = resolveChannelSubscription(channel); } - subscription.current = channelSubscription; + initialized.current = true; listen(); diff --git a/packages/react/src/types.ts b/packages/react/src/types.ts index 634b6876..320a7121 100644 --- a/packages/react/src/types.ts +++ b/packages/react/src/types.ts @@ -16,6 +16,15 @@ export type Channel = { visibility: "private" | "public" | "presence"; }; +export type ChannelReturnType< + T extends BroadcastDriver, + V extends Channel["visibility"], +> = V extends "presence" + ? Broadcaster[T]["presence"] + : V extends "private" + ? Broadcaster[T]["private"] + : Broadcaster[T]["public"]; + export type ConfigDefaults = Record< O, Broadcaster[O]["options"] @@ -28,15 +37,6 @@ export type ModelPayload = { afterCommit: boolean; }; -export type ChannelReturnType< - T extends BroadcastDriver, - V extends Channel["visibility"], -> = V extends "presence" - ? Broadcaster[T]["presence"] - : V extends "private" - ? Broadcaster[T]["private"] - : Broadcaster[T]["public"]; - // eslint-disable-next-line @typescript-eslint/no-unused-vars export type ModelName = T extends `${infer _}.${infer U}` ? ModelName diff --git a/packages/react/vite.config.ts b/packages/react/vite.config.ts index 343dcdbf..bbcffdf6 100644 --- a/packages/react/vite.config.ts +++ b/packages/react/vite.config.ts @@ -1,7 +1,27 @@ import { resolve } from "path"; -import { defineConfig, UserConfig } from "vite"; +import { defineConfig, PluginOption, UserConfig } from "vite"; import dts from "vite-plugin-dts"; +const handleEnvVariablesPlugin = (): PluginOption => { + return { + name: "handle-env-variables-plugin", + generateBundle(options, bundle) { + for (const fileName in bundle) { + const file = bundle[fileName]; + + if (file.type === "chunk" && file.fileName.endsWith(".js")) { + const transformedContent = file.code.replace( + /import\.meta\.env\.VITE_([A-Z0-9_]+)/g, + "(typeof import.meta.env !== 'undefined' ? import.meta.env.VITE_$1 : undefined)", + ); + + file.code = transformedContent; + } + } + }, + }; +}; + const config: UserConfig = (() => { const common: Partial = { rollupOptions: { @@ -40,6 +60,7 @@ const config: UserConfig = (() => { rollupTypes: true, include: ["src/**/*.ts"], }), + handleEnvVariablesPlugin(), ], define: { "import.meta.env.VITE_REVERB_APP_KEY": diff --git a/packages/vue/package.json b/packages/vue/package.json index b12b2a31..6176f773 100644 --- a/packages/vue/package.json +++ b/packages/vue/package.json @@ -1,6 +1,6 @@ { "name": "@laravel/echo-vue", - "version": "2.1.3", + "version": "2.1.4", "description": "Vue hooks for seamless integration with Laravel Echo.", "keywords": [ "laravel", diff --git a/packages/vue/src/composables/useEcho.ts b/packages/vue/src/composables/useEcho.ts index 1768c121..db2c9035 100644 --- a/packages/vue/src/composables/useEcho.ts +++ b/packages/vue/src/composables/useEcho.ts @@ -15,7 +15,7 @@ const channels: Record> = {}; const resolveChannelSubscription = ( channel: Channel, -): Connection | null => { +): Connection => { if (channels[channel.id]) { channels[channel.id].count += 1; @@ -24,12 +24,6 @@ const resolveChannelSubscription = ( const channelSubscription = subscribeToChannel(channel); - if (!channelSubscription) { - // eslint-disable-next-line no-console - console.warn(`Failed to subscribe to channel: ${channel.id}`); - return null; - } - channels[channel.id] = { count: 1, connection: channelSubscription, @@ -95,8 +89,6 @@ export const useEcho = < }, ); - let subscription: Connection | null = null; - const events = Array.isArray(event) ? event : [event]; const channel: Channel = { name: channelName, id: ["private", "presence"].includes(visibility) @@ -105,13 +97,11 @@ export const useEcho = < visibility, }; - const setupSubscription = () => { - subscription = resolveChannelSubscription(channel); - - if (!subscription) { - return; - } + const subscription: Connection = + resolveChannelSubscription(channel); + const events = Array.isArray(event) ? event : [event]; + const setupSubscription = () => { listen(); }; @@ -121,7 +111,7 @@ export const useEcho = < } events.forEach((e) => { - subscription!.listen(e, eventCallback.value); + subscription.listen(e, eventCallback.value); }); listening.value = true; @@ -133,7 +123,7 @@ export const useEcho = < } events.forEach((e) => { - subscription!.stopListening(e, eventCallback.value); + subscription.stopListening(e, eventCallback.value); }); listening.value = false; @@ -184,7 +174,7 @@ export const useEcho = < /** * Channel instance */ - channel: () => subscription! as ChannelReturnType, + channel: () => subscription as ChannelReturnType, }; }; @@ -231,8 +221,8 @@ export const useEchoModel = < >( model: TModel, identifier: string | number, - event: ModelEvents | ModelEvents[], - callback: (payload: ModelPayload) => void, + event: ModelEvents | ModelEvents[] = [], + callback: (payload: ModelPayload) => void = () => {}, dependencies: any[] = [], ) => { return useEcho, TDriver, "private">( diff --git a/packages/vue/src/types.ts b/packages/vue/src/types.ts index 634b6876..320a7121 100644 --- a/packages/vue/src/types.ts +++ b/packages/vue/src/types.ts @@ -16,6 +16,15 @@ export type Channel = { visibility: "private" | "public" | "presence"; }; +export type ChannelReturnType< + T extends BroadcastDriver, + V extends Channel["visibility"], +> = V extends "presence" + ? Broadcaster[T]["presence"] + : V extends "private" + ? Broadcaster[T]["private"] + : Broadcaster[T]["public"]; + export type ConfigDefaults = Record< O, Broadcaster[O]["options"] @@ -28,15 +37,6 @@ export type ModelPayload = { afterCommit: boolean; }; -export type ChannelReturnType< - T extends BroadcastDriver, - V extends Channel["visibility"], -> = V extends "presence" - ? Broadcaster[T]["presence"] - : V extends "private" - ? Broadcaster[T]["private"] - : Broadcaster[T]["public"]; - // eslint-disable-next-line @typescript-eslint/no-unused-vars export type ModelName = T extends `${infer _}.${infer U}` ? ModelName diff --git a/packages/vue/vite.config.ts b/packages/vue/vite.config.ts index 00f4d5cf..5584f069 100644 --- a/packages/vue/vite.config.ts +++ b/packages/vue/vite.config.ts @@ -1,7 +1,27 @@ import { resolve } from "path"; -import { defineConfig, UserConfig } from "vite"; +import { defineConfig, PluginOption, UserConfig } from "vite"; import dts from "vite-plugin-dts"; +const handleEnvVariablesPlugin = (): PluginOption => { + return { + name: "handle-env-variables-plugin", + generateBundle(options, bundle) { + for (const fileName in bundle) { + const file = bundle[fileName]; + + if (file.type === "chunk" && file.fileName.endsWith(".js")) { + const transformedContent = file.code.replace( + /import\.meta\.env\.VITE_([A-Z0-9_]+)/g, + "(typeof import.meta.env !== 'undefined' ? import.meta.env.VITE_$1 : undefined)", + ); + + file.code = transformedContent; + } + } + }, + }; +}; + const config: UserConfig = (() => { const common: Partial = { rollupOptions: { @@ -40,6 +60,7 @@ const config: UserConfig = (() => { rollupTypes: true, include: ["src/**/*.ts"], }), + handleEnvVariablesPlugin(), ], define: { "import.meta.env.VITE_REVERB_APP_KEY": diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cdefee7d..1b08924f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -34,6 +34,9 @@ importers: '@babel/preset-env': specifier: ^7.26.7 version: 7.27.1(@babel/core@7.27.1) + '@types/jquery': + specifier: ^3.5.32 + version: 3.5.32 '@types/node': specifier: ^20.0.0 version: 20.17.32 @@ -43,6 +46,9 @@ importers: '@typescript-eslint/parser': specifier: ^8.21.0 version: 8.31.1(eslint@9.25.1)(typescript@5.8.3) + axios: + specifier: ^1.9.0 + version: 1.9.0 eslint: specifier: ^9.0.0 version: 9.25.1 @@ -1426,6 +1432,9 @@ packages: '@types/estree@1.0.7': resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} + '@types/jquery@3.5.32': + resolution: {integrity: sha512-b9Xbf4CkMqS02YH8zACqN1xzdxc3cO735Qe5AbSUFmyOiaWAbcpqh9Wna+Uk0vgACvoQHpWDg2rGdHkYPLmCiQ==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -1448,6 +1457,9 @@ packages: '@types/react@19.1.2': resolution: {integrity: sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw==} + '@types/sizzle@2.3.9': + resolution: {integrity: sha512-xzLEyKB50yqCUPUJkIsrVvoWNfFUbIZI+RspLWt8u+tIW/BetMBZtgV2LY/2o+tYH8dRvQ+eoPf3NdhQCcLE2w==} + '@typescript-eslint/eslint-plugin@8.31.1': resolution: {integrity: sha512-oUlH4h1ABavI4F0Xnl8/fOtML/eu8nI2A1nYd+f+55XI0BLu+RIqKoCiZKNo6DtqZBEQm5aNKA20G3Z5w3R6GQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1679,10 +1691,16 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} + axios@1.9.0: + resolution: {integrity: sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==} + babel-plugin-polyfill-corejs2@0.4.13: resolution: {integrity: sha512-3sX/eOms8kd3q2KZ6DAhKPc0dgm525Gqq5NtWKZ7QYYZEv57OQ54KtblzJzH1lQF/eQxO8KjWGIK9IPUJNus5g==} peerDependencies: @@ -1766,6 +1784,10 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + commander@10.0.1: resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} engines: {node: '>=14'} @@ -1856,6 +1878,10 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} @@ -1920,6 +1946,10 @@ packages: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + esbuild@0.21.5: resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} engines: {node: '>=12'} @@ -2036,6 +2066,15 @@ packages: flatted@3.3.3: resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + follow-redirects@1.15.9: + resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + for-each@0.3.5: resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} engines: {node: '>= 0.4'} @@ -2044,6 +2083,10 @@ packages: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} + form-data@4.0.2: + resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==} + engines: {node: '>= 6'} + fs-extra@11.3.0: resolution: {integrity: sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==} engines: {node: '>=14.14'} @@ -2391,6 +2434,14 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + minimatch@3.0.8: resolution: {integrity: sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==} @@ -2544,6 +2595,9 @@ packages: proto-list@1.2.4: resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -4364,6 +4418,10 @@ snapshots: '@types/estree@1.0.7': {} + '@types/jquery@3.5.32': + dependencies: + '@types/sizzle': 2.3.9 + '@types/json-schema@7.0.15': {} '@types/node@20.17.32': @@ -4386,6 +4444,8 @@ snapshots: dependencies: csstype: 3.1.3 + '@types/sizzle@2.3.9': {} + '@typescript-eslint/eslint-plugin@8.31.1(@typescript-eslint/parser@8.31.1(eslint@9.25.1)(typescript@5.8.3))(eslint@9.25.1)(typescript@5.8.3)': dependencies: '@eslint-community/regexpp': 4.12.1 @@ -4701,10 +4761,20 @@ snapshots: assertion-error@2.0.1: {} + asynckit@0.4.0: {} + available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.1.0 + axios@1.9.0: + dependencies: + follow-redirects: 1.15.9 + form-data: 4.0.2 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + babel-plugin-polyfill-corejs2@0.4.13(@babel/core@7.27.1): dependencies: '@babel/compat-data': 7.27.1 @@ -4804,6 +4874,10 @@ snapshots: color-name@1.1.4: {} + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + commander@10.0.1: {} commander@9.5.0: @@ -4897,6 +4971,8 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 + delayed-stream@1.0.0: {} + dequal@2.0.3: {} dom-accessibility-api@0.5.16: {} @@ -4964,6 +5040,13 @@ snapshots: dependencies: es-errors: 1.3.0 + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + esbuild@0.21.5: optionalDependencies: '@esbuild/aix-ppc64': 0.21.5 @@ -5141,6 +5224,8 @@ snapshots: flatted@3.3.3: {} + follow-redirects@1.15.9: {} + for-each@0.3.5: dependencies: is-callable: 1.2.7 @@ -5150,6 +5235,13 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 + form-data@4.0.2: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + mime-types: 2.1.35 + fs-extra@11.3.0: dependencies: graceful-fs: 4.2.11 @@ -5495,6 +5587,12 @@ snapshots: braces: 3.0.3 picomatch: 2.3.1 + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + minimatch@3.0.8: dependencies: brace-expansion: 1.1.11 @@ -5638,6 +5736,8 @@ snapshots: proto-list@1.2.4: {} + proxy-from-env@1.1.0: {} + punycode@2.3.1: {} pusher-js@8.4.0: