UNPKG

@laravel/echo-vue

Version:

Vue hooks for seamless integration with Laravel Echo.

1,178 lines (1,177 loc) 28.6 kB
import { onUnmounted as k, ref as v, watch as P, onMounted as C } from "vue"; import q from "pusher-js"; class I { constructor() { this.notificationCreatedEvent = ".Illuminate\\Notifications\\Events\\BroadcastNotificationCreated"; } /** * Listen for a whisper event on the channel instance. */ listenForWhisper(e, t) { return this.listen(".client-" + e, t); } /** * Listen for an event on the channel instance. */ notification(e) { return this.listen(this.notificationCreatedEvent, e); } /** * Stop listening for notification events on the channel instance. */ stopListeningForNotification(e) { return this.stopListening(this.notificationCreatedEvent, e); } /** * Stop listening for a whisper event on the channel instance. */ stopListeningForWhisper(e, t) { return this.stopListening(".client-" + e, t); } } class A { /** * Create a new class instance. */ constructor(e) { this.namespace = e; } /** * Format the given event name. */ format(e) { return [".", "\\"].includes(e.charAt(0)) ? e.substring(1) : (this.namespace && (e = this.namespace + "." + e), e.replace(/\./g, "\\")); } /** * Set the event namespace. */ setNamespace(e) { this.namespace = e; } } function U(n) { try { return Reflect.construct(String, [], n), !0; } catch { return !1; } } class S extends I { /** * Create a new class instance. */ constructor(e, t, s) { super(), this.name = t, this.pusher = e, this.options = s, this.eventFormatter = new A(this.options.namespace), this.subscribe(); } /** * Subscribe to a Pusher channel. */ subscribe() { this.subscription = this.pusher.subscribe(this.name); } /** * Unsubscribe from a Pusher channel. */ unsubscribe() { this.pusher.unsubscribe(this.name); } /** * Listen for an event on the channel instance. */ listen(e, t) { return this.on(this.eventFormatter.format(e), t), this; } /** * Listen for all events on the channel instance. */ listenToAll(e) { return this.subscription.bind_global((t, s) => { if (t.startsWith("pusher:")) return; let i = String(this.options.namespace ?? "").replace( /\./g, "\\" ), r = t.startsWith(i) ? t.substring(i.length + 1) : "." + t; e(r, s); }), this; } /** * Stop listening for an event on the channel instance. */ stopListening(e, t) { return t ? this.subscription.unbind( this.eventFormatter.format(e), t ) : this.subscription.unbind(this.eventFormatter.format(e)), this; } /** * Stop listening for all events on the channel instance. */ stopListeningToAll(e) { return e ? this.subscription.unbind_global(e) : this.subscription.unbind_global(), this; } /** * Register a callback to be called anytime a subscription succeeds. */ subscribed(e) { return this.on("pusher:subscription_succeeded", () => { e(); }), this; } /** * Register a callback to be called anytime a subscription error occurs. */ error(e) { return this.on("pusher:subscription_error", (t) => { e(t); }), this; } /** * Bind a channel to an event. */ on(e, t) { return this.subscription.bind(e, t), this; } } class x extends S { /** * Send a whisper event to other clients in the channel. */ whisper(e, t) { return this.pusher.channels.channels[this.name].trigger( `client-${e}`, t ), this; } } class K extends S { /** * Send a whisper event to other clients in the channel. */ whisper(e, t) { return this.pusher.channels.channels[this.name].trigger( `client-${e}`, t ), this; } } class X extends x { /** * Register a callback to be called anytime the member list changes. */ here(e) { return this.on("pusher:subscription_succeeded", (t) => { e(Object.keys(t.members).map((s) => t.members[s])); }), this; } /** * Listen for someone joining the channel. */ joining(e) { return this.on("pusher:member_added", (t) => { e(t.info); }), this; } /** * Send a whisper event to other clients in the channel. */ whisper(e, t) { return this.pusher.channels.channels[this.name].trigger( `client-${e}`, t ), this; } /** * Listen for someone leaving the channel. */ leaving(e) { return this.on("pusher:member_removed", (t) => { e(t.info); }), this; } } class V extends I { /** * Create a new class instance. */ constructor(e, t, s) { super(), this.events = {}, this.listeners = {}, this.name = t, this.socket = e, this.options = s, this.eventFormatter = new A(this.options.namespace), this.subscribe(); } /** * Subscribe to a Socket.io channel. */ subscribe() { this.socket.emit("subscribe", { channel: this.name, auth: this.options.auth || {} }); } /** * Unsubscribe from channel and ubind event callbacks. */ unsubscribe() { this.unbind(), this.socket.emit("unsubscribe", { channel: this.name, auth: this.options.auth || {} }); } /** * Listen for an event on the channel instance. */ listen(e, t) { return this.on(this.eventFormatter.format(e), t), this; } /** * Stop listening for an event on the channel instance. */ stopListening(e, t) { return this.unbindEvent(this.eventFormatter.format(e), t), this; } /** * Register a callback to be called anytime a subscription succeeds. */ subscribed(e) { return this.on("connect", (t) => { e(t); }), this; } /** * Register a callback to be called anytime an error occurs. */ error(e) { return this; } /** * Bind the channel's socket to an event and store the callback. */ on(e, t) { return this.listeners[e] = this.listeners[e] || [], this.events[e] || (this.events[e] = (s, i) => { this.name === s && this.listeners[e] && this.listeners[e].forEach((r) => r(i)); }, this.socket.on(e, this.events[e])), this.listeners[e].push(t), this; } /** * Unbind the channel's socket from all stored event callbacks. */ unbind() { Object.keys(this.events).forEach((e) => { this.unbindEvent(e); }); } /** * Unbind the listeners for the given event. */ unbindEvent(e, t) { this.listeners[e] = this.listeners[e] || [], t && (this.listeners[e] = this.listeners[e].filter( (s) => s !== t )), (!t || this.listeners[e].length === 0) && (this.events[e] && (this.socket.removeListener(e, this.events[e]), delete this.events[e]), delete this.listeners[e]); } } class L extends V { /** * Send a whisper event to other clients in the channel. */ whisper(e, t) { return this.socket.emit("client event", { channel: this.name, event: `client-${e}`, data: t }), this; } } class Q extends L { /** * Register a callback to be called anytime the member list changes. */ here(e) { return this.on("presence:subscribed", (t) => { e(t.map((s) => s.user_info)); }), this; } /** * Listen for someone joining the channel. */ joining(e) { return this.on( "presence:joining", (t) => e(t.user_info) ), this; } /** * Send a whisper event to other clients in the channel. */ whisper(e, t) { return this.socket.emit("client event", { channel: this.name, event: `client-${e}`, data: t }), this; } /** * Listen for someone leaving the channel. */ leaving(e) { return this.on( "presence:leaving", (t) => e(t.user_info) ), this; } } class E extends I { /** * Subscribe to a channel. */ subscribe() { } /** * Unsubscribe from a channel. */ unsubscribe() { } /** * Listen for an event on the channel instance. */ listen(e, t) { return this; } /** * Listen for all events on the channel instance. */ listenToAll(e) { return this; } /** * Stop listening for an event on the channel instance. */ stopListening(e, t) { return this; } /** * Register a callback to be called anytime a subscription succeeds. */ subscribed(e) { return this; } /** * Register a callback to be called anytime an error occurs. */ error(e) { return this; } /** * Bind a channel to an event. */ on(e, t) { return this; } } class O extends E { /** * Send a whisper event to other clients in the channel. */ whisper(e, t) { return this; } } class W extends E { /** * Send a whisper event to other clients in the channel. */ whisper(e, t) { return this; } } class N extends O { /** * Register a callback to be called anytime the member list changes. */ here(e) { return this; } /** * Listen for someone joining the channel. */ joining(e) { return this; } /** * Send a whisper event to other clients in the channel. */ whisper(e, t) { return this; } /** * Listen for someone leaving the channel. */ leaving(e) { return this; } } class m { static { this._defaultOptions = { auth: { headers: {} }, authEndpoint: "/broadcasting/auth", userAuthentication: { endpoint: "/broadcasting/user-auth", headers: {} }, csrfToken: null, bearerToken: null, host: null, key: null, namespace: "App.Events" }; } /** * Create a new class instance. */ constructor(e) { this.setOptions(e), this.connect(); } /** * Merge the custom options with the defaults. */ setOptions(e) { this.options = { ...m._defaultOptions, ...e, broadcaster: e.broadcaster }; let t = this.csrfToken(); t && (this.options.auth.headers["X-CSRF-TOKEN"] = t, this.options.userAuthentication.headers["X-CSRF-TOKEN"] = t), t = this.options.bearerToken, t && (this.options.auth.headers.Authorization = "Bearer " + t, this.options.userAuthentication.headers.Authorization = "Bearer " + t); } /** * Extract the CSRF token from the page. */ csrfToken() { return typeof window < "u" && window.Laravel?.csrfToken ? window.Laravel.csrfToken : this.options.csrfToken ? this.options.csrfToken : typeof document < "u" && typeof document.querySelector == "function" ? document.querySelector('meta[name="csrf-token"]')?.getAttribute("content") ?? null : null; } } class w extends m { constructor() { super(...arguments), this.channels = {}; } /** * Create a fresh Pusher connection. */ connect() { if (typeof this.options.client < "u") this.pusher = this.options.client; else if (this.options.Pusher) this.pusher = new this.options.Pusher( this.options.key, this.options ); else if (typeof window < "u" && typeof window.Pusher < "u") this.pusher = new window.Pusher(this.options.key, this.options); else throw new Error( "Pusher client not found. Should be globally available or passed via options.client" ); } /** * Sign in the user via Pusher user authentication (https://pusher.com/docs/channels/using_channels/user-authentication/). */ signin() { this.pusher.signin(); } /** * Listen for an event on a channel instance. */ listen(e, t, s) { return this.channel(e).listen(t, s); } /** * Get a channel instance by name. */ channel(e) { return this.channels[e] || (this.channels[e] = new S( this.pusher, e, this.options )), this.channels[e]; } /** * Get a private channel instance by name. */ privateChannel(e) { return this.channels["private-" + e] || (this.channels["private-" + e] = new x( this.pusher, "private-" + e, this.options )), this.channels["private-" + e]; } /** * Get a private encrypted channel instance by name. */ encryptedPrivateChannel(e) { return this.channels["private-encrypted-" + e] || (this.channels["private-encrypted-" + e] = new K( this.pusher, "private-encrypted-" + e, this.options )), this.channels["private-encrypted-" + e]; } /** * Get a presence channel instance by name. */ presenceChannel(e) { return this.channels["presence-" + e] || (this.channels["presence-" + e] = new X( this.pusher, "presence-" + e, this.options )), this.channels["presence-" + e]; } /** * Leave the given channel, as well as its private and presence variants. */ leave(e) { [ e, "private-" + e, "private-encrypted-" + e, "presence-" + e ].forEach((t) => { this.leaveChannel(t); }); } /** * Leave the given channel. */ leaveChannel(e) { this.channels[e] && (this.channels[e].unsubscribe(), delete this.channels[e]); } /** * Get the socket ID for the connection. */ socketId() { return this.pusher.connection.socket_id; } /** * Get the current connection status. */ connectionStatus() { const e = this.pusher.connection.state; switch (e) { case "connected": case "connecting": return e; case "failed": case "unavailable": return "failed"; default: return "disconnected"; } } /** * Subscribe to connection status changes. */ onConnectionChange(e) { const t = () => { e(this.connectionStatus()); }, s = ["state_change", "connected", "disconnected"]; return s.forEach((i) => { this.pusher.connection.bind(i, t); }), () => { s.forEach((i) => { this.pusher.connection.unbind(i, t); }); }; } /** * Disconnect Pusher connection. */ disconnect() { this.pusher.disconnect(); } } class Y extends m { constructor() { super(...arguments), this.channels = {}; } /** * Create a fresh Socket.io connection. */ connect() { const e = this.getSocketIO(); this.socket = e( this.options.host ?? void 0, this.options ), this.socket.io.on("reconnect", () => { Object.values(this.channels).forEach((t) => { t.subscribe(); }); }); } /** * Get socket.io module from global scope or options. */ getSocketIO() { if (typeof this.options.client < "u") return this.options.client; if (typeof window < "u" && typeof window.io < "u") return window.io; throw new Error( "Socket.io client not found. Should be globally available or passed via options.client" ); } /** * Listen for an event on a channel instance. */ listen(e, t, s) { return this.channel(e).listen(t, s); } /** * Get a channel instance by name. */ channel(e) { return this.channels[e] || (this.channels[e] = new V( this.socket, e, this.options )), this.channels[e]; } /** * Get a private channel instance by name. */ privateChannel(e) { return this.channels["private-" + e] || (this.channels["private-" + e] = new L( this.socket, "private-" + e, this.options )), this.channels["private-" + e]; } /** * Get a presence channel instance by name. */ presenceChannel(e) { return this.channels["presence-" + e] || (this.channels["presence-" + e] = new Q( this.socket, "presence-" + e, this.options )), this.channels["presence-" + e]; } /** * Leave the given channel, as well as its private and presence variants. */ leave(e) { [e, "private-" + e, "presence-" + e].forEach((t) => { this.leaveChannel(t); }); } /** * Leave the given channel. */ leaveChannel(e) { this.channels[e] && (this.channels[e].unsubscribe(), delete this.channels[e]); } /** * Get the socket ID for the connection. */ socketId() { return this.socket.id; } /** * Get the current connection status. */ connectionStatus() { return this.socket.connected ? "connected" : this.socket.io._reconnecting ? "reconnecting" : this.socket.id !== void 0 ? "disconnected" : "connecting"; } /** * Subscribe to connection status changes. */ onConnectionChange(e) { const t = () => { e(this.connectionStatus()); }, s = [ "connect", "disconnect", "connect_error", "reconnect_attempt", "reconnect", "reconnect_error", "reconnect_failed" ]; return s.forEach((i) => { this.socket.on(i, t); }), () => { s.forEach((i) => { this.socket.off(i, t); }); }; } /** * Disconnect Socketio connection. */ disconnect() { this.socket.disconnect(); } } class R extends m { constructor() { super(...arguments), this.channels = {}; } /** * Create a fresh connection. */ connect() { } /** * Listen for an event on a channel instance. */ listen(e, t, s) { return new E(); } /** * Get a channel instance by name. */ channel(e) { return new E(); } /** * Get a private channel instance by name. */ privateChannel(e) { return new O(); } /** * Get a private encrypted channel instance by name. */ encryptedPrivateChannel(e) { return new W(); } /** * Get a presence channel instance by name. */ presenceChannel(e) { return new N(); } /** * Leave the given channel, as well as its private and presence variants. */ leave(e) { } /** * Leave the given channel. */ leaveChannel(e) { } /** * Get the socket ID for the connection. */ socketId() { return "fake-socket-id"; } /** * Get the current connection status. */ connectionStatus() { return "connected"; } /** * Subscribe to connection status changes. */ onConnectionChange(e) { return () => { }; } /** * Disconnect the connection. */ disconnect() { } } class D { /** * Create a new class instance. */ constructor(e) { this.options = e, this.connect(), this.options.withoutInterceptors || this.registerInterceptors(); } /** * Get a channel instance by name. */ channel(e) { return this.connector.channel(e); } /** * Create a new connection. */ connect() { if (this.options.broadcaster === "reverb") this.connector = new w({ ...this.options, cluster: "" }); else if (this.options.broadcaster === "pusher") this.connector = new w(this.options); else if (this.options.broadcaster === "ably") this.connector = new w({ ...this.options, cluster: "", broadcaster: "pusher" }); else if (this.options.broadcaster === "socket.io") this.connector = new Y(this.options); else if (this.options.broadcaster === "null") this.connector = new R(this.options); else if (typeof this.options.broadcaster == "function" && U(this.options.broadcaster)) this.connector = new this.options.broadcaster(this.options); else throw new Error( `Broadcaster ${typeof this.options.broadcaster} ${String(this.options.broadcaster)} is not supported.` ); } /** * Disconnect from the Echo server. */ disconnect() { this.connector.disconnect(); } /** * Get a presence channel instance by name. */ join(e) { return this.connector.presenceChannel(e); } /** * Leave the given channel, as well as its private and presence variants. */ leave(e) { this.connector.leave(e); } /** * Leave the given channel. */ leaveChannel(e) { this.connector.leaveChannel(e); } /** * Leave all channels. */ leaveAllChannels() { for (const e in this.connector.channels) this.leaveChannel(e); } /** * Listen for an event on a channel instance. */ listen(e, t, s) { return this.connector.listen(e, t, s); } /** * Get a private channel instance by name. */ private(e) { return this.connector.privateChannel(e); } /** * Get a private encrypted channel instance by name. */ encryptedPrivate(e) { if (this.connectorSupportsEncryptedPrivateChannels(this.connector)) return this.connector.encryptedPrivateChannel(e); throw new Error( `Broadcaster ${typeof this.options.broadcaster} ${String( this.options.broadcaster )} does not support encrypted private channels.` ); } connectorSupportsEncryptedPrivateChannels(e) { return e instanceof w || e instanceof R; } /** * Get the Socket ID for the connection. */ socketId() { return this.connector.socketId(); } /** * Get the current connection status. */ connectionStatus() { return this.connector.connectionStatus(); } /** * Register 3rd party request interceptors. These are used to automatically * send a connections socket id to a Laravel app with a X-Socket-Id header. */ registerInterceptors() { typeof Vue < "u" && Vue?.http && this.registerVueRequestInterceptor(), typeof axios == "function" && this.registerAxiosRequestInterceptor(), typeof jQuery == "function" && this.registerjQueryAjaxSetup(), typeof Turbo == "object" && this.registerTurboRequestInterceptor(); } /** * Register a Vue HTTP interceptor to add the X-Socket-ID header. */ registerVueRequestInterceptor() { Vue.http.interceptors.push( (e, t) => { this.socketId() && e.headers.set("X-Socket-ID", this.socketId()), t(); } ); } /** * Register an Axios HTTP interceptor to add the X-Socket-ID header. */ registerAxiosRequestInterceptor() { axios.interceptors.request.use( (e) => (this.socketId() && (e.headers["X-Socket-Id"] = this.socketId()), e) ); } /** * Register jQuery AjaxPrefilter to add the X-Socket-ID header. */ registerjQueryAjaxSetup() { typeof jQuery.ajax < "u" && jQuery.ajaxPrefilter( (e, t, s) => { this.socketId() && s.setRequestHeader("X-Socket-Id", this.socketId()); } ); } /** * Register the Turbo Request interceptor to add the X-Socket-ID header. */ registerTurboRequestInterceptor() { document.addEventListener( "turbo:before-fetch-request", (e) => { e.detail.fetchOptions.headers["X-Socket-Id"] = this.socketId(); } ); } } let l = null, b = null; const M = () => { if (l) return l; if (!b) throw new Error( "Echo has not been configured. Please call `configureEcho()` with your configuration options before using Echo." ); return b.Pusher ??= q, l = new D(b), l; }, Z = () => b !== null, ee = (n) => { b = { ...{ reverb: { broadcaster: "reverb", key: (typeof import.meta.env !== 'undefined' ? import.meta.env.VITE_REVERB_APP_KEY : undefined), wsHost: (typeof import.meta.env !== 'undefined' ? import.meta.env.VITE_REVERB_HOST : undefined), wsPort: (typeof import.meta.env !== 'undefined' ? import.meta.env.VITE_REVERB_PORT : undefined), wssPort: (typeof import.meta.env !== 'undefined' ? import.meta.env.VITE_REVERB_PORT : undefined), forceTLS: ((typeof import.meta.env !== 'undefined' ? import.meta.env.VITE_REVERB_SCHEME : undefined) ?? "https") === "https", enabledTransports: ["ws", "wss"] }, pusher: { broadcaster: "pusher", key: (typeof import.meta.env !== 'undefined' ? import.meta.env.VITE_PUSHER_APP_KEY : undefined), cluster: (typeof import.meta.env !== 'undefined' ? import.meta.env.VITE_PUSHER_APP_CLUSTER : undefined), forceTLS: !0, wsHost: (typeof import.meta.env !== 'undefined' ? import.meta.env.VITE_PUSHER_HOST : undefined), wsPort: (typeof import.meta.env !== 'undefined' ? import.meta.env.VITE_PUSHER_PORT : undefined), wssPort: (typeof import.meta.env !== 'undefined' ? import.meta.env.VITE_PUSHER_PORT : undefined), enabledTransports: ["ws", "wss"] }, "socket.io": { broadcaster: "socket.io", host: (typeof import.meta.env !== 'undefined' ? import.meta.env.VITE_SOCKET_IO_HOST : undefined) }, null: { broadcaster: "null" }, ably: { broadcaster: "pusher", key: (typeof import.meta.env !== 'undefined' ? import.meta.env.VITE_ABLY_PUBLIC_KEY : undefined), wsHost: "realtime-pusher.ably.io", wsPort: 443, disableStats: !0, encrypted: !0 } }[n.broadcaster], ...n }, l && (l = null); }, p = () => M(), j = (n) => Array.isArray(n) ? n : [n], h = {}, $ = (n) => { if (h[n.id]) return h[n.id].count += 1, h[n.id].connection; const e = z(n); return h[n.id] = { count: 1, connection: e }, e; }, z = (n) => { const e = p(); return n.visibility === "presence" ? e.join(n.name) : n.visibility === "private" ? e.private(n.name) : e.channel(n.name); }, F = (n, e = !1) => { h[n.id] && (h[n.id].count -= 1, !(h[n.id].count > 0) && (delete h[n.id], e ? p().leave(n.name) : p().leaveChannel(n.id))); }; function y(n, e = [], t = () => { }, s = [], i = "private") { const r = v(t), c = v(!1); P( () => t, (a) => { r.value = a; } ); const d = { name: n, id: ["private", "presence"].includes(i) ? `${i}-${n}` : n, visibility: i }, u = $(d), f = Array.isArray(e) ? e : [e], o = () => { _(); }, _ = () => { c.value || (f.forEach((a) => { u.listen(a, r.value); }), c.value = !0); }, T = () => { c.value && (f.forEach((a) => { u.stopListening(a, r.value); }), c.value = !1); }, g = (a = !1) => { T(), F(d, a); }; return C(() => { o(); }), k(() => { g(); }), s.length > 0 && P( // eslint-disable-next-line @typescript-eslint/no-unsafe-return () => s, () => { g(), o(); }, { deep: !0 } ), { /** * Leave the channel */ leaveChannel: g, /** * Leave the channel and also its associated private and presence channels */ leave: () => g(!0), /** * Stop listening for event(s) without leaving the channel */ stopListening: T, /** * Listen for event(s) */ listen: _, /** * Channel instance */ channel: () => u }; } const te = (n, e = () => { }, t = [], s = []) => { const i = y( n, [], e, s, "private" ), r = j(t).map((o) => o.includes(".") ? [o, o.replace(/\./g, "\\")] : [o, o.replace(/\\/g, ".")]).flat(), c = v(!1), d = (o) => { c.value && (r.length === 0 || r.includes(o.type)) && e(o); }, u = () => { c.value || (i.channel().notification(d), c.value = !0); }, f = () => { c.value && (i.channel().stopListeningForNotification(d), c.value = !1); }; return C(() => { u(); }), k(() => { f(); }), { ...i, /** * Stop listening for notification events */ stopListening: f, /** * Listen for notification events */ listen: u }; }, ne = (n, e = [], t = () => { }, s = []) => y( n, e, t, s, "presence" ), se = (n, e = [], t = () => { }, s = []) => y( n, e, t, s, "public" ); function H(n, e = "private") { const t = { name: n, id: ["private", "presence"].includes(e) ? `${e}-${n}` : n, visibility: e }, s = $(t), i = (r = !1) => { F(t, r); }; return k(() => { i(); }), { /** * Leave the channel */ leaveChannel: i, /** * Leave the channel and also its associated private and presence channels */ leave: () => i(!0), /** * Channel instance */ channel: () => s }; } const ie = (n) => H(n, "presence"), re = (n) => H(n, "public"), oe = (n, e, t = [], s = () => { }, i = []) => y( `${n}.${e}`, j(t).map((r) => r.startsWith(".") ? r : `.${r}`), s, i, "private" ), B = (n, e = !0) => { const t = p(); let s; C(() => { e && n(t.connectionStatus()), s = t.connector.onConnectionChange(n); }), k(() => { s?.(); }); }, ce = () => { const n = p(), e = v(n.connectionStatus()); return B((t) => { e.value = t; }), e; }, he = () => { const n = p(), e = v(n.socketId()); return B(() => { e.value = n.socketId(); }, !1), e; }; export { ee as configureEcho, p as echo, Z as echoIsConfigured, H as useChannel, ce as useConnectionStatus, y as useEcho, oe as useEchoModel, te as useEchoNotification, ne as useEchoPresence, se as useEchoPublic, ie as usePresenceChannel, re as usePublicChannel, he as useSocketId }; //# sourceMappingURL=index.js.map