@looplay/sdk 0.7.0 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +101 -21
- package/dist/looplay-sdk-realtime.cjs.js +73 -0
- package/dist/looplay-sdk-realtime.cjs.js.map +1 -0
- package/dist/looplay-sdk-realtime.esm.js +71 -0
- package/dist/looplay-sdk-realtime.esm.js.map +1 -0
- package/dist/looplay-sdk-realtime.min.js +3 -0
- package/dist/looplay-sdk-realtime.min.js.map +1 -0
- package/dist/looplay-sdk.cjs.js +84 -8
- package/dist/looplay-sdk.cjs.js.map +1 -1
- package/dist/looplay-sdk.esm.js +84 -8
- package/dist/looplay-sdk.esm.js.map +1 -1
- package/dist/looplay-sdk.min.js +2 -2
- package/dist/looplay-sdk.min.js.map +1 -1
- package/dist/types/apps/LooplaySDK.types.d.ts +60 -0
- package/dist/types/apps/api-client.d.ts +11 -0
- package/dist/types/apps/service-client.d.ts +20 -1
- package/dist/types/apps/ws-client.d.ts +35 -0
- package/dist/types/realtime.d.ts +9 -0
- package/package.json +17 -1
package/README.md
CHANGED
|
@@ -10,8 +10,7 @@ API Reference: https://docs.looplay.gg/build-on-loopplay/looplay-sdk
|
|
|
10
10
|
- [Core concept: one SDK integration = one game](#core-concept-one-sdk-integration--one-game)
|
|
11
11
|
- [Tracking a game — hosted on Looplay or published anywhere else](#tracking-a-game--hosted-on-looplay-or-published-anywhere-else)
|
|
12
12
|
- [`LooplaySDK` — direct integration (your own backend/auth)](#looplaysdk--direct-integration-your-own-backendauth)
|
|
13
|
-
- [Store —
|
|
14
|
-
- [Purchases require your own backend](#purchases-require-your-own-backend)
|
|
13
|
+
- [Store — browsing and purchases](#store--browsing-and-purchases)
|
|
15
14
|
- [Rewarded ads via parent window](#rewarded-ads-via-parent-window)
|
|
16
15
|
- [Drop-in `<script>` tag (no build step required)](#drop-in-script-tag-no-build-step-required)
|
|
17
16
|
- [Auth storage tradeoff](#auth-storage-tradeoff)
|
|
@@ -128,34 +127,100 @@ const profile = await sdk.getMyProfile();
|
|
|
128
127
|
throws if the game doesn't exist or isn't live — a lightweight, read-only,
|
|
129
128
|
unauthenticated check. Use `'none'` (default) to skip it.
|
|
130
129
|
|
|
131
|
-
## Store —
|
|
130
|
+
## Store — browsing and purchases
|
|
132
131
|
|
|
133
|
-
The SDK exposes
|
|
134
|
-
|
|
135
|
-
|
|
132
|
+
The SDK exposes the game's coin store — storefront, public asset catalog,
|
|
133
|
+
the caller's own owned assets/purchase history, and (for a logged-in
|
|
134
|
+
player) purchasing an offer:
|
|
136
135
|
|
|
137
136
|
```ts
|
|
138
|
-
const store = await sdk.api!.getStore(gameId);
|
|
139
|
-
const assets = await sdk.api!.listGameAssets(gameId);
|
|
140
|
-
const owned = await sdk.api!.listMyGameAssets(gameId);
|
|
137
|
+
const store = await sdk.api!.getStore(gameId); // sections + offers, no auth required
|
|
138
|
+
const assets = await sdk.api!.listGameAssets(gameId); // public asset catalog, no auth required
|
|
139
|
+
const owned = await sdk.api!.listMyGameAssets(gameId); // requires a logged-in user
|
|
141
140
|
const purchases = await sdk.api!.listMyStorePurchases(gameId); // requires a logged-in user
|
|
141
|
+
|
|
142
|
+
// Spends the player's coin balance — requires a logged-in user, nothing
|
|
143
|
+
// else. No backend or secret needed: safe to call directly from the game.
|
|
144
|
+
const result = await sdk.api!.purchaseStoreOffer(gameId, 'starter_pack', { quantity: 1 });
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
`purchaseStoreOffer` signs a short-lived checkout token and redeems it in
|
|
148
|
+
one call — the same safety mechanism as the play-attempt token used for
|
|
149
|
+
tracking, not a static secret. This is enough for creators with no backend
|
|
150
|
+
of their own.
|
|
151
|
+
|
|
152
|
+
### Real-time updates (optional, separate import)
|
|
153
|
+
|
|
154
|
+
Purchases (and any other balance change — quest rewards, referral payouts,
|
|
155
|
+
...) also push a WebSocket event, useful for reacting from a different tab
|
|
156
|
+
than the one that made the call, or after a purchase completes out-of-band
|
|
157
|
+
(e.g. a hosted-checkout redirect flow). This lives in a **separate
|
|
158
|
+
`@looplay/sdk/realtime` subpath**, not the main `@looplay/sdk` import — it
|
|
159
|
+
pulls in `socket.io-client`, which most integrations (tracking-only or
|
|
160
|
+
store-browsing-only) don't need:
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
npm install socket.io-client # peer dependency, only needed if you import '@looplay/sdk/realtime'
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
import { WsClient } from '@looplay/sdk/realtime';
|
|
168
|
+
|
|
169
|
+
const ws = new WsClient({
|
|
170
|
+
baseUrl: 'https://api.looplay.gg',
|
|
171
|
+
getAccessToken: () => sdk.getAccessToken(), // reuse whatever you already pass to LooplaySDK/ApiClient
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
const unsubscribe = ws.onStorePurchase((event) => {
|
|
175
|
+
console.log(`Got ${event.quantity}x ${event.name}`, event.items);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
ws.onBalanceChange((event) => {
|
|
179
|
+
console.log('Balance changed', event.changeAmount, event.balanceType);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// later
|
|
183
|
+
unsubscribe();
|
|
142
184
|
```
|
|
143
185
|
|
|
144
|
-
|
|
186
|
+
The connection is opened lazily on the first `onBalanceChange`/
|
|
187
|
+
`onStorePurchase` call and closed once the last listener unsubscribes — a
|
|
188
|
+
`WsClient` you never subscribe on never opens a socket. Call
|
|
189
|
+
`ws.disconnect()` to close it immediately regardless of active listeners.
|
|
190
|
+
|
|
191
|
+
### Backend-initiated purchases (optional)
|
|
192
|
+
|
|
193
|
+
If you *do* have your own backend and want to initiate a purchase without
|
|
194
|
+
the player's browser involved (e.g. an admin grant, or a payment webhook),
|
|
195
|
+
use `ServiceClient`'s creator+game secret-pair methods instead — never
|
|
196
|
+
embed `x-creator-key`/`x-game-secret` in client/browser code:
|
|
197
|
+
|
|
198
|
+
```ts
|
|
199
|
+
import { ServiceClient } from '@looplay/sdk';
|
|
145
200
|
|
|
146
|
-
|
|
147
|
-
balance always requires the creator+game *secret* pair
|
|
148
|
-
(`x-creator-key`/`x-game-secret`), which must never be embedded in
|
|
149
|
-
client/browser code. To let players buy a store offer:
|
|
201
|
+
const service = new ServiceClient({ baseUrl: 'https://api.looplay.gg' });
|
|
150
202
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
203
|
+
const auth = {
|
|
204
|
+
creatorKey: process.env.LOOPLAY_CREATOR_KEY!,
|
|
205
|
+
gameSecret: process.env.LOOPLAY_GAME_SECRET!,
|
|
206
|
+
bearerToken: playerAccessToken, // the specific player you're purchasing on behalf of
|
|
207
|
+
};
|
|
156
208
|
|
|
157
|
-
|
|
158
|
-
|
|
209
|
+
const intent = await service.createGameStoreCheckoutIntent(auth, {
|
|
210
|
+
offerCode: 'starter_pack',
|
|
211
|
+
quantity: 1,
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
const result = await service.purchaseGameStoreOffer(auth, {
|
|
215
|
+
offerCode: intent.offerCode,
|
|
216
|
+
requestId: intent.requestId,
|
|
217
|
+
quantity: intent.quantity,
|
|
218
|
+
checkoutToken: intent.checkoutToken,
|
|
219
|
+
});
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
The player (if connected) receives the same `store_purchase_completed`
|
|
223
|
+
WebSocket event either way.
|
|
159
224
|
|
|
160
225
|
## Rewarded ads via parent window
|
|
161
226
|
|
|
@@ -222,6 +287,21 @@ directly, no bundler needed:
|
|
|
222
287
|
</script>
|
|
223
288
|
```
|
|
224
289
|
|
|
290
|
+
This bundle does **not** include real-time (`WsClient`)/`socket.io-client` —
|
|
291
|
+
that's a separate opt-in browser bundle, only needed if you want
|
|
292
|
+
`onBalanceChange`/`onStorePurchase`:
|
|
293
|
+
|
|
294
|
+
```html
|
|
295
|
+
<script src="https://unpkg.com/@looplay/sdk/realtime/browser"></script>
|
|
296
|
+
<script>
|
|
297
|
+
const ws = new LooplaySDKRealtime.WsClient({
|
|
298
|
+
baseUrl: 'https://api.looplay.gg',
|
|
299
|
+
getAccessToken: async () => myAccessToken,
|
|
300
|
+
});
|
|
301
|
+
ws.onStorePurchase((event) => console.log('purchased', event));
|
|
302
|
+
</script>
|
|
303
|
+
```
|
|
304
|
+
|
|
225
305
|
**Security note**: the origin check relies on `parentOrigin` (explicit option)
|
|
226
306
|
or `document.referrer`. Referrer can be stripped by `Referrer-Policy`, browser
|
|
227
307
|
privacy settings, or extensions — when that happens the check is skipped and
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var socket_ioClient = require('socket.io-client');
|
|
4
|
+
|
|
5
|
+
// src/apps/ws-client.ts
|
|
6
|
+
var WsClient = class {
|
|
7
|
+
constructor(options) {
|
|
8
|
+
this.options = options;
|
|
9
|
+
}
|
|
10
|
+
options;
|
|
11
|
+
socket;
|
|
12
|
+
connectPromise;
|
|
13
|
+
balanceListeners = /* @__PURE__ */ new Set();
|
|
14
|
+
purchaseListeners = /* @__PURE__ */ new Set();
|
|
15
|
+
/** Fires on every balance change — purchases, quest rewards, referral payouts, etc. */
|
|
16
|
+
onBalanceChange(listener) {
|
|
17
|
+
this.balanceListeners.add(listener);
|
|
18
|
+
void this.ensureConnected();
|
|
19
|
+
return () => {
|
|
20
|
+
this.balanceListeners.delete(listener);
|
|
21
|
+
this.disconnectIfIdle();
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/** Fires once a store purchase finishes — see `StorePurchaseCompletedEvent`. */
|
|
25
|
+
onStorePurchase(listener) {
|
|
26
|
+
this.purchaseListeners.add(listener);
|
|
27
|
+
void this.ensureConnected();
|
|
28
|
+
return () => {
|
|
29
|
+
this.purchaseListeners.delete(listener);
|
|
30
|
+
this.disconnectIfIdle();
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/** Closes the socket immediately, regardless of active listeners. */
|
|
34
|
+
disconnect() {
|
|
35
|
+
this.socket?.disconnect();
|
|
36
|
+
this.socket = void 0;
|
|
37
|
+
this.connectPromise = void 0;
|
|
38
|
+
}
|
|
39
|
+
async ensureConnected() {
|
|
40
|
+
if (this.socket?.connected) return this.socket;
|
|
41
|
+
if (this.connectPromise) return this.connectPromise;
|
|
42
|
+
this.connectPromise = (async () => {
|
|
43
|
+
const token = await this.options.getAccessToken();
|
|
44
|
+
if (!token) return void 0;
|
|
45
|
+
const socket = socket_ioClient.io(this.options.baseUrl, {
|
|
46
|
+
transports: ["websocket"],
|
|
47
|
+
auth: { token: `Bearer ${token}` }
|
|
48
|
+
});
|
|
49
|
+
socket.on("balance_change", (payload) => {
|
|
50
|
+
for (const listener of this.balanceListeners) listener(payload);
|
|
51
|
+
});
|
|
52
|
+
socket.on("store_purchase_completed", (payload) => {
|
|
53
|
+
for (const listener of this.purchaseListeners) listener(payload);
|
|
54
|
+
});
|
|
55
|
+
this.socket = socket;
|
|
56
|
+
return socket;
|
|
57
|
+
})();
|
|
58
|
+
try {
|
|
59
|
+
return await this.connectPromise;
|
|
60
|
+
} finally {
|
|
61
|
+
this.connectPromise = void 0;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
disconnectIfIdle() {
|
|
65
|
+
if (this.balanceListeners.size === 0 && this.purchaseListeners.size === 0) {
|
|
66
|
+
this.disconnect();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
exports.WsClient = WsClient;
|
|
72
|
+
//# sourceMappingURL=looplay-sdk-realtime.cjs.js.map
|
|
73
|
+
//# sourceMappingURL=looplay-sdk-realtime.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/apps/ws-client.ts"],"names":["io"],"mappings":";;;;;AAsBO,IAAM,WAAN,MAAe;AAAA,EAMpB,YAA6B,OAAA,EAA0B;AAA1B,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAAA,EAA2B;AAAA,EAA3B,OAAA;AAAA,EALrB,MAAA;AAAA,EACA,cAAA;AAAA,EACS,gBAAA,uBAAuB,GAAA,EAAkC;AAAA,EACzD,iBAAA,uBAAwB,GAAA,EAA2C;AAAA;AAAA,EAKpF,gBAAgB,QAAA,EAAoD;AAClE,IAAA,IAAA,CAAK,gBAAA,CAAiB,IAAI,QAAQ,CAAA;AAClC,IAAA,KAAK,KAAK,eAAA,EAAgB;AAC1B,IAAA,OAAO,MAAM;AACX,MAAA,IAAA,CAAK,gBAAA,CAAiB,OAAO,QAAQ,CAAA;AACrC,MAAA,IAAA,CAAK,gBAAA,EAAiB;AAAA,IACxB,CAAA;AAAA,EACF;AAAA;AAAA,EAGA,gBAAgB,QAAA,EAA6D;AAC3E,IAAA,IAAA,CAAK,iBAAA,CAAkB,IAAI,QAAQ,CAAA;AACnC,IAAA,KAAK,KAAK,eAAA,EAAgB;AAC1B,IAAA,OAAO,MAAM;AACX,MAAA,IAAA,CAAK,iBAAA,CAAkB,OAAO,QAAQ,CAAA;AACtC,MAAA,IAAA,CAAK,gBAAA,EAAiB;AAAA,IACxB,CAAA;AAAA,EACF;AAAA;AAAA,EAGA,UAAA,GAAmB;AACjB,IAAA,IAAA,CAAK,QAAQ,UAAA,EAAW;AACxB,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAA,CAAK,cAAA,GAAiB,MAAA;AAAA,EACxB;AAAA,EAEA,MAAc,eAAA,GAA+C;AAC3D,IAAA,IAAI,IAAA,CAAK,MAAA,EAAQ,SAAA,EAAW,OAAO,IAAA,CAAK,MAAA;AACxC,IAAA,IAAI,IAAA,CAAK,cAAA,EAAgB,OAAO,IAAA,CAAK,cAAA;AAErC,IAAA,IAAA,CAAK,kBAAkB,YAAY;AACjC,MAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,CAAK,OAAA,CAAQ,cAAA,EAAe;AAGhD,MAAA,IAAI,CAAC,OAAO,OAAO,MAAA;AAEnB,MAAA,MAAM,MAAA,GAASA,kBAAA,CAAG,IAAA,CAAK,OAAA,CAAQ,OAAA,EAAS;AAAA,QACtC,UAAA,EAAY,CAAC,WAAW,CAAA;AAAA,QACxB,IAAA,EAAM,EAAE,KAAA,EAAO,CAAA,OAAA,EAAU,KAAK,CAAA,CAAA;AAAG,OAClC,CAAA;AAED,MAAA,MAAA,CAAO,EAAA,CAAG,gBAAA,EAAkB,CAAC,OAAA,KAAgC;AAC3D,QAAA,KAAA,MAAW,QAAA,IAAY,IAAA,CAAK,gBAAA,EAAkB,QAAA,CAAS,OAAO,CAAA;AAAA,MAChE,CAAC,CAAA;AACD,MAAA,MAAA,CAAO,EAAA,CAAG,0BAAA,EAA4B,CAAC,OAAA,KAAyC;AAC9E,QAAA,KAAA,MAAW,QAAA,IAAY,IAAA,CAAK,iBAAA,EAAmB,QAAA,CAAS,OAAO,CAAA;AAAA,MACjE,CAAC,CAAA;AAED,MAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,MAAA,OAAO,MAAA;AAAA,IACT,CAAA,GAAG;AAEH,IAAA,IAAI;AACF,MAAA,OAAO,MAAM,IAAA,CAAK,cAAA;AAAA,IACpB,CAAA,SAAE;AACA,MAAA,IAAA,CAAK,cAAA,GAAiB,MAAA;AAAA,IACxB;AAAA,EACF;AAAA,EAEQ,gBAAA,GAAyB;AAC/B,IAAA,IAAI,KAAK,gBAAA,CAAiB,IAAA,KAAS,KAAK,IAAA,CAAK,iBAAA,CAAkB,SAAS,CAAA,EAAG;AACzE,MAAA,IAAA,CAAK,UAAA,EAAW;AAAA,IAClB;AAAA,EACF;AACF","file":"looplay-sdk-realtime.cjs.js","sourcesContent":["import { io, type Socket } from 'socket.io-client';\nimport type { BalanceChangeEvent, StorePurchaseCompletedEvent } from './LooplaySDK.types';\n\nexport interface WsClientOptions {\n baseUrl: string;\n /** Resolves the current player's access token — re-checked on every (re)connect. */\n getAccessToken: () => Promise<string | undefined>;\n}\n\ntype Listener<T> = (payload: T) => void;\n\n/**\n * Lazy-connecting Socket.IO client mirroring gbs-service's AppGateway.\n * Both events it exposes (`balance_change`, `store_purchase_completed`) are\n * pushed only to the authenticated player's own room — there is nothing to\n * receive without an access token, so `subscribe*` is a no-op until one is\n * available.\n *\n * The connection is opened on the first subscription and closed once the\n * last listener unsubscribes — a game that never calls `onBalanceChange`/\n * `onStorePurchase` never opens a socket at all.\n */\nexport class WsClient {\n private socket?: Socket;\n private connectPromise?: Promise<Socket | undefined>;\n private readonly balanceListeners = new Set<Listener<BalanceChangeEvent>>();\n private readonly purchaseListeners = new Set<Listener<StorePurchaseCompletedEvent>>();\n\n constructor(private readonly options: WsClientOptions) {}\n\n /** Fires on every balance change — purchases, quest rewards, referral payouts, etc. */\n onBalanceChange(listener: Listener<BalanceChangeEvent>): () => void {\n this.balanceListeners.add(listener);\n void this.ensureConnected();\n return () => {\n this.balanceListeners.delete(listener);\n this.disconnectIfIdle();\n };\n }\n\n /** Fires once a store purchase finishes — see `StorePurchaseCompletedEvent`. */\n onStorePurchase(listener: Listener<StorePurchaseCompletedEvent>): () => void {\n this.purchaseListeners.add(listener);\n void this.ensureConnected();\n return () => {\n this.purchaseListeners.delete(listener);\n this.disconnectIfIdle();\n };\n }\n\n /** Closes the socket immediately, regardless of active listeners. */\n disconnect(): void {\n this.socket?.disconnect();\n this.socket = undefined;\n this.connectPromise = undefined;\n }\n\n private async ensureConnected(): Promise<Socket | undefined> {\n if (this.socket?.connected) return this.socket;\n if (this.connectPromise) return this.connectPromise;\n\n this.connectPromise = (async () => {\n const token = await this.options.getAccessToken();\n // Both events are user-room-scoped — an unauthenticated socket would\n // never receive anything, so don't bother opening one.\n if (!token) return undefined;\n\n const socket = io(this.options.baseUrl, {\n transports: ['websocket'],\n auth: { token: `Bearer ${token}` },\n });\n\n socket.on('balance_change', (payload: BalanceChangeEvent) => {\n for (const listener of this.balanceListeners) listener(payload);\n });\n socket.on('store_purchase_completed', (payload: StorePurchaseCompletedEvent) => {\n for (const listener of this.purchaseListeners) listener(payload);\n });\n\n this.socket = socket;\n return socket;\n })();\n\n try {\n return await this.connectPromise;\n } finally {\n this.connectPromise = undefined;\n }\n }\n\n private disconnectIfIdle(): void {\n if (this.balanceListeners.size === 0 && this.purchaseListeners.size === 0) {\n this.disconnect();\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { io } from 'socket.io-client';
|
|
2
|
+
|
|
3
|
+
// src/apps/ws-client.ts
|
|
4
|
+
var WsClient = class {
|
|
5
|
+
constructor(options) {
|
|
6
|
+
this.options = options;
|
|
7
|
+
}
|
|
8
|
+
options;
|
|
9
|
+
socket;
|
|
10
|
+
connectPromise;
|
|
11
|
+
balanceListeners = /* @__PURE__ */ new Set();
|
|
12
|
+
purchaseListeners = /* @__PURE__ */ new Set();
|
|
13
|
+
/** Fires on every balance change — purchases, quest rewards, referral payouts, etc. */
|
|
14
|
+
onBalanceChange(listener) {
|
|
15
|
+
this.balanceListeners.add(listener);
|
|
16
|
+
void this.ensureConnected();
|
|
17
|
+
return () => {
|
|
18
|
+
this.balanceListeners.delete(listener);
|
|
19
|
+
this.disconnectIfIdle();
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/** Fires once a store purchase finishes — see `StorePurchaseCompletedEvent`. */
|
|
23
|
+
onStorePurchase(listener) {
|
|
24
|
+
this.purchaseListeners.add(listener);
|
|
25
|
+
void this.ensureConnected();
|
|
26
|
+
return () => {
|
|
27
|
+
this.purchaseListeners.delete(listener);
|
|
28
|
+
this.disconnectIfIdle();
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/** Closes the socket immediately, regardless of active listeners. */
|
|
32
|
+
disconnect() {
|
|
33
|
+
this.socket?.disconnect();
|
|
34
|
+
this.socket = void 0;
|
|
35
|
+
this.connectPromise = void 0;
|
|
36
|
+
}
|
|
37
|
+
async ensureConnected() {
|
|
38
|
+
if (this.socket?.connected) return this.socket;
|
|
39
|
+
if (this.connectPromise) return this.connectPromise;
|
|
40
|
+
this.connectPromise = (async () => {
|
|
41
|
+
const token = await this.options.getAccessToken();
|
|
42
|
+
if (!token) return void 0;
|
|
43
|
+
const socket = io(this.options.baseUrl, {
|
|
44
|
+
transports: ["websocket"],
|
|
45
|
+
auth: { token: `Bearer ${token}` }
|
|
46
|
+
});
|
|
47
|
+
socket.on("balance_change", (payload) => {
|
|
48
|
+
for (const listener of this.balanceListeners) listener(payload);
|
|
49
|
+
});
|
|
50
|
+
socket.on("store_purchase_completed", (payload) => {
|
|
51
|
+
for (const listener of this.purchaseListeners) listener(payload);
|
|
52
|
+
});
|
|
53
|
+
this.socket = socket;
|
|
54
|
+
return socket;
|
|
55
|
+
})();
|
|
56
|
+
try {
|
|
57
|
+
return await this.connectPromise;
|
|
58
|
+
} finally {
|
|
59
|
+
this.connectPromise = void 0;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
disconnectIfIdle() {
|
|
63
|
+
if (this.balanceListeners.size === 0 && this.purchaseListeners.size === 0) {
|
|
64
|
+
this.disconnect();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export { WsClient };
|
|
70
|
+
//# sourceMappingURL=looplay-sdk-realtime.esm.js.map
|
|
71
|
+
//# sourceMappingURL=looplay-sdk-realtime.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/apps/ws-client.ts"],"names":[],"mappings":";;;AAsBO,IAAM,WAAN,MAAe;AAAA,EAMpB,YAA6B,OAAA,EAA0B;AAA1B,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAAA,EAA2B;AAAA,EAA3B,OAAA;AAAA,EALrB,MAAA;AAAA,EACA,cAAA;AAAA,EACS,gBAAA,uBAAuB,GAAA,EAAkC;AAAA,EACzD,iBAAA,uBAAwB,GAAA,EAA2C;AAAA;AAAA,EAKpF,gBAAgB,QAAA,EAAoD;AAClE,IAAA,IAAA,CAAK,gBAAA,CAAiB,IAAI,QAAQ,CAAA;AAClC,IAAA,KAAK,KAAK,eAAA,EAAgB;AAC1B,IAAA,OAAO,MAAM;AACX,MAAA,IAAA,CAAK,gBAAA,CAAiB,OAAO,QAAQ,CAAA;AACrC,MAAA,IAAA,CAAK,gBAAA,EAAiB;AAAA,IACxB,CAAA;AAAA,EACF;AAAA;AAAA,EAGA,gBAAgB,QAAA,EAA6D;AAC3E,IAAA,IAAA,CAAK,iBAAA,CAAkB,IAAI,QAAQ,CAAA;AACnC,IAAA,KAAK,KAAK,eAAA,EAAgB;AAC1B,IAAA,OAAO,MAAM;AACX,MAAA,IAAA,CAAK,iBAAA,CAAkB,OAAO,QAAQ,CAAA;AACtC,MAAA,IAAA,CAAK,gBAAA,EAAiB;AAAA,IACxB,CAAA;AAAA,EACF;AAAA;AAAA,EAGA,UAAA,GAAmB;AACjB,IAAA,IAAA,CAAK,QAAQ,UAAA,EAAW;AACxB,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAA,CAAK,cAAA,GAAiB,MAAA;AAAA,EACxB;AAAA,EAEA,MAAc,eAAA,GAA+C;AAC3D,IAAA,IAAI,IAAA,CAAK,MAAA,EAAQ,SAAA,EAAW,OAAO,IAAA,CAAK,MAAA;AACxC,IAAA,IAAI,IAAA,CAAK,cAAA,EAAgB,OAAO,IAAA,CAAK,cAAA;AAErC,IAAA,IAAA,CAAK,kBAAkB,YAAY;AACjC,MAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,CAAK,OAAA,CAAQ,cAAA,EAAe;AAGhD,MAAA,IAAI,CAAC,OAAO,OAAO,MAAA;AAEnB,MAAA,MAAM,MAAA,GAAS,EAAA,CAAG,IAAA,CAAK,OAAA,CAAQ,OAAA,EAAS;AAAA,QACtC,UAAA,EAAY,CAAC,WAAW,CAAA;AAAA,QACxB,IAAA,EAAM,EAAE,KAAA,EAAO,CAAA,OAAA,EAAU,KAAK,CAAA,CAAA;AAAG,OAClC,CAAA;AAED,MAAA,MAAA,CAAO,EAAA,CAAG,gBAAA,EAAkB,CAAC,OAAA,KAAgC;AAC3D,QAAA,KAAA,MAAW,QAAA,IAAY,IAAA,CAAK,gBAAA,EAAkB,QAAA,CAAS,OAAO,CAAA;AAAA,MAChE,CAAC,CAAA;AACD,MAAA,MAAA,CAAO,EAAA,CAAG,0BAAA,EAA4B,CAAC,OAAA,KAAyC;AAC9E,QAAA,KAAA,MAAW,QAAA,IAAY,IAAA,CAAK,iBAAA,EAAmB,QAAA,CAAS,OAAO,CAAA;AAAA,MACjE,CAAC,CAAA;AAED,MAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,MAAA,OAAO,MAAA;AAAA,IACT,CAAA,GAAG;AAEH,IAAA,IAAI;AACF,MAAA,OAAO,MAAM,IAAA,CAAK,cAAA;AAAA,IACpB,CAAA,SAAE;AACA,MAAA,IAAA,CAAK,cAAA,GAAiB,MAAA;AAAA,IACxB;AAAA,EACF;AAAA,EAEQ,gBAAA,GAAyB;AAC/B,IAAA,IAAI,KAAK,gBAAA,CAAiB,IAAA,KAAS,KAAK,IAAA,CAAK,iBAAA,CAAkB,SAAS,CAAA,EAAG;AACzE,MAAA,IAAA,CAAK,UAAA,EAAW;AAAA,IAClB;AAAA,EACF;AACF","file":"looplay-sdk-realtime.esm.js","sourcesContent":["import { io, type Socket } from 'socket.io-client';\nimport type { BalanceChangeEvent, StorePurchaseCompletedEvent } from './LooplaySDK.types';\n\nexport interface WsClientOptions {\n baseUrl: string;\n /** Resolves the current player's access token — re-checked on every (re)connect. */\n getAccessToken: () => Promise<string | undefined>;\n}\n\ntype Listener<T> = (payload: T) => void;\n\n/**\n * Lazy-connecting Socket.IO client mirroring gbs-service's AppGateway.\n * Both events it exposes (`balance_change`, `store_purchase_completed`) are\n * pushed only to the authenticated player's own room — there is nothing to\n * receive without an access token, so `subscribe*` is a no-op until one is\n * available.\n *\n * The connection is opened on the first subscription and closed once the\n * last listener unsubscribes — a game that never calls `onBalanceChange`/\n * `onStorePurchase` never opens a socket at all.\n */\nexport class WsClient {\n private socket?: Socket;\n private connectPromise?: Promise<Socket | undefined>;\n private readonly balanceListeners = new Set<Listener<BalanceChangeEvent>>();\n private readonly purchaseListeners = new Set<Listener<StorePurchaseCompletedEvent>>();\n\n constructor(private readonly options: WsClientOptions) {}\n\n /** Fires on every balance change — purchases, quest rewards, referral payouts, etc. */\n onBalanceChange(listener: Listener<BalanceChangeEvent>): () => void {\n this.balanceListeners.add(listener);\n void this.ensureConnected();\n return () => {\n this.balanceListeners.delete(listener);\n this.disconnectIfIdle();\n };\n }\n\n /** Fires once a store purchase finishes — see `StorePurchaseCompletedEvent`. */\n onStorePurchase(listener: Listener<StorePurchaseCompletedEvent>): () => void {\n this.purchaseListeners.add(listener);\n void this.ensureConnected();\n return () => {\n this.purchaseListeners.delete(listener);\n this.disconnectIfIdle();\n };\n }\n\n /** Closes the socket immediately, regardless of active listeners. */\n disconnect(): void {\n this.socket?.disconnect();\n this.socket = undefined;\n this.connectPromise = undefined;\n }\n\n private async ensureConnected(): Promise<Socket | undefined> {\n if (this.socket?.connected) return this.socket;\n if (this.connectPromise) return this.connectPromise;\n\n this.connectPromise = (async () => {\n const token = await this.options.getAccessToken();\n // Both events are user-room-scoped — an unauthenticated socket would\n // never receive anything, so don't bother opening one.\n if (!token) return undefined;\n\n const socket = io(this.options.baseUrl, {\n transports: ['websocket'],\n auth: { token: `Bearer ${token}` },\n });\n\n socket.on('balance_change', (payload: BalanceChangeEvent) => {\n for (const listener of this.balanceListeners) listener(payload);\n });\n socket.on('store_purchase_completed', (payload: StorePurchaseCompletedEvent) => {\n for (const listener of this.purchaseListeners) listener(payload);\n });\n\n this.socket = socket;\n return socket;\n })();\n\n try {\n return await this.connectPromise;\n } finally {\n this.connectPromise = undefined;\n }\n }\n\n private disconnectIfIdle(): void {\n if (this.balanceListeners.size === 0 && this.purchaseListeners.size === 0) {\n this.disconnect();\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
var LooplaySDKRealtime=(function(exports){'use strict';var Ve=Object.defineProperty;var Me=(s,e)=>{for(var t in e)Ve(s,t,{get:e[t],enumerable:true});};var d=Object.create(null);d.open="0";d.close="1";d.ping="2";d.pong="3";d.message="4";d.upgrade="5";d.noop="6";var B=Object.create(null);Object.keys(d).forEach(s=>{B[d[s]]=s;});var N={type:"error",data:"parser error"};var le=typeof Blob=="function"||typeof Blob<"u"&&Object.prototype.toString.call(Blob)==="[object BlobConstructor]",pe=typeof ArrayBuffer=="function",de=s=>typeof ArrayBuffer.isView=="function"?ArrayBuffer.isView(s):s&&s.buffer instanceof ArrayBuffer,L=({type:s,data:e},t,r)=>le&&e instanceof Blob?t?r(e):fe(e,r):pe&&(e instanceof ArrayBuffer||de(e))?t?r(e):fe(new Blob([e]),r):r(d[s]+(e||"")),fe=(s,e)=>{let t=new FileReader;return t.onload=function(){let r=t.result.split(",")[1];e("b"+(r||""));},t.readAsDataURL(s)};function ue(s){return s instanceof Uint8Array?s:s instanceof ArrayBuffer?new Uint8Array(s):new Uint8Array(s.buffer,s.byteOffset,s.byteLength)}var Q;function me(s,e){if(le&&s.data instanceof Blob)return s.data.arrayBuffer().then(ue).then(e);if(pe&&(s.data instanceof ArrayBuffer||de(s.data)))return e(ue(s.data));L(s,false,t=>{Q||(Q=new TextEncoder),e(Q.encode(t));});}var ye="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",P=typeof Uint8Array>"u"?[]:new Uint8Array(256);for(let s=0;s<ye.length;s++)P[ye.charCodeAt(s)]=s;var ge=s=>{let e=s.length*.75,t=s.length,r,i=0,n,o,c,h;s[s.length-1]==="="&&(e--,s[s.length-2]==="="&&e--);let m=new ArrayBuffer(e),p=new Uint8Array(m);for(r=0;r<t;r+=4)n=P[s.charCodeAt(r)],o=P[s.charCodeAt(r+1)],c=P[s.charCodeAt(r+2)],h=P[s.charCodeAt(r+3)],p[i++]=n<<2|o>>4,p[i++]=(o&15)<<4|c>>2,p[i++]=(c&3)<<6|h&63;return m};var He=typeof ArrayBuffer=="function",q=(s,e)=>{if(typeof s!="string")return {type:"message",data:_e(s,e)};let t=s.charAt(0);return t==="b"?{type:"message",data:We(s.substring(1),e)}:B[t]?s.length>1?{type:B[t],data:s.substring(1)}:{type:B[t]}:N},We=(s,e)=>{if(He){let t=ge(s);return _e(t,e)}else return {base64:true,data:s}},_e=(s,e)=>e==="blob"?s instanceof Blob?s:new Blob([s]):s instanceof ArrayBuffer?s:s.buffer;var be="",we=(s,e)=>{let t=s.length,r=new Array(t),i=0;s.forEach((n,o)=>{L(n,false,c=>{r[o]=c,++i===t&&e(r.join(be));});});},Ee=(s,e)=>{let t=s.split(be),r=[];for(let i=0;i<t.length;i++){let n=q(t[i],e);if(r.push(n),n.type==="error")break}return r};function ve(){return new TransformStream({transform(s,e){me(s,t=>{let r=t.length,i;if(r<126)i=new Uint8Array(1),new DataView(i.buffer).setUint8(0,r);else if(r<65536){i=new Uint8Array(3);let n=new DataView(i.buffer);n.setUint8(0,126),n.setUint16(1,r);}else {i=new Uint8Array(9);let n=new DataView(i.buffer);n.setUint8(0,127),n.setBigUint64(1,BigInt(r));}s.data&&typeof s.data!="string"&&(i[0]|=128),e.enqueue(i),e.enqueue(t);});}})}var G;function M(s){return s.reduce((e,t)=>e+t.length,0)}function H(s,e){if(s[0].length===e)return s.shift();let t=new Uint8Array(e),r=0;for(let i=0;i<e;i++)t[i]=s[0][r++],r===s[0].length&&(s.shift(),r=0);return s.length&&r<s[0].length&&(s[0]=s[0].slice(r)),t}function ke(s,e){G||(G=new TextDecoder);let t=[],r=0,i=-1,n=false;return new TransformStream({transform(o,c){for(t.push(o);;){if(r===0){if(M(t)<1)break;let h=H(t,1);n=(h[0]&128)===128,i=h[0]&127,i<126?r=3:i===126?r=1:r=2;}else if(r===1){if(M(t)<2)break;let h=H(t,2);i=new DataView(h.buffer,h.byteOffset,h.length).getUint16(0),r=3;}else if(r===2){if(M(t)<8)break;let h=H(t,8),m=new DataView(h.buffer,h.byteOffset,h.length),p=m.getUint32(0);if(p>Math.pow(2,21)-1){c.enqueue(N);break}i=p*Math.pow(2,32)+m.getUint32(4),r=3;}else {if(M(t)<i)break;let h=H(t,i);c.enqueue(q(n?h:G.decode(h),e)),r=0;}if(i===0||i>s){c.enqueue(N);break}}}})}var j=4;function f(s){if(s)return Ke(s)}function Ke(s){for(var e in f.prototype)s[e]=f.prototype[e];return s}f.prototype.on=f.prototype.addEventListener=function(s,e){return this._callbacks=this._callbacks||{},(this._callbacks["$"+s]=this._callbacks["$"+s]||[]).push(e),this};f.prototype.once=function(s,e){function t(){this.off(s,t),e.apply(this,arguments);}return t.fn=e,this.on(s,t),this};f.prototype.off=f.prototype.removeListener=f.prototype.removeAllListeners=f.prototype.removeEventListener=function(s,e){if(this._callbacks=this._callbacks||{},arguments.length==0)return this._callbacks={},this;var t=this._callbacks["$"+s];if(!t)return this;if(arguments.length==1)return delete this._callbacks["$"+s],this;for(var r,i=0;i<t.length;i++)if(r=t[i],r===e||r.fn===e){t.splice(i,1);break}return t.length===0&&delete this._callbacks["$"+s],this};f.prototype.emit=function(s){this._callbacks=this._callbacks||{};for(var e=new Array(arguments.length-1),t=this._callbacks["$"+s],r=1;r<arguments.length;r++)e[r-1]=arguments[r];if(t){t=t.slice(0);for(var r=0,i=t.length;r<i;++r)t[r].apply(this,e);}return this};f.prototype.emitReserved=f.prototype.emit;f.prototype.listeners=function(s){return this._callbacks=this._callbacks||{},this._callbacks["$"+s]||[]};f.prototype.hasListeners=function(s){return !!this.listeners(s).length};var y=typeof Promise=="function"&&typeof Promise.resolve=="function"?e=>Promise.resolve().then(e):(e,t)=>t(e,0),u=typeof self<"u"?self:typeof window<"u"?window:Function("return this")(),xe="arraybuffer";function W(s,...e){return e.reduce((t,r)=>(s.hasOwnProperty(r)&&(t[r]=s[r]),t),{})}var Ye=u.setTimeout,Je=u.clearTimeout;function g(s,e){e.useNativeTimers?(s.setTimeoutFn=Ye.bind(u),s.clearTimeoutFn=Je.bind(u)):(s.setTimeoutFn=u.setTimeout.bind(u),s.clearTimeoutFn=u.clearTimeout.bind(u));}var ze=1.33;function Te(s){return typeof s=="string"?Xe(s):Math.ceil((s.byteLength||s.size)*ze)}function Xe(s){let e=0,t=0;for(let r=0,i=s.length;r<i;r++)e=s.charCodeAt(r),e<128?t+=1:e<2048?t+=2:e<55296||e>=57344?t+=3:(r++,t+=4);return t}function K(){return Date.now().toString(36).substring(3)+Math.random().toString(36).substring(2,5)}function Ae(s){let e="";for(let t in s)s.hasOwnProperty(t)&&(e.length&&(e+="&"),e+=encodeURIComponent(t)+"="+encodeURIComponent(s[t]));return e}function Ce(s){let e={},t=s.split("&");for(let r=0,i=t.length;r<i;r++){let n=t[r].split("=");e[decodeURIComponent(n[0])]=decodeURIComponent(n[1]);}return e}var Y=class extends Error{constructor(e,t,r){super(e),this.description=t,this.context=r,this.type="TransportError";}},_=class extends f{constructor(e){super(),this.writable=false,g(this,e),this.opts=e,this.query=e.query,this.socket=e.socket,this.supportsBinary=!e.forceBase64;}onError(e,t,r){return super.emitReserved("error",new Y(e,t,r)),this}open(){return this.readyState="opening",this.doOpen(),this}close(){return (this.readyState==="opening"||this.readyState==="open")&&(this.doClose(),this.onClose()),this}send(e){this.readyState==="open"&&this.write(e);}onOpen(){this.readyState="open",this.writable=true,super.emitReserved("open");}onData(e){let t=q(e,this.socket.binaryType);this.onPacket(t);}onPacket(e){super.emitReserved("packet",e);}onClose(e){this.readyState="closed",super.emitReserved("close",e);}pause(e){}createUri(e,t={}){return e+"://"+this._hostname()+this._port()+this.opts.path+this._query(t)}_hostname(){let e=this.opts.hostname;return e.indexOf(":")===-1?e:"["+e+"]"}_port(){return this.opts.port&&(this.opts.secure&&Number(this.opts.port)!==443||!this.opts.secure&&Number(this.opts.port)!==80)?":"+this.opts.port:""}_query(e){let t=Ae(e);return t.length?"?"+t:""}};var D=class extends _{constructor(){super(...arguments),this._polling=false;}get name(){return "polling"}doOpen(){this._poll();}pause(e){this.readyState="pausing";let t=()=>{this.readyState="paused",e();};if(this._polling||!this.writable){let r=0;this._polling&&(r++,this.once("pollComplete",function(){--r||t();})),this.writable||(r++,this.once("drain",function(){--r||t();}));}else t();}_poll(){this._polling=true,this.doPoll(),this.emitReserved("poll");}onData(e){let t=r=>{if(this.readyState==="opening"&&r.type==="open"&&this.onOpen(),r.type==="close")return this.onClose({description:"transport closed by the server"}),false;this.onPacket(r);};Ee(e,this.socket.binaryType).forEach(t),this.readyState!=="closed"&&(this._polling=false,this.emitReserved("pollComplete"),this.readyState==="open"&&this._poll());}doClose(){let e=()=>{this.write([{type:"close"}]);};this.readyState==="open"?e():this.once("open",e);}write(e){this.writable=false,we(e,t=>{this.doWrite(t,()=>{this.writable=true,this.emitReserved("drain");});});}uri(){let e=this.opts.secure?"https":"http",t=this.query||{};return this.opts.timestampRequests!==false&&(t[this.opts.timestampParam]=K()),!this.supportsBinary&&!t.sid&&(t.b64=1),this.createUri(e,t)}};var Se=false;try{Se=typeof XMLHttpRequest<"u"&&"withCredentials"in new XMLHttpRequest;}catch{}var Re=Se;function $e(){}var Z=class extends D{constructor(e){if(super(e),typeof location<"u"){let t=location.protocol==="https:",r=location.port;r||(r=t?"443":"80"),this.xd=typeof location<"u"&&e.hostname!==location.hostname||r!==e.port;}}doWrite(e,t){let r=this.request({method:"POST",data:e});r.on("success",t),r.on("error",(i,n)=>{this.onError("xhr post error",i,n);});}doPoll(){let e=this.request();e.on("data",this.onData.bind(this)),e.on("error",(t,r)=>{this.onError("xhr poll error",t,r);}),this.pollXhr=e;}},w=class s extends f{constructor(e,t,r){super(),this.createRequest=e,g(this,r),this._opts=r,this._method=r.method||"GET",this._uri=t,this._data=r.data!==void 0?r.data:null,this._create();}_create(){var e;let t=W(this._opts,"agent","pfx","key","passphrase","cert","ca","ciphers","rejectUnauthorized","autoUnref");t.xdomain=!!this._opts.xd;let r=this._xhr=this.createRequest(t);try{r.open(this._method,this._uri,!0);try{if(this._opts.extraHeaders){r.setDisableHeaderCheck&&r.setDisableHeaderCheck(!0);for(let i in this._opts.extraHeaders)this._opts.extraHeaders.hasOwnProperty(i)&&r.setRequestHeader(i,this._opts.extraHeaders[i]);}}catch{}if(this._method==="POST")try{r.setRequestHeader("Content-type","text/plain;charset=UTF-8");}catch{}try{r.setRequestHeader("Accept","*/*");}catch{}(e=this._opts.cookieJar)===null||e===void 0||e.addCookies(r),"withCredentials"in r&&(r.withCredentials=this._opts.withCredentials),this._opts.requestTimeout&&(r.timeout=this._opts.requestTimeout),r.onreadystatechange=()=>{var i;r.readyState===3&&((i=this._opts.cookieJar)===null||i===void 0||i.parseCookies(r.getResponseHeader("set-cookie"))),r.readyState===4&&(r.status===200||r.status===1223?this._onLoad():this.setTimeoutFn(()=>{this._onError(typeof r.status=="number"?r.status:0);},0));},r.send(this._data);}catch(i){this.setTimeoutFn(()=>{this._onError(i);},0);return}typeof document<"u"&&(this._index=s.requestsCount++,s.requests[this._index]=this);}_onError(e){this.emitReserved("error",e,this._xhr),this._cleanup(true);}_cleanup(e){if(!(typeof this._xhr>"u"||this._xhr===null)){if(this._xhr.onreadystatechange=$e,e)try{this._xhr.abort();}catch{}typeof document<"u"&&delete s.requests[this._index],this._xhr=null;}}_onLoad(){let e=this._xhr.responseText;e!==null&&(this.emitReserved("data",e),this.emitReserved("success"),this._cleanup());}abort(){this._cleanup();}};w.requestsCount=0;w.requests={};if(typeof document<"u"){if(typeof attachEvent=="function")attachEvent("onunload",Oe);else if(typeof addEventListener=="function"){let s="onpagehide"in u?"pagehide":"unload";addEventListener(s,Oe,false);}}function Oe(){for(let s in w.requests)w.requests.hasOwnProperty(s)&&w.requests[s].abort();}var Qe=(function(){let s=Be({xdomain:false});return s&&s.responseType!==null})(),E=class extends Z{constructor(e){super(e);let t=e&&e.forceBase64;this.supportsBinary=Qe&&!t;}request(e={}){return Object.assign(e,{xd:this.xd},this.opts),new w(Be,this.uri(),e)}};function Be(s){let e=s.xdomain;try{if(typeof XMLHttpRequest<"u"&&(!e||Re))return new XMLHttpRequest}catch{}if(!e)try{return new u[["Active"].concat("Object").join("X")]("Microsoft.XMLHTTP")}catch{}}var Ne=typeof navigator<"u"&&typeof navigator.product=="string"&&navigator.product.toLowerCase()==="reactnative",te=class extends _{get name(){return "websocket"}doOpen(){let e=this.uri(),t=this.opts.protocols,r=Ne?{}:W(this.opts,"agent","perMessageDeflate","pfx","key","passphrase","cert","ca","ciphers","rejectUnauthorized","localAddress","protocolVersion","origin","maxPayload","family","checkServerIdentity");this.opts.extraHeaders&&(r.headers=this.opts.extraHeaders);try{this.ws=this.createSocket(e,t,r);}catch(i){return this.emitReserved("error",i)}this.ws.binaryType=this.socket.binaryType,this.addEventListeners();}addEventListeners(){this.ws.onopen=()=>{this.opts.autoUnref&&this.ws._socket.unref(),this.onOpen();},this.ws.onclose=e=>this.onClose({description:"websocket connection closed",context:e}),this.ws.onmessage=e=>this.onData(e.data),this.ws.onerror=e=>this.onError("websocket error",e);}write(e){this.writable=false;for(let t=0;t<e.length;t++){let r=e[t],i=t===e.length-1;L(r,this.supportsBinary,n=>{try{this.doWrite(r,n);}catch{}i&&y(()=>{this.writable=true,this.emitReserved("drain");},this.setTimeoutFn);});}}doClose(){typeof this.ws<"u"&&(this.ws.onerror=()=>{},this.ws.close(),this.ws=null);}uri(){let e=this.opts.secure?"wss":"ws",t=this.query||{};return this.opts.timestampRequests&&(t[this.opts.timestampParam]=K()),this.supportsBinary||(t.b64=1),this.createUri(e,t)}},ee=u.WebSocket||u.MozWebSocket,v=class extends te{createSocket(e,t,r){return Ne?new ee(e,t,r):t?new ee(e,t):new ee(e)}doWrite(e,t){this.ws.send(t);}};var T=class extends _{get name(){return "webtransport"}doOpen(){try{this._transport=new WebTransport(this.createUri("https"),this.opts.transportOptions[this.name]);}catch(e){return this.emitReserved("error",e)}this._transport.closed.then(()=>{this.onClose();}).catch(e=>{this.onError("webtransport error",e);}),this._transport.ready.then(()=>{this._transport.createBidirectionalStream().then(e=>{let t=ke(Number.MAX_SAFE_INTEGER,this.socket.binaryType),r=e.readable.pipeThrough(t).getReader(),i=ve();i.readable.pipeTo(e.writable),this._writer=i.writable.getWriter();let n=()=>{r.read().then(({done:c,value:h})=>{c||(this.onPacket(h),n());}).catch(c=>{});};n();let o={type:"open"};this.query.sid&&(o.data=`{"sid":"${this.query.sid}"}`),this._writer.write(o).then(()=>this.onOpen());});});}write(e){this.writable=false;for(let t=0;t<e.length;t++){let r=e[t],i=t===e.length-1;this._writer.write(r).then(()=>{i&&y(()=>{this.writable=true,this.emitReserved("drain");},this.setTimeoutFn);});}}doClose(){var e;(e=this._transport)===null||e===void 0||e.close();}};var se={websocket:v,webtransport:T,polling:E};var Ge=/^(?:(?![^:@\/?#]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@\/?#]*)(?::([^:@\/?#]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/,je=["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"];function A(s){if(s.length>8e3)throw "URI too long";let e=s,t=s.indexOf("["),r=s.indexOf("]");t!=-1&&r!=-1&&(s=s.substring(0,t)+s.substring(t,r).replace(/:/g,";")+s.substring(r,s.length));let i=Ge.exec(s||""),n={},o=14;for(;o--;)n[je[o]]=i[o]||"";return t!=-1&&r!=-1&&(n.source=e,n.host=n.host.substring(1,n.host.length-1).replace(/;/g,":"),n.authority=n.authority.replace("[","").replace("]","").replace(/;/g,":"),n.ipv6uri=true),n.pathNames=Ze(n,n.path),n.queryKey=et(n,n.query),n}function Ze(s,e){let t=/\/{2,9}/g,r=e.replace(t,"/").split("/");return (e.slice(0,1)=="/"||e.length===0)&&r.splice(0,1),e.slice(-1)=="/"&&r.splice(r.length-1,1),r}function et(s,e){let t={};return e.replace(/(?:^|&)([^&=]*)=?([^&]*)/g,function(r,i,n){i&&(t[i]=n);}),t}var re=typeof addEventListener=="function"&&typeof removeEventListener=="function",J=[];re&&addEventListener("offline",()=>{J.forEach(s=>s());},false);var k=class s extends f{constructor(e,t){if(super(),this.binaryType=xe,this.writeBuffer=[],this._prevBufferLen=0,this._pingInterval=-1,this._pingTimeout=-1,this._maxPayload=-1,this._pingTimeoutTime=1/0,e&&typeof e=="object"&&(t=e,e=null),e){let r=A(e);t.hostname=r.host,t.secure=r.protocol==="https"||r.protocol==="wss",t.port=r.port,r.query&&(t.query=r.query);}else t.host&&(t.hostname=A(t.host).host);g(this,t),this.secure=t.secure!=null?t.secure:typeof location<"u"&&location.protocol==="https:",t.hostname&&!t.port&&(t.port=this.secure?"443":"80"),this.hostname=t.hostname||(typeof location<"u"?location.hostname:"localhost"),this.port=t.port||(typeof location<"u"&&location.port?location.port:this.secure?"443":"80"),this.transports=[],this._transportsByName={},t.transports.forEach(r=>{let i=r.prototype.name;this.transports.push(i),this._transportsByName[i]=r;}),this.opts=Object.assign({path:"/engine.io",agent:false,withCredentials:false,upgrade:true,timestampParam:"t",rememberUpgrade:false,addTrailingSlash:true,rejectUnauthorized:true,perMessageDeflate:{threshold:1024},transportOptions:{},closeOnBeforeunload:false},t),this.opts.path=this.opts.path.replace(/\/$/,"")+(this.opts.addTrailingSlash?"/":""),typeof this.opts.query=="string"&&(this.opts.query=Ce(this.opts.query)),re&&(this.opts.closeOnBeforeunload&&(this._beforeunloadEventListener=()=>{this.transport&&(this.transport.removeAllListeners(),this.transport.close());},addEventListener("beforeunload",this._beforeunloadEventListener,false)),this.hostname!=="localhost"&&(this._offlineEventListener=()=>{this._onClose("transport close",{description:"network connection lost"});},J.push(this._offlineEventListener))),this.opts.withCredentials&&(this._cookieJar=void 0),this._open();}createTransport(e){let t=Object.assign({},this.opts.query);t.EIO=j,t.transport=e,this.id&&(t.sid=this.id);let r=Object.assign({},this.opts,{query:t,socket:this,hostname:this.hostname,secure:this.secure,port:this.port},this.opts.transportOptions[e]);return new this._transportsByName[e](r)}_open(){if(this.transports.length===0){this.setTimeoutFn(()=>{this.emitReserved("error","No transports available");},0);return}let e=this.opts.rememberUpgrade&&s.priorWebsocketSuccess&&this.transports.indexOf("websocket")!==-1?"websocket":this.transports[0];this.readyState="opening";let t=this.createTransport(e);t.open(),this.setTransport(t);}setTransport(e){this.transport&&this.transport.removeAllListeners(),this.transport=e,e.on("drain",this._onDrain.bind(this)).on("packet",this._onPacket.bind(this)).on("error",this._onError.bind(this)).on("close",t=>this._onClose("transport close",t));}onOpen(){this.readyState="open",s.priorWebsocketSuccess=this.transport.name==="websocket",this.emitReserved("open"),this.flush();}_onPacket(e){if(this.readyState==="opening"||this.readyState==="open"||this.readyState==="closing")switch(this.emitReserved("packet",e),this.emitReserved("heartbeat"),e.type){case "open":this.onHandshake(JSON.parse(e.data));break;case "ping":this._sendPacket("pong"),this.emitReserved("ping"),this.emitReserved("pong"),this._resetPingTimeout();break;case "error":let t=new Error("server error");t.code=e.data,this._onError(t);break;case "message":this.emitReserved("data",e.data),this.emitReserved("message",e.data);break}}onHandshake(e){this.emitReserved("handshake",e),this.id=e.sid,this.transport.query.sid=e.sid,this._pingInterval=e.pingInterval,this._pingTimeout=e.pingTimeout,this._maxPayload=e.maxPayload,this.onOpen(),this.readyState!=="closed"&&this._resetPingTimeout();}_resetPingTimeout(){this.clearTimeoutFn(this._pingTimeoutTimer);let e=this._pingInterval+this._pingTimeout;this._pingTimeoutTime=Date.now()+e,this._pingTimeoutTimer=this.setTimeoutFn(()=>{this._onClose("ping timeout");},e),this.opts.autoUnref&&this._pingTimeoutTimer.unref();}_onDrain(){this.writeBuffer.splice(0,this._prevBufferLen),this._prevBufferLen=0,this.writeBuffer.length===0?this.emitReserved("drain"):this.flush();}flush(){if(this.readyState!=="closed"&&this.transport.writable&&!this.upgrading&&this.writeBuffer.length){let e=this._getWritablePackets();this.transport.send(e),this._prevBufferLen=e.length,this.emitReserved("flush");}}_getWritablePackets(){if(!(this._maxPayload&&this.transport.name==="polling"&&this.writeBuffer.length>1))return this.writeBuffer;let t=1;for(let r=0;r<this.writeBuffer.length;r++){let i=this.writeBuffer[r].data;if(i&&(t+=Te(i)),r>0&&t>this._maxPayload)return this.writeBuffer.slice(0,r);t+=2;}return this.writeBuffer}_hasPingExpired(){if(!this._pingTimeoutTime)return true;let e=Date.now()>this._pingTimeoutTime;return e&&(this._pingTimeoutTime=0,y(()=>{this._onClose("ping timeout");},this.setTimeoutFn)),e}write(e,t,r){return this._sendPacket("message",e,t,r),this}send(e,t,r){return this._sendPacket("message",e,t,r),this}_sendPacket(e,t,r,i){if(typeof t=="function"&&(i=t,t=void 0),typeof r=="function"&&(i=r,r=null),this.readyState==="closing"||this.readyState==="closed")return;r=r||{},r.compress=r.compress!==false;let n={type:e,data:t,options:r};this.emitReserved("packetCreate",n),this.writeBuffer.push(n),i&&this.once("flush",i),this.flush();}close(){let e=()=>{this._onClose("forced close"),this.transport.close();},t=()=>{this.off("upgrade",t),this.off("upgradeError",t),e();},r=()=>{this.once("upgrade",t),this.once("upgradeError",t);};return (this.readyState==="opening"||this.readyState==="open")&&(this.readyState="closing",this.writeBuffer.length?this.once("drain",()=>{this.upgrading?r():e();}):this.upgrading?r():e()),this}_onError(e){if(s.priorWebsocketSuccess=false,this.opts.tryAllTransports&&this.transports.length>1&&this.readyState==="opening")return this.transports.shift(),this._open();this.emitReserved("error",e),this._onClose("transport error",e);}_onClose(e,t){if(this.readyState==="opening"||this.readyState==="open"||this.readyState==="closing"){if(this.clearTimeoutFn(this._pingTimeoutTimer),this.transport.removeAllListeners("close"),this.transport.close(),this.transport.removeAllListeners(),re&&(this._beforeunloadEventListener&&removeEventListener("beforeunload",this._beforeunloadEventListener,false),this._offlineEventListener)){let r=J.indexOf(this._offlineEventListener);r!==-1&&J.splice(r,1);}this.readyState="closed",this.id=null,this.emitReserved("close",e,t),this.writeBuffer=[],this._prevBufferLen=0;}}};k.protocol=j;var z=class extends k{constructor(){super(...arguments),this._upgrades=[];}onOpen(){if(super.onOpen(),this.readyState==="open"&&this.opts.upgrade)for(let e=0;e<this._upgrades.length;e++)this._probe(this._upgrades[e]);}_probe(e){let t=this.createTransport(e),r=false;k.priorWebsocketSuccess=false;let i=()=>{r||(t.send([{type:"ping",data:"probe"}]),t.once("packet",b=>{if(!r)if(b.type==="pong"&&b.data==="probe"){if(this.upgrading=true,this.emitReserved("upgrading",t),!t)return;k.priorWebsocketSuccess=t.name==="websocket",this.transport.pause(()=>{r||this.readyState!=="closed"&&(p(),this.setTransport(t),t.send([{type:"upgrade"}]),this.emitReserved("upgrade",t),t=null,this.upgrading=false,this.flush());});}else {let O=new Error("probe error");O.transport=t.name,this.emitReserved("upgradeError",O);}}));};function n(){r||(r=true,p(),t.close(),t=null);}let o=b=>{let O=new Error("probe error: "+b);O.transport=t.name,n(),this.emitReserved("upgradeError",O);};function c(){o("transport closed");}function h(){o("socket closed");}function m(b){t&&b.name!==t.name&&n();}let p=()=>{t.removeListener("open",i),t.removeListener("error",o),t.removeListener("close",c),this.off("close",h),this.off("upgrading",m);};t.once("open",i),t.once("error",o),t.once("close",c),this.once("close",h),this.once("upgrading",m),this._upgrades.indexOf("webtransport")!==-1&&e!=="webtransport"?this.setTimeoutFn(()=>{r||t.open();},200):t.open();}onHandshake(e){this._upgrades=this._filterUpgrades(e.upgrades),super.onHandshake(e);}_filterUpgrades(e){let t=[];for(let r=0;r<e.length;r++)~this.transports.indexOf(e[r])&&t.push(e[r]);return t}},C=class extends z{constructor(e,t={}){let r=typeof e=="object",i=r?{...e}:{...t};(!i.transports||i.transports&&typeof i.transports[0]=="string")&&(i.transports=(i.transports||["polling","websocket","webtransport"]).map(n=>se[n]).filter(n=>!!n)),super(r?i:e,i);}};function Le(s,e="",t){let r=s;t=t||typeof location<"u"&&location,s==null&&(s=t.protocol+"//"+t.host),typeof s=="string"&&(s.charAt(0)==="/"&&(s.charAt(1)==="/"?s=t.protocol+s:s=t.host+s),/^(https?|wss?):\/\//.test(s)||(typeof t<"u"?s=t.protocol+"//"+s:s="https://"+s),r=A(s)),r.port||(/^(http|ws)$/.test(r.protocol)?r.port="80":/^(http|ws)s$/.test(r.protocol)&&(r.port="443")),r.path=r.path||"/";let n=r.host.indexOf(":")!==-1?"["+r.host+"]":r.host;return r.id=r.protocol+"://"+n+":"+r.port+e,r.href=r.protocol+"://"+n+(t&&t.port===r.port?"":":"+r.port),r}var ce={};Me(ce,{Decoder:()=>oe,Encoder:()=>ne,PacketType:()=>a,isPacketValid:()=>ht,protocol:()=>Ue});var st=typeof ArrayBuffer=="function",rt=s=>typeof ArrayBuffer.isView=="function"?ArrayBuffer.isView(s):s.buffer instanceof ArrayBuffer,Pe=Object.prototype.toString,it=typeof Blob=="function"||typeof Blob<"u"&&Pe.call(Blob)==="[object BlobConstructor]",nt=typeof File=="function"||typeof File<"u"&&Pe.call(File)==="[object FileConstructor]";function U(s){return st&&(s instanceof ArrayBuffer||rt(s))||it&&s instanceof Blob||nt&&s instanceof File}function I(s,e){if(!s||typeof s!="object")return false;if(Array.isArray(s)){for(let t=0,r=s.length;t<r;t++)if(I(s[t]))return true;return false}if(U(s))return true;if(s.toJSON&&typeof s.toJSON=="function"&&arguments.length===1)return I(s.toJSON(),true);for(let t in s)if(Object.prototype.hasOwnProperty.call(s,t)&&I(s[t]))return true;return false}function qe(s){let e=[],t=s.data,r=s;return r.data=X(t,e),r.attachments=e.length,{packet:r,buffers:e}}function X(s,e,t){if(!s)return s;if(U(s)){let r={_placeholder:true,num:e.length};return e.push(s),r}else if(Array.isArray(s)){let r=new Array(s.length);for(let i=0;i<s.length;i++)r[i]=X(s[i],e);return r}else if(typeof s=="object"&&!(s instanceof Date)){if(s.toJSON&&typeof s.toJSON=="function"&&!t)return X(s.toJSON(),e,true);let r={};for(let i in s)Object.prototype.hasOwnProperty.call(s,i)&&(r[i]=X(s[i],e));return r}return s}function De(s,e){return s.data=ie(s.data,e),delete s.attachments,s}function ie(s,e){if(!s)return s;if(s&&s._placeholder===true){if(typeof s.num=="number"&&s.num>=0&&s.num<e.length)return e[s.num];throw new Error("illegal attachments")}else if(Array.isArray(s))for(let t=0;t<s.length;t++)s[t]=ie(s[t],e);else if(typeof s=="object")for(let t in s)Object.prototype.hasOwnProperty.call(s,t)&&(s[t]=ie(s[t],e));return s}var Ie=["connect","connect_error","disconnect","disconnecting","newListener","removeListener"],Ue=5,a;(function(s){s[s.CONNECT=0]="CONNECT",s[s.DISCONNECT=1]="DISCONNECT",s[s.EVENT=2]="EVENT",s[s.ACK=3]="ACK",s[s.CONNECT_ERROR=4]="CONNECT_ERROR",s[s.BINARY_EVENT=5]="BINARY_EVENT",s[s.BINARY_ACK=6]="BINARY_ACK";})(a||(a={}));var ne=class{constructor(e){this.replacer=e;}encode(e){return (e.type===a.EVENT||e.type===a.ACK)&&I(e)?this.encodeAsBinary({type:e.type===a.EVENT?a.BINARY_EVENT:a.BINARY_ACK,nsp:e.nsp,data:e.data,id:e.id}):[this.encodeAsString(e)]}encodeAsString(e){let t=""+e.type;return (e.type===a.BINARY_EVENT||e.type===a.BINARY_ACK)&&(t+=e.attachments+"-"),e.nsp&&e.nsp!=="/"&&(t+=e.nsp+","),e.id!=null&&(t+=e.id),e.data!=null&&(t+=JSON.stringify(e.data,this.replacer)),t}encodeAsBinary(e){let t=qe(e),r=this.encodeAsString(t.packet),i=t.buffers;return i.unshift(r),i}},oe=class s extends f{constructor(e){super(),this.opts=Object.assign({reviver:void 0,maxAttachments:10},typeof e=="function"?{reviver:e}:e);}add(e){let t;if(typeof e=="string"){if(this.reconstructor)throw new Error("got plaintext data when reconstructing a packet");t=this.decodeString(e);let r=t.type===a.BINARY_EVENT;r||t.type===a.BINARY_ACK?(t.type=r?a.EVENT:a.ACK,this.reconstructor=new ae(t)):super.emitReserved("decoded",t);}else if(U(e)||e.base64)if(this.reconstructor)t=this.reconstructor.takeBinaryData(e),t&&(this.reconstructor=null,super.emitReserved("decoded",t));else throw new Error("got binary data when not reconstructing a packet");else throw new Error("Unknown type: "+e)}decodeString(e){let t=0,r={type:Number(e.charAt(0))};if(a[r.type]===void 0)throw new Error("unknown packet type "+r.type);if(r.type===a.BINARY_EVENT||r.type===a.BINARY_ACK){let n=t+1;for(;e.charAt(++t)!=="-"&&t!=e.length;);let o=e.substring(n,t);if(o!=Number(o)||e.charAt(t)!=="-")throw new Error("Illegal attachments");let c=Number(o);if(!Fe(c)||c<1)throw new Error("Illegal attachments");if(c>this.opts.maxAttachments)throw new Error("too many attachments");r.attachments=c;}if(e.charAt(t+1)==="/"){let n=t+1;for(;++t&&!(e.charAt(t)===","||t===e.length););r.nsp=e.substring(n,t);}else r.nsp="/";let i=e.charAt(t+1);if(i!==""&&Number(i)==i){let n=t+1;for(;++t;){let o=e.charAt(t);if(o==null||Number(o)!=o){--t;break}if(t===e.length)break}r.id=Number(e.substring(n,t+1));}if(e.charAt(++t)){let n=this.tryParse(e.substr(t));if(s.isPayloadValid(r.type,n))r.data=n;else throw new Error("invalid payload")}return r}tryParse(e){try{return JSON.parse(e,this.opts.reviver)}catch{return false}}static isPayloadValid(e,t){switch(e){case a.CONNECT:return $(t);case a.DISCONNECT:return t===void 0;case a.CONNECT_ERROR:return typeof t=="string"||$(t);case a.EVENT:case a.BINARY_EVENT:return Array.isArray(t)&&(typeof t[0]=="number"||typeof t[0]=="string"&&Ie.indexOf(t[0])===-1);case a.ACK:case a.BINARY_ACK:return Array.isArray(t)}}destroy(){this.reconstructor&&(this.reconstructor.finishedReconstruction(),this.reconstructor=null);}},ae=class{constructor(e){this.packet=e,this.buffers=[],this.reconPack=e;}takeBinaryData(e){if(this.buffers.push(e),this.buffers.length===this.reconPack.attachments){let t=De(this.reconPack,this.buffers);return this.finishedReconstruction(),t}return null}finishedReconstruction(){this.reconPack=null,this.buffers=[];}};function ot(s){return typeof s=="string"}var Fe=Number.isInteger||function(s){return typeof s=="number"&&isFinite(s)&&Math.floor(s)===s};function at(s){return s===void 0||Fe(s)}function $(s){return Object.prototype.toString.call(s)==="[object Object]"}function ct(s,e){switch(s){case a.CONNECT:return e===void 0||$(e);case a.DISCONNECT:return e===void 0;case a.EVENT:return Array.isArray(e)&&(typeof e[0]=="number"||typeof e[0]=="string"&&Ie.indexOf(e[0])===-1);case a.ACK:return Array.isArray(e);case a.CONNECT_ERROR:return typeof e=="string"||$(e);default:return false}}function ht(s){return ot(s.nsp)&&at(s.id)&&ct(s.type,s.data)}function l(s,e,t){return s.on(e,t),function(){s.off(e,t);}}var ft=Object.freeze({connect:1,connect_error:1,disconnect:1,disconnecting:1,newListener:1,removeListener:1}),S=class extends f{constructor(e,t,r){super(),this.connected=false,this.recovered=false,this.receiveBuffer=[],this.sendBuffer=[],this._queue=[],this._queueSeq=0,this.ids=0,this.acks={},this.flags={},this.io=e,this.nsp=t,r&&r.auth&&(this.auth=r.auth),this._opts=Object.assign({},r),this.io._autoConnect&&this.open();}get disconnected(){return !this.connected}subEvents(){if(this.subs)return;let e=this.io;this.subs=[l(e,"open",this.onopen.bind(this)),l(e,"packet",this.onpacket.bind(this)),l(e,"error",this.onerror.bind(this)),l(e,"close",this.onclose.bind(this))];}get active(){return !!this.subs}connect(){return this.connected?this:(this.subEvents(),this.io._reconnecting||this.io.open(),this.io._readyState==="open"&&this.onopen(),this)}open(){return this.connect()}send(...e){return e.unshift("message"),this.emit.apply(this,e),this}emit(e,...t){var r,i,n;if(ft.hasOwnProperty(e))throw new Error('"'+e.toString()+'" is a reserved event name');if(t.unshift(e),this._opts.retries&&!this.flags.fromQueue&&!this.flags.volatile)return this._addToQueue(t),this;let o={type:a.EVENT,data:t};if(o.options={},o.options.compress=this.flags.compress!==false,typeof t[t.length-1]=="function"){let p=this.ids++,b=t.pop();this._registerAckCallback(p,b),o.id=p;}let c=(i=(r=this.io.engine)===null||r===void 0?void 0:r.transport)===null||i===void 0?void 0:i.writable,h=this.connected&&!(!((n=this.io.engine)===null||n===void 0)&&n._hasPingExpired());return this.flags.volatile&&!c||(h?(this.notifyOutgoingListeners(o),this.packet(o)):this.sendBuffer.push(o)),this.flags={},this}_registerAckCallback(e,t){var r;let i=(r=this.flags.timeout)!==null&&r!==void 0?r:this._opts.ackTimeout;if(i===void 0){this.acks[e]=t;return}let n=this.io.setTimeoutFn(()=>{delete this.acks[e];for(let c=0;c<this.sendBuffer.length;c++)this.sendBuffer[c].id===e&&this.sendBuffer.splice(c,1);t.call(this,new Error("operation has timed out"));},i),o=(...c)=>{this.io.clearTimeoutFn(n),t.apply(this,c);};o.withError=true,this.acks[e]=o;}emitWithAck(e,...t){return new Promise((r,i)=>{let n=(o,c)=>o?i(o):r(c);n.withError=true,t.push(n),this.emit(e,...t);})}_addToQueue(e){let t;typeof e[e.length-1]=="function"&&(t=e.pop());let r={id:this._queueSeq++,tryCount:0,pending:false,args:e,flags:Object.assign({fromQueue:true},this.flags)};e.push((i,...n)=>(this._queue[0],i!==null?r.tryCount>this._opts.retries&&(this._queue.shift(),t&&t(i)):(this._queue.shift(),t&&t(null,...n)),r.pending=false,this._drainQueue())),this._queue.push(r),this._drainQueue();}_drainQueue(e=false){if(!this.connected||this._queue.length===0)return;let t=this._queue[0];t.pending&&!e||(t.pending=true,t.tryCount++,this.flags=t.flags,this.emit.apply(this,t.args));}packet(e){e.nsp=this.nsp,this.io._packet(e);}onopen(){typeof this.auth=="function"?this.auth(e=>{this._sendConnectPacket(e);}):this._sendConnectPacket(this.auth);}_sendConnectPacket(e){this.packet({type:a.CONNECT,data:this._pid?Object.assign({pid:this._pid,offset:this._lastOffset},e):e});}onerror(e){this.connected||this.emitReserved("connect_error",e);}onclose(e,t){this.connected=false,delete this.id,this.emitReserved("disconnect",e,t),this._clearAcks();}_clearAcks(){Object.keys(this.acks).forEach(e=>{if(!this.sendBuffer.some(r=>String(r.id)===e)){let r=this.acks[e];delete this.acks[e],r.withError&&r.call(this,new Error("socket has been disconnected"));}});}onpacket(e){if(e.nsp===this.nsp)switch(e.type){case a.CONNECT:e.data&&e.data.sid?this.onconnect(e.data.sid,e.data.pid):this.emitReserved("connect_error",new Error("It seems you are trying to reach a Socket.IO server in v2.x with a v3.x client, but they are not compatible (more information here: https://socket.io/docs/v3/migrating-from-2-x-to-3-0/)"));break;case a.EVENT:case a.BINARY_EVENT:this.onevent(e);break;case a.ACK:case a.BINARY_ACK:this.onack(e);break;case a.DISCONNECT:this.ondisconnect();break;case a.CONNECT_ERROR:this.destroy();let r=new Error(e.data.message);r.data=e.data.data,this.emitReserved("connect_error",r);break}}onevent(e){let t=e.data||[];e.id!=null&&t.push(this.ack(e.id)),this.connected?this.emitEvent(t):this.receiveBuffer.push(Object.freeze(t));}emitEvent(e){if(this._anyListeners&&this._anyListeners.length){let t=this._anyListeners.slice();for(let r of t)r.apply(this,e);}super.emit.apply(this,e),this._pid&&e.length&&typeof e[e.length-1]=="string"&&(this._lastOffset=e[e.length-1]);}ack(e){let t=this,r=false;return function(...i){r||(r=true,t.packet({type:a.ACK,id:e,data:i}));}}onack(e){let t=this.acks[e.id];typeof t=="function"&&(delete this.acks[e.id],t.withError&&e.data.unshift(null),t.apply(this,e.data));}onconnect(e,t){this.id=e,this.recovered=t&&this._pid===t,this._pid=t,this.connected=true,this.emitBuffered(),this._drainQueue(true),this.emitReserved("connect");}emitBuffered(){this.receiveBuffer.forEach(e=>this.emitEvent(e)),this.receiveBuffer=[],this.sendBuffer.forEach(e=>{this.notifyOutgoingListeners(e),this.packet(e);}),this.sendBuffer=[];}ondisconnect(){this.destroy(),this.onclose("io server disconnect");}destroy(){this.subs&&(this.subs.forEach(e=>e()),this.subs=void 0),this.io._destroy(this);}disconnect(){return this.connected&&this.packet({type:a.DISCONNECT}),this.destroy(),this.connected&&this.onclose("io client disconnect"),this}close(){return this.disconnect()}compress(e){return this.flags.compress=e,this}get volatile(){return this.flags.volatile=true,this}timeout(e){return this.flags.timeout=e,this}onAny(e){return this._anyListeners=this._anyListeners||[],this._anyListeners.push(e),this}prependAny(e){return this._anyListeners=this._anyListeners||[],this._anyListeners.unshift(e),this}offAny(e){if(!this._anyListeners)return this;if(e){let t=this._anyListeners;for(let r=0;r<t.length;r++)if(e===t[r])return t.splice(r,1),this}else this._anyListeners=[];return this}listenersAny(){return this._anyListeners||[]}onAnyOutgoing(e){return this._anyOutgoingListeners=this._anyOutgoingListeners||[],this._anyOutgoingListeners.push(e),this}prependAnyOutgoing(e){return this._anyOutgoingListeners=this._anyOutgoingListeners||[],this._anyOutgoingListeners.unshift(e),this}offAnyOutgoing(e){if(!this._anyOutgoingListeners)return this;if(e){let t=this._anyOutgoingListeners;for(let r=0;r<t.length;r++)if(e===t[r])return t.splice(r,1),this}else this._anyOutgoingListeners=[];return this}listenersAnyOutgoing(){return this._anyOutgoingListeners||[]}notifyOutgoingListeners(e){if(this._anyOutgoingListeners&&this._anyOutgoingListeners.length){let t=this._anyOutgoingListeners.slice();for(let r of t)r.apply(this,e.data);}}};function x(s){s=s||{},this.ms=s.min||100,this.max=s.max||1e4,this.factor=s.factor||2,this.jitter=s.jitter>0&&s.jitter<=1?s.jitter:0,this.attempts=0;}x.prototype.duration=function(){var s=this.ms*Math.pow(this.factor,this.attempts++);if(this.jitter){var e=Math.random(),t=Math.floor(e*this.jitter*s);s=(Math.floor(e*10)&1)==0?s-t:s+t;}return Math.min(s,this.max)|0};x.prototype.reset=function(){this.attempts=0;};x.prototype.setMin=function(s){this.ms=s;};x.prototype.setMax=function(s){this.max=s;};x.prototype.setJitter=function(s){this.jitter=s;};var R=class extends f{constructor(e,t){var r;super(),this.nsps={},this.subs=[],e&&typeof e=="object"&&(t=e,e=void 0),t=t||{},t.path=t.path||"/socket.io",this.opts=t,g(this,t),this.reconnection(t.reconnection!==false),this.reconnectionAttempts(t.reconnectionAttempts||1/0),this.reconnectionDelay(t.reconnectionDelay||1e3),this.reconnectionDelayMax(t.reconnectionDelayMax||5e3),this.randomizationFactor((r=t.randomizationFactor)!==null&&r!==void 0?r:.5),this.backoff=new x({min:this.reconnectionDelay(),max:this.reconnectionDelayMax(),jitter:this.randomizationFactor()}),this.timeout(t.timeout==null?2e4:t.timeout),this._readyState="closed",this.uri=e;let i=t.parser||ce;this.encoder=new i.Encoder,this.decoder=new i.Decoder,this._autoConnect=t.autoConnect!==false,this._autoConnect&&this.open();}reconnection(e){return arguments.length?(this._reconnection=!!e,e||(this.skipReconnect=true),this):this._reconnection}reconnectionAttempts(e){return e===void 0?this._reconnectionAttempts:(this._reconnectionAttempts=e,this)}reconnectionDelay(e){var t;return e===void 0?this._reconnectionDelay:(this._reconnectionDelay=e,(t=this.backoff)===null||t===void 0||t.setMin(e),this)}randomizationFactor(e){var t;return e===void 0?this._randomizationFactor:(this._randomizationFactor=e,(t=this.backoff)===null||t===void 0||t.setJitter(e),this)}reconnectionDelayMax(e){var t;return e===void 0?this._reconnectionDelayMax:(this._reconnectionDelayMax=e,(t=this.backoff)===null||t===void 0||t.setMax(e),this)}timeout(e){return arguments.length?(this._timeout=e,this):this._timeout}maybeReconnectOnOpen(){!this._reconnecting&&this._reconnection&&this.backoff.attempts===0&&this.reconnect();}open(e){if(~this._readyState.indexOf("open"))return this;this.engine=new C(this.uri,this.opts);let t=this.engine,r=this;this._readyState="opening",this.skipReconnect=false;let i=l(t,"open",function(){r.onopen(),e&&e();}),n=c=>{this.cleanup(),this._readyState="closed",this.emitReserved("error",c),e?e(c):this.maybeReconnectOnOpen();},o=l(t,"error",n);if(this._timeout!==false){let c=this._timeout,h=this.setTimeoutFn(()=>{i(),n(new Error("timeout")),t.close();},c);this.opts.autoUnref&&h.unref(),this.subs.push(()=>{this.clearTimeoutFn(h);});}return this.subs.push(i),this.subs.push(o),this}connect(e){return this.open(e)}onopen(){this.cleanup(),this._readyState="open",this.emitReserved("open");let e=this.engine;this.subs.push(l(e,"ping",this.onping.bind(this)),l(e,"data",this.ondata.bind(this)),l(e,"error",this.onerror.bind(this)),l(e,"close",this.onclose.bind(this)),l(this.decoder,"decoded",this.ondecoded.bind(this)));}onping(){this.emitReserved("ping");}ondata(e){try{this.decoder.add(e);}catch(t){this.onclose("parse error",t);}}ondecoded(e){y(()=>{this.emitReserved("packet",e);},this.setTimeoutFn);}onerror(e){this.emitReserved("error",e);}socket(e,t){let r=this.nsps[e];return r?this._autoConnect&&!r.active&&r.connect():(r=new S(this,e,t),this.nsps[e]=r),r}_destroy(e){let t=Object.keys(this.nsps);for(let r of t)if(this.nsps[r].active)return;this._close();}_packet(e){let t=this.encoder.encode(e);for(let r=0;r<t.length;r++)this.engine.write(t[r],e.options);}cleanup(){this.subs.forEach(e=>e()),this.subs.length=0,this.decoder.destroy();}_close(){this.skipReconnect=true,this._reconnecting=false,this.onclose("forced close");}disconnect(){return this._close()}onclose(e,t){var r;this.cleanup(),(r=this.engine)===null||r===void 0||r.close(),this.backoff.reset(),this._readyState="closed",this.emitReserved("close",e,t),this._reconnection&&!this.skipReconnect&&this.reconnect();}reconnect(){if(this._reconnecting||this.skipReconnect)return this;let e=this;if(this.backoff.attempts>=this._reconnectionAttempts)this.backoff.reset(),this.emitReserved("reconnect_failed"),this._reconnecting=false;else {let t=this.backoff.duration();this._reconnecting=true;let r=this.setTimeoutFn(()=>{e.skipReconnect||(this.emitReserved("reconnect_attempt",e.backoff.attempts),!e.skipReconnect&&e.open(i=>{i?(e._reconnecting=false,e.reconnect(),this.emitReserved("reconnect_error",i)):e.onreconnect();}));},t);this.opts.autoUnref&&r.unref(),this.subs.push(()=>{this.clearTimeoutFn(r);});}}onreconnect(){let e=this.backoff.attempts;this._reconnecting=false,this.backoff.reset(),this.emitReserved("reconnect",e);}};var F={};function V(s,e){typeof s=="object"&&(e=s,s=void 0),e=e||{};let t=Le(s,e.path||"/socket.io"),r=t.source,i=t.id,n=t.path,o=F[i]&&n in F[i].nsps,c=e.forceNew||e["force new connection"]||e.multiplex===false||o,h;return c?h=new R(r,e):(F[i]||(F[i]=new R(r,e)),h=F[i]),t.query&&!e.query&&(e.query=t.queryKey),h.socket(t.path,e)}Object.assign(V,{Manager:R,Socket:S,io:V,connect:V});var he=class{constructor(e){this.options=e;}options;socket;connectPromise;balanceListeners=new Set;purchaseListeners=new Set;onBalanceChange(e){return this.balanceListeners.add(e),this.ensureConnected(),()=>{this.balanceListeners.delete(e),this.disconnectIfIdle();}}onStorePurchase(e){return this.purchaseListeners.add(e),this.ensureConnected(),()=>{this.purchaseListeners.delete(e),this.disconnectIfIdle();}}disconnect(){this.socket?.disconnect(),this.socket=void 0,this.connectPromise=void 0;}async ensureConnected(){if(this.socket?.connected)return this.socket;if(this.connectPromise)return this.connectPromise;this.connectPromise=(async()=>{let e=await this.options.getAccessToken();if(!e)return;let t=V(this.options.baseUrl,{transports:["websocket"],auth:{token:`Bearer ${e}`}});return t.on("balance_change",r=>{for(let i of this.balanceListeners)i(r);}),t.on("store_purchase_completed",r=>{for(let i of this.purchaseListeners)i(r);}),this.socket=t,t})();try{return await this.connectPromise}finally{this.connectPromise=void 0;}}disconnectIfIdle(){this.balanceListeners.size===0&&this.purchaseListeners.size===0&&this.disconnect();}};
|
|
2
|
+
exports.WsClient=he;return exports;})({});//# sourceMappingURL=looplay-sdk-realtime.min.js.map
|
|
3
|
+
//# sourceMappingURL=looplay-sdk-realtime.min.js.map
|