@broadcastingplatforms/sdk 0.0.0-dev.52fbff9
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/dist/auth-CSkJb9Wc.d.mts +1180 -0
- package/dist/auth-CSkJb9Wc.d.ts +1180 -0
- package/dist/auth.d.mts +1 -0
- package/dist/auth.d.ts +1 -0
- package/dist/auth.js +456 -0
- package/dist/auth.mjs +433 -0
- package/dist/base-client-BHrP5nb_.d.ts +70 -0
- package/dist/base-client-BbMR6ZrV.d.mts +70 -0
- package/dist/browser-client.d.mts +47 -0
- package/dist/browser-client.d.ts +47 -0
- package/dist/browser-client.js +1983 -0
- package/dist/browser-client.mjs +1952 -0
- package/dist/channels.d.mts +1 -0
- package/dist/channels.d.ts +1 -0
- package/dist/channels.js +78 -0
- package/dist/channels.mjs +55 -0
- package/dist/chat.d.mts +1 -0
- package/dist/chat.d.ts +1 -0
- package/dist/chat.js +105 -0
- package/dist/chat.mjs +80 -0
- package/dist/errors.d.mts +68 -0
- package/dist/errors.d.ts +68 -0
- package/dist/errors.js +151 -0
- package/dist/errors.mjs +127 -0
- package/dist/http.d.mts +1 -0
- package/dist/http.d.ts +1 -0
- package/dist/http.js +323 -0
- package/dist/http.mjs +298 -0
- package/dist/index.d.mts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +2072 -0
- package/dist/index.mjs +2025 -0
- package/dist/realtime.d.mts +9 -0
- package/dist/realtime.d.ts +9 -0
- package/dist/realtime.js +1050 -0
- package/dist/realtime.mjs +1021 -0
- package/dist/resource.d.mts +1 -0
- package/dist/resource.d.ts +1 -0
- package/dist/resource.js +52 -0
- package/dist/resource.mjs +27 -0
- package/dist/server-client.d.mts +60 -0
- package/dist/server-client.d.ts +60 -0
- package/dist/server-client.js +1984 -0
- package/dist/server-client.mjs +1954 -0
- package/dist/storage.d.mts +149 -0
- package/dist/storage.d.ts +149 -0
- package/dist/storage.js +243 -0
- package/dist/storage.mjs +211 -0
- package/dist/streams.d.mts +1 -0
- package/dist/streams.d.ts +1 -0
- package/dist/streams.js +267 -0
- package/dist/streams.mjs +242 -0
- package/dist/types.d.mts +1 -0
- package/dist/types.d.ts +1 -0
- package/dist/types.js +19 -0
- package/dist/types.mjs +1 -0
- package/package.json +139 -0
|
@@ -0,0 +1,1983 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
31
|
+
|
|
32
|
+
// src/browser-client.ts
|
|
33
|
+
var browser_client_exports = {};
|
|
34
|
+
__export(browser_client_exports, {
|
|
35
|
+
BrowserClient: () => BrowserClient,
|
|
36
|
+
createBrowserClient: () => createBrowserClient,
|
|
37
|
+
createClient: () => createClient
|
|
38
|
+
});
|
|
39
|
+
module.exports = __toCommonJS(browser_client_exports);
|
|
40
|
+
|
|
41
|
+
// src/auth.ts
|
|
42
|
+
var import_jwt_decode = require("jwt-decode");
|
|
43
|
+
|
|
44
|
+
// src/errors.ts
|
|
45
|
+
var SDKError = class extends Error {
|
|
46
|
+
/**
|
|
47
|
+
* Construct an SDKError. Signature is compatible with Error.
|
|
48
|
+
* You can pass in a message or an options object, as with the Error constructor.
|
|
49
|
+
* Additional fields (code, etc) may be added via the second argument.
|
|
50
|
+
*/
|
|
51
|
+
constructor(message, details = {}) {
|
|
52
|
+
const resolvedMessage = message ?? (typeof details.message === "string" ? details.message : "Unknown error");
|
|
53
|
+
super(resolvedMessage);
|
|
54
|
+
/**
|
|
55
|
+
* Canonical SDK error code.
|
|
56
|
+
*/
|
|
57
|
+
__publicField(this, "code");
|
|
58
|
+
/**
|
|
59
|
+
* HTTP status code if available.
|
|
60
|
+
*/
|
|
61
|
+
__publicField(this, "statusCode");
|
|
62
|
+
/**
|
|
63
|
+
* End-user safe message.
|
|
64
|
+
*/
|
|
65
|
+
__publicField(this, "userMessage");
|
|
66
|
+
/**
|
|
67
|
+
* Optional request metadata (null when unavailable).
|
|
68
|
+
*/
|
|
69
|
+
__publicField(this, "request");
|
|
70
|
+
/**
|
|
71
|
+
* Optional response metadata (null when unavailable).
|
|
72
|
+
*/
|
|
73
|
+
__publicField(this, "response");
|
|
74
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
75
|
+
if (details && typeof details === "object") {
|
|
76
|
+
for (const [key, value] of Object.entries(details)) {
|
|
77
|
+
if (!["name", "message", "stack"].includes(key)) {
|
|
78
|
+
this[key] = value;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
this.name = "SDKError";
|
|
83
|
+
this.code = details.code ?? "unknown_error";
|
|
84
|
+
this.statusCode = typeof details.statusCode === "number" ? details.statusCode : void 0;
|
|
85
|
+
this.userMessage = typeof details.userMessage === "string" ? details.userMessage : this.message;
|
|
86
|
+
this.request = details.request ?? null;
|
|
87
|
+
this.response = details.response ?? null;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Serialize the error into a plain object, preserving extra fields.
|
|
91
|
+
*/
|
|
92
|
+
toJSON() {
|
|
93
|
+
const extras = { ...this };
|
|
94
|
+
delete extras.code;
|
|
95
|
+
delete extras.statusCode;
|
|
96
|
+
delete extras.message;
|
|
97
|
+
delete extras.userMessage;
|
|
98
|
+
delete extras.request;
|
|
99
|
+
delete extras.response;
|
|
100
|
+
delete extras.form;
|
|
101
|
+
delete extras.cause;
|
|
102
|
+
return {
|
|
103
|
+
...extras,
|
|
104
|
+
code: this.code,
|
|
105
|
+
statusCode: this.statusCode,
|
|
106
|
+
message: this.message,
|
|
107
|
+
userMessage: this.userMessage,
|
|
108
|
+
request: this.request,
|
|
109
|
+
response: this.response
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
var STATUS_CODE_DEFAULTS = {
|
|
114
|
+
401: {
|
|
115
|
+
code: "authentication_required",
|
|
116
|
+
message: "Authentication required",
|
|
117
|
+
userMessage: "Please log in to continue. Your session may have expired."
|
|
118
|
+
},
|
|
119
|
+
403: {
|
|
120
|
+
code: "permission_denied",
|
|
121
|
+
message: "Permission denied",
|
|
122
|
+
userMessage: "You do not have permission to perform this action."
|
|
123
|
+
},
|
|
124
|
+
404: {
|
|
125
|
+
code: "not_found",
|
|
126
|
+
message: "Resource not found",
|
|
127
|
+
userMessage: "The requested resource was not found."
|
|
128
|
+
},
|
|
129
|
+
422: {
|
|
130
|
+
code: "validation_failed",
|
|
131
|
+
message: "Validation failed",
|
|
132
|
+
userMessage: "The provided information is invalid. Please check your input and try again."
|
|
133
|
+
},
|
|
134
|
+
429: {
|
|
135
|
+
code: "rate_limited",
|
|
136
|
+
message: "Rate limit exceeded",
|
|
137
|
+
userMessage: "Too many requests. Please wait a moment and try again."
|
|
138
|
+
},
|
|
139
|
+
500: {
|
|
140
|
+
code: "server_error",
|
|
141
|
+
message: "Internal server error",
|
|
142
|
+
userMessage: "Something went wrong on our end. Please try again later."
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
var DEFAULT_ERROR = {
|
|
146
|
+
code: "unknown_error",
|
|
147
|
+
userMessage: "An unexpected error occurred. Please try again."
|
|
148
|
+
};
|
|
149
|
+
function createSdkError(message, details = {}) {
|
|
150
|
+
const statusCode = details.response?.status;
|
|
151
|
+
const statusValues = statusCode && STATUS_CODE_DEFAULTS[statusCode] ? STATUS_CODE_DEFAULTS[statusCode] : DEFAULT_ERROR;
|
|
152
|
+
const enrichedDetails = {
|
|
153
|
+
...details,
|
|
154
|
+
statusCode,
|
|
155
|
+
code: details.code ?? statusValues.code,
|
|
156
|
+
userMessage: details.userMessage ?? statusValues.userMessage,
|
|
157
|
+
request: details.request ?? null,
|
|
158
|
+
response: details.response ?? null
|
|
159
|
+
};
|
|
160
|
+
return new SDKError(message, enrichedDetails);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// src/storage.ts
|
|
164
|
+
var DEFAULT_AUTH_COOKIE_NAME = "auth_token";
|
|
165
|
+
var DEFAULT_COOKIE_OPTIONS = {
|
|
166
|
+
path: "/",
|
|
167
|
+
sameSite: "lax"
|
|
168
|
+
};
|
|
169
|
+
var isBrowser = () => typeof document !== "undefined";
|
|
170
|
+
var resolveCookieName = (prefix, key) => prefix ? `${prefix}${key}` : key;
|
|
171
|
+
var resolveCookieValue = (value) => {
|
|
172
|
+
if (value === null || value === void 0) {
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
if (typeof value === "string") {
|
|
176
|
+
return value;
|
|
177
|
+
}
|
|
178
|
+
if (typeof value === "object" && typeof value.value === "string") {
|
|
179
|
+
return value.value;
|
|
180
|
+
}
|
|
181
|
+
return null;
|
|
182
|
+
};
|
|
183
|
+
var decodeCookieValue = (value) => decodeURIComponent(value.replace(/\+/g, " "));
|
|
184
|
+
var encodeCookieValue = (value) => encodeURIComponent(value);
|
|
185
|
+
var readCookie = (name) => {
|
|
186
|
+
if (!isBrowser()) {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
const entries = document.cookie ? document.cookie.split("; ") : [];
|
|
190
|
+
for (const entry of entries) {
|
|
191
|
+
const [rawKey, ...rest] = entry.split("=");
|
|
192
|
+
if (rawKey && decodeCookieValue(rawKey) === name) {
|
|
193
|
+
return decodeCookieValue(rest.join("="));
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return null;
|
|
197
|
+
};
|
|
198
|
+
var writeCookie = (name, value, options) => {
|
|
199
|
+
if (!isBrowser()) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
const parts = [`${encodeCookieValue(name)}=${encodeCookieValue(value)}`];
|
|
203
|
+
if (options.path) {
|
|
204
|
+
parts.push(`Path=${options.path}`);
|
|
205
|
+
}
|
|
206
|
+
if (options.domain) {
|
|
207
|
+
parts.push(`Domain=${options.domain}`);
|
|
208
|
+
}
|
|
209
|
+
if (options.sameSite) {
|
|
210
|
+
parts.push(`SameSite=${options.sameSite}`);
|
|
211
|
+
}
|
|
212
|
+
if (options.secure) {
|
|
213
|
+
parts.push("Secure");
|
|
214
|
+
}
|
|
215
|
+
if (options.expires instanceof Date) {
|
|
216
|
+
parts.push(`Expires=${options.expires.toUTCString()}`);
|
|
217
|
+
} else if (typeof options.expires === "number") {
|
|
218
|
+
const expires = /* @__PURE__ */ new Date();
|
|
219
|
+
expires.setDate(expires.getDate() + options.expires);
|
|
220
|
+
parts.push(`Expires=${expires.toUTCString()}`);
|
|
221
|
+
}
|
|
222
|
+
document.cookie = parts.join("; ");
|
|
223
|
+
};
|
|
224
|
+
var deleteCookie = (name, options) => {
|
|
225
|
+
if (!isBrowser()) {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
writeCookie(name, "", { ...options, expires: /* @__PURE__ */ new Date(0) });
|
|
229
|
+
};
|
|
230
|
+
var BrowserCookieStorageAdapter = class {
|
|
231
|
+
constructor(options = {}) {
|
|
232
|
+
__publicField(this, "cookiePrefix");
|
|
233
|
+
__publicField(this, "cookieOptions");
|
|
234
|
+
this.cookiePrefix = options.cookiePrefix ?? "";
|
|
235
|
+
this.cookieOptions = { ...DEFAULT_COOKIE_OPTIONS, ...options.cookieOptions };
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Read a cookie value.
|
|
239
|
+
*/
|
|
240
|
+
get(key) {
|
|
241
|
+
const cookieName = resolveCookieName(this.cookiePrefix, key);
|
|
242
|
+
return readCookie(cookieName);
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Persist a cookie value.
|
|
246
|
+
*/
|
|
247
|
+
set(key, value) {
|
|
248
|
+
const cookieName = resolveCookieName(this.cookiePrefix, key);
|
|
249
|
+
writeCookie(cookieName, value, this.cookieOptions);
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Delete a persisted cookie value.
|
|
253
|
+
*/
|
|
254
|
+
delete(key) {
|
|
255
|
+
const cookieName = resolveCookieName(this.cookiePrefix, key);
|
|
256
|
+
deleteCookie(cookieName, this.cookieOptions);
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
var ServerCookieAccessorsStorageAdapter = class {
|
|
260
|
+
constructor(options) {
|
|
261
|
+
__publicField(this, "cookiePrefix");
|
|
262
|
+
__publicField(this, "cookieOptions");
|
|
263
|
+
__publicField(this, "cookies");
|
|
264
|
+
this.cookies = options.cookies;
|
|
265
|
+
this.cookiePrefix = options.cookiePrefix ?? "";
|
|
266
|
+
this.cookieOptions = { ...DEFAULT_COOKIE_OPTIONS, ...options.cookieOptions };
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Read a cookie value.
|
|
270
|
+
*/
|
|
271
|
+
get(key) {
|
|
272
|
+
const cookieName = resolveCookieName(this.cookiePrefix, key);
|
|
273
|
+
const value = this.cookies.get(cookieName);
|
|
274
|
+
return resolveCookieValue(value);
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Persist a cookie value.
|
|
278
|
+
*/
|
|
279
|
+
set(key, value) {
|
|
280
|
+
const cookieName = resolveCookieName(this.cookiePrefix, key);
|
|
281
|
+
this.cookies.set(cookieName, value, this.cookieOptions);
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Delete a persisted cookie value.
|
|
285
|
+
*/
|
|
286
|
+
delete(key) {
|
|
287
|
+
const cookieName = resolveCookieName(this.cookiePrefix, key);
|
|
288
|
+
this.cookies.delete(cookieName, this.cookieOptions);
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
var NoopStorageAdapter = class {
|
|
292
|
+
/**
|
|
293
|
+
* Read a stored value (always null).
|
|
294
|
+
*/
|
|
295
|
+
get() {
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Persist a stored value (no-op).
|
|
300
|
+
*/
|
|
301
|
+
set() {
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Delete a stored value (no-op).
|
|
305
|
+
*/
|
|
306
|
+
delete() {
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
var createDefaultStorageAdapter = (options = {}) => {
|
|
310
|
+
if (isBrowser()) {
|
|
311
|
+
if (options.cookies) {
|
|
312
|
+
return new ServerCookieAccessorsStorageAdapter({
|
|
313
|
+
cookies: options.cookies,
|
|
314
|
+
cookiePrefix: options.cookiePrefix,
|
|
315
|
+
cookieOptions: options.cookieOptions
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
return new BrowserCookieStorageAdapter(options);
|
|
319
|
+
}
|
|
320
|
+
if (options.cookies) {
|
|
321
|
+
return new ServerCookieAccessorsStorageAdapter({
|
|
322
|
+
cookies: options.cookies,
|
|
323
|
+
cookiePrefix: options.cookiePrefix,
|
|
324
|
+
cookieOptions: options.cookieOptions
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
return new NoopStorageAdapter();
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
// src/auth.ts
|
|
331
|
+
var DEFAULT_REFRESH_THRESHOLD_SECONDS = 60;
|
|
332
|
+
var getTokenExpiry = (token) => {
|
|
333
|
+
try {
|
|
334
|
+
const payload = (0, import_jwt_decode.jwtDecode)(token);
|
|
335
|
+
const exp = payload?.exp;
|
|
336
|
+
return typeof exp === "number" ? exp : null;
|
|
337
|
+
} catch (error) {
|
|
338
|
+
const message = error instanceof Error ? error.message : "Failed to decode token";
|
|
339
|
+
throw createSdkError(message);
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
var AuthClient = class {
|
|
343
|
+
/**
|
|
344
|
+
* Create a new auth client instance.
|
|
345
|
+
*/
|
|
346
|
+
constructor(http, options = {}) {
|
|
347
|
+
__publicField(this, "http");
|
|
348
|
+
__publicField(this, "storage");
|
|
349
|
+
__publicField(this, "storageKey");
|
|
350
|
+
__publicField(this, "refreshEnabled");
|
|
351
|
+
__publicField(this, "refreshThresholdSeconds");
|
|
352
|
+
__publicField(this, "serviceKey");
|
|
353
|
+
__publicField(this, "currentSession", null);
|
|
354
|
+
__publicField(this, "stateListeners", /* @__PURE__ */ new Set());
|
|
355
|
+
__publicField(this, "restorePromise", null);
|
|
356
|
+
/**
|
|
357
|
+
* Track whether storage restoration has already been attempted.
|
|
358
|
+
*/
|
|
359
|
+
__publicField(this, "restoreAttempted", false);
|
|
360
|
+
this.http = http;
|
|
361
|
+
this.storage = options.storage ?? new NoopStorageAdapter();
|
|
362
|
+
this.storageKey = options.storageKey ?? DEFAULT_AUTH_COOKIE_NAME;
|
|
363
|
+
this.refreshEnabled = options.autoRefresh ?? false;
|
|
364
|
+
this.refreshThresholdSeconds = options.refreshThresholdSeconds ?? DEFAULT_REFRESH_THRESHOLD_SECONDS;
|
|
365
|
+
this.serviceKey = options.serviceKey ?? null;
|
|
366
|
+
this.registerAuthHook();
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Set the current bearer token, or clear it when null.
|
|
370
|
+
*/
|
|
371
|
+
async setToken(token) {
|
|
372
|
+
if (!token) {
|
|
373
|
+
await this.storage.delete(this.storageKey);
|
|
374
|
+
this.currentSession = null;
|
|
375
|
+
this.emitState("SIGNED_OUT", null);
|
|
376
|
+
return null;
|
|
377
|
+
}
|
|
378
|
+
return this.applyToken(token, "SIGNED_IN");
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Get the currently configured token (if any).
|
|
382
|
+
*/
|
|
383
|
+
getToken() {
|
|
384
|
+
return this.currentSession ?? this.serviceKey ?? null;
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Clear the current token and session.
|
|
388
|
+
*/
|
|
389
|
+
async clearToken() {
|
|
390
|
+
await this.setToken(null);
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Sign in using a JWT token.
|
|
394
|
+
*/
|
|
395
|
+
async signInWithToken(token, options = {}) {
|
|
396
|
+
if (options.verifySession) {
|
|
397
|
+
this.assertTokenNotExpired(token);
|
|
398
|
+
}
|
|
399
|
+
return this.applyToken(token, "SIGNED_IN");
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Sign in using email/password credentials.
|
|
403
|
+
*/
|
|
404
|
+
async signIn(payload) {
|
|
405
|
+
const { data, request, response } = await this.http.requestWithMetadata(
|
|
406
|
+
"/v2/auth/login",
|
|
407
|
+
{
|
|
408
|
+
method: "POST",
|
|
409
|
+
body: JSON.stringify(payload)
|
|
410
|
+
}
|
|
411
|
+
);
|
|
412
|
+
const token = this.resolveTokenFromResponse(data, { request, response });
|
|
413
|
+
return this.applyToken(token, "SIGNED_IN");
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Sign out the current user.
|
|
417
|
+
*/
|
|
418
|
+
async signOut() {
|
|
419
|
+
try {
|
|
420
|
+
await this.http.request("/v2/auth/logout", { method: "POST" });
|
|
421
|
+
} finally {
|
|
422
|
+
await this.clearToken();
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Get the current session, restoring from storage if needed.
|
|
427
|
+
*/
|
|
428
|
+
async getSession() {
|
|
429
|
+
if (this.currentSession) {
|
|
430
|
+
return this.currentSession;
|
|
431
|
+
}
|
|
432
|
+
await this.restoreFromStorage();
|
|
433
|
+
return this.currentSession;
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Refresh the current session token.
|
|
437
|
+
* Manual refresh is always available; automatic refresh is controlled
|
|
438
|
+
* by the `autoRefresh` option.
|
|
439
|
+
*/
|
|
440
|
+
async refreshToken() {
|
|
441
|
+
if (this.isUsingServiceKey()) {
|
|
442
|
+
throw createSdkError("Token refresh is unavailable when using a service key");
|
|
443
|
+
}
|
|
444
|
+
try {
|
|
445
|
+
const { data, request, response } = await this.http.requestWithMetadata(
|
|
446
|
+
"/v2/auth/refresh",
|
|
447
|
+
{ method: "POST" }
|
|
448
|
+
);
|
|
449
|
+
const token = this.resolveTokenFromResponse(data, { request, response });
|
|
450
|
+
return await this.applyToken(token, "TOKEN_REFRESHED");
|
|
451
|
+
} catch (error) {
|
|
452
|
+
await this.clearToken();
|
|
453
|
+
throw error;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Subscribe to auth state changes.
|
|
458
|
+
*/
|
|
459
|
+
onAuthStateChange(callback) {
|
|
460
|
+
this.stateListeners.add(callback);
|
|
461
|
+
return () => {
|
|
462
|
+
this.stateListeners.delete(callback);
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
emitState(event, token) {
|
|
466
|
+
for (const listener of this.stateListeners) {
|
|
467
|
+
listener(event, token);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Register the auth header hook for outgoing HTTP requests.
|
|
472
|
+
*/
|
|
473
|
+
registerAuthHook() {
|
|
474
|
+
this.http.onBeforeRequest(async (request) => {
|
|
475
|
+
if (!this.http.isSameOrigin(request.url)) {
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
const token = await this.resolveRequestToken();
|
|
479
|
+
if (!token) {
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
const headers = {
|
|
483
|
+
...request.init.headers ?? {}
|
|
484
|
+
};
|
|
485
|
+
if (headers.Authorization || headers.authorization) {
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
return {
|
|
489
|
+
...request,
|
|
490
|
+
init: {
|
|
491
|
+
...request.init,
|
|
492
|
+
headers: {
|
|
493
|
+
...headers,
|
|
494
|
+
Authorization: `Bearer ${token}`
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
};
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* Resolve the bearer token to use for outgoing requests.
|
|
502
|
+
*/
|
|
503
|
+
async resolveRequestToken() {
|
|
504
|
+
if (this.currentSession) {
|
|
505
|
+
return this.currentSession;
|
|
506
|
+
}
|
|
507
|
+
if (this.serviceKey) {
|
|
508
|
+
return this.serviceKey;
|
|
509
|
+
}
|
|
510
|
+
return await this.getSession();
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* Persist a token update and notify listeners.
|
|
514
|
+
*/
|
|
515
|
+
async applyToken(token, event) {
|
|
516
|
+
await Promise.resolve(this.storage.set(this.storageKey, token));
|
|
517
|
+
this.currentSession = token;
|
|
518
|
+
this.emitState(event, token);
|
|
519
|
+
return token;
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* Restore a persisted token from storage when needed.
|
|
523
|
+
*/
|
|
524
|
+
async restoreFromStorage() {
|
|
525
|
+
if (this.restorePromise) {
|
|
526
|
+
return this.restorePromise;
|
|
527
|
+
}
|
|
528
|
+
if (this.restoreAttempted) {
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
if (this.serviceKey) {
|
|
532
|
+
this.restoreAttempted = true;
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
this.restorePromise = (async () => {
|
|
536
|
+
const storedToken = await Promise.resolve(
|
|
537
|
+
this.storage.get(this.storageKey)
|
|
538
|
+
);
|
|
539
|
+
if (!storedToken) {
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
let exp = null;
|
|
543
|
+
if (this.refreshEnabled) {
|
|
544
|
+
try {
|
|
545
|
+
exp = getTokenExpiry(storedToken);
|
|
546
|
+
} catch {
|
|
547
|
+
this.currentSession = null;
|
|
548
|
+
await Promise.resolve(this.storage.delete(this.storageKey));
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
const hadSession = this.currentSession !== null;
|
|
553
|
+
this.currentSession = storedToken;
|
|
554
|
+
if (!hadSession) {
|
|
555
|
+
this.emitState("SIGNED_IN", storedToken);
|
|
556
|
+
}
|
|
557
|
+
if (this.refreshEnabled && exp !== null) {
|
|
558
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
559
|
+
if (exp - now <= this.refreshThresholdSeconds) {
|
|
560
|
+
try {
|
|
561
|
+
await this.refreshToken();
|
|
562
|
+
} catch {
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
})();
|
|
567
|
+
try {
|
|
568
|
+
await this.restorePromise;
|
|
569
|
+
} finally {
|
|
570
|
+
this.restorePromise = null;
|
|
571
|
+
this.restoreAttempted = true;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* Determine if the client is currently using the service key.
|
|
576
|
+
*/
|
|
577
|
+
isUsingServiceKey() {
|
|
578
|
+
return !!this.serviceKey && !this.currentSession;
|
|
579
|
+
}
|
|
580
|
+
/**
|
|
581
|
+
* Resolve the auth token from a response payload and request metadata.
|
|
582
|
+
*/
|
|
583
|
+
resolveTokenFromResponse(response, metadata) {
|
|
584
|
+
if (response.error || response.error_description) {
|
|
585
|
+
const message = response.error_description ?? response.error ?? "Authentication failed";
|
|
586
|
+
throw createSdkError(message, {
|
|
587
|
+
request: metadata.request,
|
|
588
|
+
response: metadata.response,
|
|
589
|
+
userMessage: message
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
const token = response.access_token ?? response.token;
|
|
593
|
+
if (!token) {
|
|
594
|
+
throw createSdkError("Missing access token in response", {
|
|
595
|
+
request: metadata.request,
|
|
596
|
+
response: metadata.response
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
return token;
|
|
600
|
+
}
|
|
601
|
+
assertTokenNotExpired(token) {
|
|
602
|
+
const exp = getTokenExpiry(token);
|
|
603
|
+
if (exp === null) {
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
607
|
+
if (exp < now) {
|
|
608
|
+
throw createSdkError("Token has expired");
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
};
|
|
612
|
+
|
|
613
|
+
// src/channels.ts
|
|
614
|
+
var ChannelsClient = class {
|
|
615
|
+
/**
|
|
616
|
+
* Create a new channels client instance.
|
|
617
|
+
*/
|
|
618
|
+
constructor(http) {
|
|
619
|
+
__publicField(this, "http");
|
|
620
|
+
this.http = http;
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* Fetch a channel by username.
|
|
624
|
+
*/
|
|
625
|
+
async get(username, options = {}) {
|
|
626
|
+
const rest = { ...options, body: void 0 };
|
|
627
|
+
return this.http.request(
|
|
628
|
+
`/v2/channels/${encodeURIComponent(String(username))}`,
|
|
629
|
+
{
|
|
630
|
+
...rest,
|
|
631
|
+
method: "GET"
|
|
632
|
+
}
|
|
633
|
+
);
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* Follow a channel by slug.
|
|
637
|
+
*/
|
|
638
|
+
async follow(channelSlug, options = {}) {
|
|
639
|
+
return this.http.request(
|
|
640
|
+
`/v2/channels/${encodeURIComponent(channelSlug)}/follow`,
|
|
641
|
+
{
|
|
642
|
+
...options,
|
|
643
|
+
method: "POST"
|
|
644
|
+
}
|
|
645
|
+
);
|
|
646
|
+
}
|
|
647
|
+
/**
|
|
648
|
+
* Unfollow a channel by slug.
|
|
649
|
+
*/
|
|
650
|
+
async unfollow(channelSlug, options = {}) {
|
|
651
|
+
return this.http.request(
|
|
652
|
+
`/v2/channels/${encodeURIComponent(channelSlug)}/unfollow`,
|
|
653
|
+
{
|
|
654
|
+
...options,
|
|
655
|
+
method: "POST"
|
|
656
|
+
}
|
|
657
|
+
);
|
|
658
|
+
}
|
|
659
|
+
};
|
|
660
|
+
|
|
661
|
+
// src/resource.ts
|
|
662
|
+
var buildQueryString = (params) => {
|
|
663
|
+
if (!params) {
|
|
664
|
+
return "";
|
|
665
|
+
}
|
|
666
|
+
const searchParams = new URLSearchParams();
|
|
667
|
+
for (const [key, value] of Object.entries(params)) {
|
|
668
|
+
if (Array.isArray(value)) {
|
|
669
|
+
for (const item of value) {
|
|
670
|
+
if (item === null || item === void 0) {
|
|
671
|
+
continue;
|
|
672
|
+
}
|
|
673
|
+
searchParams.append(`${key}[]`, String(item));
|
|
674
|
+
}
|
|
675
|
+
continue;
|
|
676
|
+
}
|
|
677
|
+
if (value === null || value === void 0) {
|
|
678
|
+
continue;
|
|
679
|
+
}
|
|
680
|
+
searchParams.set(key, String(value));
|
|
681
|
+
}
|
|
682
|
+
return searchParams.toString();
|
|
683
|
+
};
|
|
684
|
+
|
|
685
|
+
// src/chat.ts
|
|
686
|
+
var ChatClient = class {
|
|
687
|
+
/**
|
|
688
|
+
* Create a new chat client instance.
|
|
689
|
+
*/
|
|
690
|
+
constructor(http) {
|
|
691
|
+
__publicField(this, "http");
|
|
692
|
+
this.http = http;
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* Fetch chat history for a stream.
|
|
696
|
+
*/
|
|
697
|
+
async getMessages(streamId, params = {}, options = {}) {
|
|
698
|
+
const rest = { ...options, body: void 0 };
|
|
699
|
+
const basePath = `/v2/streams/${encodeURIComponent(String(streamId))}/chat`;
|
|
700
|
+
const query = buildQueryString(params);
|
|
701
|
+
const path = query ? `${basePath}?${query}` : basePath;
|
|
702
|
+
return this.http.request(
|
|
703
|
+
path,
|
|
704
|
+
{
|
|
705
|
+
...rest,
|
|
706
|
+
method: "GET"
|
|
707
|
+
}
|
|
708
|
+
);
|
|
709
|
+
}
|
|
710
|
+
/**
|
|
711
|
+
* Resource-style alias for fetching chat messages by stream id.
|
|
712
|
+
* @param streamId - Stream identifier.
|
|
713
|
+
* @param options - Request options.
|
|
714
|
+
* @returns Chat messages response payload.
|
|
715
|
+
*/
|
|
716
|
+
async get(streamId, options = {}) {
|
|
717
|
+
return this.getMessages(streamId, {}, options);
|
|
718
|
+
}
|
|
719
|
+
/**
|
|
720
|
+
* Send a message to a stream chat.
|
|
721
|
+
*/
|
|
722
|
+
async sendMessage(streamId, message, options = {}) {
|
|
723
|
+
return this.http.request(
|
|
724
|
+
`/v2/streams/${encodeURIComponent(String(streamId))}/chat`,
|
|
725
|
+
{
|
|
726
|
+
...options,
|
|
727
|
+
method: "POST",
|
|
728
|
+
body: JSON.stringify({ message })
|
|
729
|
+
}
|
|
730
|
+
);
|
|
731
|
+
}
|
|
732
|
+
};
|
|
733
|
+
|
|
734
|
+
// src/http.ts
|
|
735
|
+
var resolveFetch = (provided) => {
|
|
736
|
+
if (provided) {
|
|
737
|
+
return provided.bind(globalThis);
|
|
738
|
+
}
|
|
739
|
+
if (typeof fetch === "function") {
|
|
740
|
+
return fetch.bind(globalThis);
|
|
741
|
+
}
|
|
742
|
+
throw createSdkError(
|
|
743
|
+
"Fetch implementation not found. Provide options.fetch when running outside Node 22+ or the browser."
|
|
744
|
+
);
|
|
745
|
+
};
|
|
746
|
+
var redactRequestMetadata = (request) => {
|
|
747
|
+
const redacted = request.clone();
|
|
748
|
+
redacted.headers.delete("authorization");
|
|
749
|
+
return redacted;
|
|
750
|
+
};
|
|
751
|
+
var removeContentTypeHeader = (headers) => {
|
|
752
|
+
for (const key of Object.keys(headers)) {
|
|
753
|
+
if (key.toLowerCase() === "content-type") {
|
|
754
|
+
delete headers[key];
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
};
|
|
758
|
+
var normalizeHeaders = (headers) => {
|
|
759
|
+
if (!headers) {
|
|
760
|
+
return {};
|
|
761
|
+
}
|
|
762
|
+
if (headers instanceof Headers) {
|
|
763
|
+
return Object.fromEntries(headers.entries());
|
|
764
|
+
}
|
|
765
|
+
if (Array.isArray(headers)) {
|
|
766
|
+
return Object.fromEntries(headers);
|
|
767
|
+
}
|
|
768
|
+
return { ...headers };
|
|
769
|
+
};
|
|
770
|
+
var HttpClient = class {
|
|
771
|
+
/**
|
|
772
|
+
* Create a new HTTP client instance.
|
|
773
|
+
*/
|
|
774
|
+
constructor(options) {
|
|
775
|
+
__publicField(this, "baseUrl");
|
|
776
|
+
__publicField(this, "defaultHeaders");
|
|
777
|
+
__publicField(this, "fetcher");
|
|
778
|
+
__publicField(this, "beforeRequestHooks", []);
|
|
779
|
+
this.baseUrl = options.baseUrl.replace(/\/+$/, "");
|
|
780
|
+
this.defaultHeaders = {
|
|
781
|
+
"Content-Type": "application/json",
|
|
782
|
+
Accept: "application/json",
|
|
783
|
+
...options.headers
|
|
784
|
+
};
|
|
785
|
+
this.fetcher = resolveFetch(options.fetch);
|
|
786
|
+
}
|
|
787
|
+
/**
|
|
788
|
+
* Register a hook that runs before each request.
|
|
789
|
+
*/
|
|
790
|
+
onBeforeRequest(hook) {
|
|
791
|
+
this.beforeRequestHooks = [...this.beforeRequestHooks, hook];
|
|
792
|
+
return () => {
|
|
793
|
+
this.beforeRequestHooks = this.beforeRequestHooks.filter(
|
|
794
|
+
(existing) => existing !== hook
|
|
795
|
+
);
|
|
796
|
+
};
|
|
797
|
+
}
|
|
798
|
+
/**
|
|
799
|
+
* Execute an HTTP request and return the parsed response.
|
|
800
|
+
*/
|
|
801
|
+
async request(path, options = {}) {
|
|
802
|
+
const { data } = await this.requestWithMetadata(path, options);
|
|
803
|
+
return data;
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
806
|
+
* Execute an HTTP request and return the response with request metadata.
|
|
807
|
+
*/
|
|
808
|
+
async requestWithMetadata(path, options = {}) {
|
|
809
|
+
const url = /^https?:\/\//i.test(path) ? path : `${this.baseUrl}${path.startsWith("/") ? path : `/${path}`}`;
|
|
810
|
+
const method = (options.method ?? "GET").toUpperCase();
|
|
811
|
+
const headers = {
|
|
812
|
+
...this.defaultHeaders,
|
|
813
|
+
...options.headers
|
|
814
|
+
};
|
|
815
|
+
const hasExplicitContentType = Object.keys(options.headers ?? {}).some(
|
|
816
|
+
(key) => key.toLowerCase() === "content-type"
|
|
817
|
+
);
|
|
818
|
+
let request = {
|
|
819
|
+
url,
|
|
820
|
+
init: {
|
|
821
|
+
...options,
|
|
822
|
+
method,
|
|
823
|
+
headers
|
|
824
|
+
}
|
|
825
|
+
};
|
|
826
|
+
request = await this.beforeRequestHooks.reduce(
|
|
827
|
+
async (pendingRequest, hook) => {
|
|
828
|
+
const currentRequest = await pendingRequest;
|
|
829
|
+
const result = await hook(currentRequest);
|
|
830
|
+
return result ?? currentRequest;
|
|
831
|
+
},
|
|
832
|
+
Promise.resolve(request)
|
|
833
|
+
);
|
|
834
|
+
const normalizedHeaders = normalizeHeaders(request.init.headers);
|
|
835
|
+
const resolvedMethod = (request.init.method ?? method).toUpperCase();
|
|
836
|
+
const hasBody = request.init.body !== void 0 && request.init.body !== null;
|
|
837
|
+
if (!hasBody && !hasExplicitContentType && (resolvedMethod === "GET" || resolvedMethod === "HEAD")) {
|
|
838
|
+
removeContentTypeHeader(normalizedHeaders);
|
|
839
|
+
}
|
|
840
|
+
request = {
|
|
841
|
+
...request,
|
|
842
|
+
init: {
|
|
843
|
+
...request.init,
|
|
844
|
+
method: resolvedMethod,
|
|
845
|
+
headers: normalizedHeaders
|
|
846
|
+
}
|
|
847
|
+
};
|
|
848
|
+
const requestMetadata = new Request(request.url, request.init);
|
|
849
|
+
let response = null;
|
|
850
|
+
try {
|
|
851
|
+
response = await this.fetcher(request.url, request.init);
|
|
852
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
853
|
+
const isJson = contentType.includes("application/json");
|
|
854
|
+
if (!response.ok) {
|
|
855
|
+
const payload = isJson ? await response.json().catch(() => void 0) : await response.text();
|
|
856
|
+
const payloadObject = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : null;
|
|
857
|
+
const fallbackMessage = typeof payload === "string" ? payload : null;
|
|
858
|
+
const message = typeof payloadObject?.message === "string" ? payloadObject.message : fallbackMessage || response.statusText || "Request failed";
|
|
859
|
+
const { code, ...payloadDetails } = payloadObject ?? {};
|
|
860
|
+
const resolvedCode = typeof code === "string" ? code : void 0;
|
|
861
|
+
throw createSdkError(message, {
|
|
862
|
+
...payloadDetails,
|
|
863
|
+
code: resolvedCode,
|
|
864
|
+
request: redactRequestMetadata(requestMetadata),
|
|
865
|
+
response
|
|
866
|
+
});
|
|
867
|
+
}
|
|
868
|
+
if (response.status === 204) {
|
|
869
|
+
return { data: void 0, request: requestMetadata, response };
|
|
870
|
+
}
|
|
871
|
+
if (contentType.includes("application/json")) {
|
|
872
|
+
return {
|
|
873
|
+
data: await response.json(),
|
|
874
|
+
request: requestMetadata,
|
|
875
|
+
response
|
|
876
|
+
};
|
|
877
|
+
}
|
|
878
|
+
return {
|
|
879
|
+
data: await response.text(),
|
|
880
|
+
request: requestMetadata,
|
|
881
|
+
response
|
|
882
|
+
};
|
|
883
|
+
} catch (error) {
|
|
884
|
+
if (error instanceof SDKError) {
|
|
885
|
+
throw error;
|
|
886
|
+
}
|
|
887
|
+
const fallbackMessage = error instanceof Error ? error.message : "Request failed";
|
|
888
|
+
throw createSdkError(fallbackMessage, {
|
|
889
|
+
request: redactRequestMetadata(requestMetadata),
|
|
890
|
+
response
|
|
891
|
+
});
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
/**
|
|
895
|
+
* Determine whether the provided URL is same-origin with the configured base URL.
|
|
896
|
+
*/
|
|
897
|
+
isSameOrigin(url) {
|
|
898
|
+
try {
|
|
899
|
+
return new URL(url).origin === new URL(this.baseUrl).origin;
|
|
900
|
+
} catch {
|
|
901
|
+
return false;
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
};
|
|
905
|
+
|
|
906
|
+
// src/realtime.ts
|
|
907
|
+
var resolvePusher = () => {
|
|
908
|
+
const injected = globalThis.__SDK_Pusher;
|
|
909
|
+
if (injected) {
|
|
910
|
+
return injected;
|
|
911
|
+
}
|
|
912
|
+
const globalPusher = globalThis.Pusher;
|
|
913
|
+
if (globalPusher) {
|
|
914
|
+
return globalPusher;
|
|
915
|
+
}
|
|
916
|
+
if (typeof require === "function") {
|
|
917
|
+
try {
|
|
918
|
+
const module2 = require("pusher-js");
|
|
919
|
+
return module2.default ?? module2;
|
|
920
|
+
} catch {
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
const dynamicImport = import("pusher-js");
|
|
924
|
+
return dynamicImport.then((module2) => {
|
|
925
|
+
const resolvedModule = module2;
|
|
926
|
+
return resolvedModule.default ?? module2;
|
|
927
|
+
}).catch(() => {
|
|
928
|
+
throw createSdkError(
|
|
929
|
+
"Pusher constructor not found. Provide globalThis.__SDK_Pusher/globalThis.Pusher, or ensure pusher-js is resolvable from a CJS context (ESM runtimes must inject the global constructor)."
|
|
930
|
+
);
|
|
931
|
+
});
|
|
932
|
+
};
|
|
933
|
+
var isPromise = (value) => Boolean(value && typeof value.then === "function");
|
|
934
|
+
var normalizeAuthEndpoint = (baseUrl, authEndpoint) => {
|
|
935
|
+
if (authEndpoint) {
|
|
936
|
+
return authEndpoint;
|
|
937
|
+
}
|
|
938
|
+
if (!baseUrl) {
|
|
939
|
+
return "/api/broadcasting/auth";
|
|
940
|
+
}
|
|
941
|
+
const trimmed = baseUrl.replace(/\/+$/, "");
|
|
942
|
+
if (trimmed.endsWith("/api")) {
|
|
943
|
+
return `${trimmed}/broadcasting/auth`;
|
|
944
|
+
}
|
|
945
|
+
return `${trimmed}/api/broadcasting/auth`;
|
|
946
|
+
};
|
|
947
|
+
var normalizePresenceMembers = (members) => {
|
|
948
|
+
if (!members) {
|
|
949
|
+
return [];
|
|
950
|
+
}
|
|
951
|
+
if (Array.isArray(members)) {
|
|
952
|
+
return members;
|
|
953
|
+
}
|
|
954
|
+
const memberRecord = members.members;
|
|
955
|
+
if (memberRecord && typeof memberRecord === "object") {
|
|
956
|
+
return Object.values(memberRecord);
|
|
957
|
+
}
|
|
958
|
+
if (typeof members === "object") {
|
|
959
|
+
return Object.values(members);
|
|
960
|
+
}
|
|
961
|
+
return [];
|
|
962
|
+
};
|
|
963
|
+
var createPresenceBindings = () => ({
|
|
964
|
+
here: /* @__PURE__ */ new Map(),
|
|
965
|
+
joining: /* @__PURE__ */ new Map(),
|
|
966
|
+
leaving: /* @__PURE__ */ new Map()
|
|
967
|
+
});
|
|
968
|
+
var NoopRealtimeChannel = class {
|
|
969
|
+
listen() {
|
|
970
|
+
}
|
|
971
|
+
stopListening() {
|
|
972
|
+
}
|
|
973
|
+
/**
|
|
974
|
+
* Register a no-op presence callback.
|
|
975
|
+
* @returns Unsubscribe function.
|
|
976
|
+
*/
|
|
977
|
+
here(_callback) {
|
|
978
|
+
return () => void 0;
|
|
979
|
+
}
|
|
980
|
+
/**
|
|
981
|
+
* Register a no-op presence callback.
|
|
982
|
+
* @returns Unsubscribe function.
|
|
983
|
+
*/
|
|
984
|
+
joining(_callback) {
|
|
985
|
+
return () => void 0;
|
|
986
|
+
}
|
|
987
|
+
/**
|
|
988
|
+
* Register a no-op presence callback.
|
|
989
|
+
* @returns Unsubscribe function.
|
|
990
|
+
*/
|
|
991
|
+
leaving(_callback) {
|
|
992
|
+
return () => void 0;
|
|
993
|
+
}
|
|
994
|
+
};
|
|
995
|
+
var NoopRealtimeTransport = class {
|
|
996
|
+
constructor() {
|
|
997
|
+
/**
|
|
998
|
+
* Raw realtime provider instance.
|
|
999
|
+
*/
|
|
1000
|
+
__publicField(this, "pusher", null);
|
|
1001
|
+
}
|
|
1002
|
+
/**
|
|
1003
|
+
* Subscribe to a public channel.
|
|
1004
|
+
*/
|
|
1005
|
+
channel() {
|
|
1006
|
+
return new NoopRealtimeChannel();
|
|
1007
|
+
}
|
|
1008
|
+
/**
|
|
1009
|
+
* Subscribe to a private channel.
|
|
1010
|
+
*/
|
|
1011
|
+
"private"() {
|
|
1012
|
+
return new NoopRealtimeChannel();
|
|
1013
|
+
}
|
|
1014
|
+
/**
|
|
1015
|
+
* Subscribe to a presence channel.
|
|
1016
|
+
*/
|
|
1017
|
+
join() {
|
|
1018
|
+
return new NoopRealtimeChannel();
|
|
1019
|
+
}
|
|
1020
|
+
/**
|
|
1021
|
+
* Leave a channel.
|
|
1022
|
+
*/
|
|
1023
|
+
leave() {
|
|
1024
|
+
}
|
|
1025
|
+
/**
|
|
1026
|
+
* Disconnect the realtime client.
|
|
1027
|
+
*/
|
|
1028
|
+
disconnect() {
|
|
1029
|
+
}
|
|
1030
|
+
/**
|
|
1031
|
+
* Update the auth token for realtime subscriptions.
|
|
1032
|
+
*/
|
|
1033
|
+
setToken() {
|
|
1034
|
+
}
|
|
1035
|
+
/**
|
|
1036
|
+
* Listen for connection state changes.
|
|
1037
|
+
*/
|
|
1038
|
+
onConnectionStateChange(callback) {
|
|
1039
|
+
callback("disconnected");
|
|
1040
|
+
return () => void 0;
|
|
1041
|
+
}
|
|
1042
|
+
};
|
|
1043
|
+
var PusherRealtimeTransport = class {
|
|
1044
|
+
/**
|
|
1045
|
+
* Create a new Pusher-backed realtime transport.
|
|
1046
|
+
* @param options - Realtime client configuration.
|
|
1047
|
+
*/
|
|
1048
|
+
constructor(options) {
|
|
1049
|
+
__publicField(this, "pusher", null);
|
|
1050
|
+
__publicField(this, "options");
|
|
1051
|
+
/**
|
|
1052
|
+
* Resolved Pusher constructor used during initialization.
|
|
1053
|
+
*/
|
|
1054
|
+
__publicField(this, "pusherConstructor", null);
|
|
1055
|
+
/**
|
|
1056
|
+
* Initialization promise when awaiting async token resolution.
|
|
1057
|
+
*/
|
|
1058
|
+
__publicField(this, "initializationPromise", null);
|
|
1059
|
+
/**
|
|
1060
|
+
* Track whether disconnect was invoked before initialization finished.
|
|
1061
|
+
*/
|
|
1062
|
+
__publicField(this, "isDisconnected", false);
|
|
1063
|
+
__publicField(this, "subscriptions", /* @__PURE__ */ new Map());
|
|
1064
|
+
__publicField(this, "connectionListeners", /* @__PURE__ */ new Set());
|
|
1065
|
+
/**
|
|
1066
|
+
* Mutable auth header map shared with the Pusher instance.
|
|
1067
|
+
*/
|
|
1068
|
+
__publicField(this, "authHeaders", {});
|
|
1069
|
+
__publicField(this, "token", null);
|
|
1070
|
+
__publicField(this, "currentState", "connecting");
|
|
1071
|
+
/**
|
|
1072
|
+
* Track whether connection listeners are currently being notified.
|
|
1073
|
+
*/
|
|
1074
|
+
__publicField(this, "isNotifyingState", false);
|
|
1075
|
+
/**
|
|
1076
|
+
* Queue connection state transitions to preserve delivery order.
|
|
1077
|
+
*/
|
|
1078
|
+
__publicField(this, "pendingStates", []);
|
|
1079
|
+
this.options = options;
|
|
1080
|
+
const pendingResolutions = [];
|
|
1081
|
+
const pusherResolution = resolvePusher();
|
|
1082
|
+
if (isPromise(pusherResolution)) {
|
|
1083
|
+
pendingResolutions.push(
|
|
1084
|
+
pusherResolution.then((constructor) => {
|
|
1085
|
+
this.pusherConstructor = constructor;
|
|
1086
|
+
})
|
|
1087
|
+
);
|
|
1088
|
+
} else {
|
|
1089
|
+
this.pusherConstructor = pusherResolution;
|
|
1090
|
+
}
|
|
1091
|
+
const tokenResolution = this.resolveTokenFromOptions();
|
|
1092
|
+
if (isPromise(tokenResolution)) {
|
|
1093
|
+
pendingResolutions.push(tokenResolution);
|
|
1094
|
+
}
|
|
1095
|
+
if (pendingResolutions.length > 0) {
|
|
1096
|
+
this.initializationPromise = Promise.all(pendingResolutions).then(() => {
|
|
1097
|
+
if (this.isDisconnected) {
|
|
1098
|
+
this.initializationPromise = null;
|
|
1099
|
+
return;
|
|
1100
|
+
}
|
|
1101
|
+
this.initialize();
|
|
1102
|
+
}).catch((error) => {
|
|
1103
|
+
this.handleInitializationFailure(error);
|
|
1104
|
+
});
|
|
1105
|
+
return;
|
|
1106
|
+
}
|
|
1107
|
+
this.initialize();
|
|
1108
|
+
}
|
|
1109
|
+
/**
|
|
1110
|
+
* Subscribe to a public channel.
|
|
1111
|
+
*/
|
|
1112
|
+
channel(name) {
|
|
1113
|
+
return this.subscribe(name, "public");
|
|
1114
|
+
}
|
|
1115
|
+
/**
|
|
1116
|
+
* Subscribe to a private channel.
|
|
1117
|
+
*/
|
|
1118
|
+
"private"(name) {
|
|
1119
|
+
return this.subscribe(name, "private");
|
|
1120
|
+
}
|
|
1121
|
+
/**
|
|
1122
|
+
* Subscribe to a presence channel.
|
|
1123
|
+
*/
|
|
1124
|
+
join(name) {
|
|
1125
|
+
return this.subscribe(name, "presence");
|
|
1126
|
+
}
|
|
1127
|
+
/**
|
|
1128
|
+
* Leave a channel.
|
|
1129
|
+
*/
|
|
1130
|
+
leave(name) {
|
|
1131
|
+
const subscription = this.subscriptions.get(name) ?? this.subscriptions.get(this.getChannelName(name, "presence")) ?? this.subscriptions.get(this.getChannelName(name, "private"));
|
|
1132
|
+
if (!subscription) {
|
|
1133
|
+
return;
|
|
1134
|
+
}
|
|
1135
|
+
if (!this.pusher) {
|
|
1136
|
+
this.subscriptions.delete(subscription.channelName);
|
|
1137
|
+
return;
|
|
1138
|
+
}
|
|
1139
|
+
this.pusher.unsubscribe(subscription.channelName);
|
|
1140
|
+
this.subscriptions.delete(subscription.channelName);
|
|
1141
|
+
}
|
|
1142
|
+
/**
|
|
1143
|
+
* Disconnect the realtime client.
|
|
1144
|
+
*/
|
|
1145
|
+
disconnect() {
|
|
1146
|
+
this.isDisconnected = true;
|
|
1147
|
+
if (!this.pusher) {
|
|
1148
|
+
this.subscriptions.clear();
|
|
1149
|
+
this.handleConnectionState("disconnected");
|
|
1150
|
+
return;
|
|
1151
|
+
}
|
|
1152
|
+
this.pusher.disconnect();
|
|
1153
|
+
this.pusher = null;
|
|
1154
|
+
this.subscriptions.clear();
|
|
1155
|
+
this.handleConnectionState("disconnected");
|
|
1156
|
+
}
|
|
1157
|
+
/**
|
|
1158
|
+
* Update the auth token for realtime subscriptions.
|
|
1159
|
+
*/
|
|
1160
|
+
setToken(token) {
|
|
1161
|
+
this.applyToken(token);
|
|
1162
|
+
}
|
|
1163
|
+
/**
|
|
1164
|
+
* Listen for connection state changes.
|
|
1165
|
+
*/
|
|
1166
|
+
onConnectionStateChange(callback) {
|
|
1167
|
+
this.connectionListeners.add(callback);
|
|
1168
|
+
callback(this.currentState);
|
|
1169
|
+
return () => {
|
|
1170
|
+
this.connectionListeners.delete(callback);
|
|
1171
|
+
};
|
|
1172
|
+
}
|
|
1173
|
+
/**
|
|
1174
|
+
* Record initialization failures without throwing unhandled rejections.
|
|
1175
|
+
* @param error - Initialization failure.
|
|
1176
|
+
*/
|
|
1177
|
+
handleInitializationFailure(error) {
|
|
1178
|
+
void error;
|
|
1179
|
+
this.initializationPromise = null;
|
|
1180
|
+
this.pusher = null;
|
|
1181
|
+
this.handleConnectionState("failed");
|
|
1182
|
+
}
|
|
1183
|
+
initialize() {
|
|
1184
|
+
if (!this.pusherConstructor) {
|
|
1185
|
+
throw createSdkError(
|
|
1186
|
+
"Pusher constructor not found. Provide globalThis.__SDK_Pusher/globalThis.Pusher, or ensure pusher-js is resolvable from a CJS context (ESM runtimes must inject the global constructor)."
|
|
1187
|
+
);
|
|
1188
|
+
}
|
|
1189
|
+
const authEndpoint = normalizeAuthEndpoint(
|
|
1190
|
+
this.options.baseUrl,
|
|
1191
|
+
this.options.authEndpoint
|
|
1192
|
+
);
|
|
1193
|
+
this.pusher = new this.pusherConstructor(this.options.appKey, {
|
|
1194
|
+
wsHost: this.options.wsHost,
|
|
1195
|
+
wsPort: this.options.wsPort ?? 443,
|
|
1196
|
+
wssPort: this.options.wssPort ?? 443,
|
|
1197
|
+
forceTLS: this.options.forceTLS ?? true,
|
|
1198
|
+
enabledTransports: this.options.enabledTransports ?? ["ws", "wss"],
|
|
1199
|
+
cluster: this.options.cluster ?? "",
|
|
1200
|
+
authEndpoint,
|
|
1201
|
+
auth: {
|
|
1202
|
+
headers: this.authHeaders
|
|
1203
|
+
}
|
|
1204
|
+
});
|
|
1205
|
+
this.pusher.connection.bind("state_change", (states) => {
|
|
1206
|
+
this.handleConnectionState(states.current);
|
|
1207
|
+
});
|
|
1208
|
+
this.handleConnectionState(this.pusher.connection.state);
|
|
1209
|
+
this.initializationPromise = null;
|
|
1210
|
+
this.flushPendingSubscriptions(this.pusher);
|
|
1211
|
+
}
|
|
1212
|
+
/**
|
|
1213
|
+
* Subscribe any queued channels after initialization completes.
|
|
1214
|
+
* @param pusher - Initialized Pusher client instance.
|
|
1215
|
+
*/
|
|
1216
|
+
flushPendingSubscriptions(pusher) {
|
|
1217
|
+
for (const subscription of this.subscriptions.values()) {
|
|
1218
|
+
if (!subscription.pending) {
|
|
1219
|
+
continue;
|
|
1220
|
+
}
|
|
1221
|
+
const channel = pusher.subscribe(
|
|
1222
|
+
subscription.channelName
|
|
1223
|
+
);
|
|
1224
|
+
subscription.channel = channel;
|
|
1225
|
+
subscription.pending = false;
|
|
1226
|
+
this.bindListeners(subscription);
|
|
1227
|
+
this.rebindPresenceCallbacks(subscription);
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
/**
|
|
1231
|
+
* Resolve an initial token from the options provider if available.
|
|
1232
|
+
* @returns A promise when async token resolution is in progress.
|
|
1233
|
+
* @throws {SDKError} When token resolution fails.
|
|
1234
|
+
*/
|
|
1235
|
+
resolveTokenFromOptions() {
|
|
1236
|
+
if (!this.options.getToken) {
|
|
1237
|
+
return;
|
|
1238
|
+
}
|
|
1239
|
+
try {
|
|
1240
|
+
const result = this.options.getToken();
|
|
1241
|
+
if (isPromise(result)) {
|
|
1242
|
+
return result.then((token) => {
|
|
1243
|
+
this.applyToken(token);
|
|
1244
|
+
}).catch((error) => {
|
|
1245
|
+
throw this.normalizeTokenError(error, "Failed to resolve auth token.");
|
|
1246
|
+
});
|
|
1247
|
+
}
|
|
1248
|
+
this.applyToken(result ?? null);
|
|
1249
|
+
} catch (error) {
|
|
1250
|
+
throw this.normalizeTokenError(error, "Failed to resolve auth token.");
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
/**
|
|
1254
|
+
* Normalize token resolution errors into SDKError instances.
|
|
1255
|
+
* @param error - Error to normalize.
|
|
1256
|
+
* @param fallbackMessage - Fallback error message.
|
|
1257
|
+
* @returns Normalized SDKError instance.
|
|
1258
|
+
*/
|
|
1259
|
+
normalizeTokenError(error, fallbackMessage) {
|
|
1260
|
+
if (error instanceof SDKError) {
|
|
1261
|
+
return error;
|
|
1262
|
+
}
|
|
1263
|
+
const message = error instanceof Error ? error.message : fallbackMessage;
|
|
1264
|
+
return createSdkError(message);
|
|
1265
|
+
}
|
|
1266
|
+
/**
|
|
1267
|
+
* Apply a new auth token to the client configuration.
|
|
1268
|
+
* Refresh auth subscriptions whenever the token changes.
|
|
1269
|
+
*/
|
|
1270
|
+
applyToken(token) {
|
|
1271
|
+
if (token === this.token) {
|
|
1272
|
+
return;
|
|
1273
|
+
}
|
|
1274
|
+
this.token = token;
|
|
1275
|
+
this.syncAuthHeaders();
|
|
1276
|
+
if (!this.pusher) {
|
|
1277
|
+
return;
|
|
1278
|
+
}
|
|
1279
|
+
this.refreshAuthSubscriptions();
|
|
1280
|
+
}
|
|
1281
|
+
/**
|
|
1282
|
+
* Sync the auth header map with the current token.
|
|
1283
|
+
*/
|
|
1284
|
+
syncAuthHeaders() {
|
|
1285
|
+
if (this.token) {
|
|
1286
|
+
this.authHeaders.Authorization = `Bearer ${this.token}`;
|
|
1287
|
+
return;
|
|
1288
|
+
}
|
|
1289
|
+
delete this.authHeaders.Authorization;
|
|
1290
|
+
}
|
|
1291
|
+
/**
|
|
1292
|
+
* Normalize and broadcast realtime connection state changes.
|
|
1293
|
+
*/
|
|
1294
|
+
handleConnectionState(state) {
|
|
1295
|
+
const mapped = this.mapConnectionState(state);
|
|
1296
|
+
if (mapped === this.currentState) {
|
|
1297
|
+
return;
|
|
1298
|
+
}
|
|
1299
|
+
this.currentState = mapped;
|
|
1300
|
+
this.pendingStates.push(mapped);
|
|
1301
|
+
if (this.isNotifyingState) {
|
|
1302
|
+
return;
|
|
1303
|
+
}
|
|
1304
|
+
this.isNotifyingState = true;
|
|
1305
|
+
let firstError = null;
|
|
1306
|
+
try {
|
|
1307
|
+
while (this.pendingStates.length) {
|
|
1308
|
+
const nextState = this.pendingStates.shift();
|
|
1309
|
+
if (!nextState) {
|
|
1310
|
+
continue;
|
|
1311
|
+
}
|
|
1312
|
+
const listeners = Array.from(this.connectionListeners);
|
|
1313
|
+
for (const listener of listeners) {
|
|
1314
|
+
try {
|
|
1315
|
+
listener(nextState);
|
|
1316
|
+
} catch (error) {
|
|
1317
|
+
if (!firstError) {
|
|
1318
|
+
firstError = error;
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
} finally {
|
|
1324
|
+
this.isNotifyingState = false;
|
|
1325
|
+
}
|
|
1326
|
+
if (firstError) {
|
|
1327
|
+
throw firstError;
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
mapConnectionState(state) {
|
|
1331
|
+
switch (state) {
|
|
1332
|
+
case "initialized":
|
|
1333
|
+
case "connecting":
|
|
1334
|
+
return "connecting";
|
|
1335
|
+
case "connected":
|
|
1336
|
+
return "connected";
|
|
1337
|
+
case "disconnected":
|
|
1338
|
+
return "disconnected";
|
|
1339
|
+
case "unavailable":
|
|
1340
|
+
return "unavailable";
|
|
1341
|
+
case "failed":
|
|
1342
|
+
return "failed";
|
|
1343
|
+
default:
|
|
1344
|
+
return "disconnected";
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
subscribe(name, type) {
|
|
1348
|
+
if (this.isDisconnected) {
|
|
1349
|
+
return new NoopRealtimeChannel();
|
|
1350
|
+
}
|
|
1351
|
+
const channelName = this.getChannelName(name, type);
|
|
1352
|
+
const existing = this.subscriptions.get(channelName);
|
|
1353
|
+
if (existing) {
|
|
1354
|
+
return this.createChannelWrapper(existing);
|
|
1355
|
+
}
|
|
1356
|
+
if (!this.pusher) {
|
|
1357
|
+
if (this.initializationPromise) {
|
|
1358
|
+
const subscription2 = this.createPendingSubscription(
|
|
1359
|
+
name,
|
|
1360
|
+
channelName,
|
|
1361
|
+
type
|
|
1362
|
+
);
|
|
1363
|
+
this.subscriptions.set(channelName, subscription2);
|
|
1364
|
+
return this.createChannelWrapper(subscription2);
|
|
1365
|
+
}
|
|
1366
|
+
return new NoopRealtimeChannel();
|
|
1367
|
+
}
|
|
1368
|
+
const channel = this.pusher.subscribe(channelName);
|
|
1369
|
+
const subscription = {
|
|
1370
|
+
name,
|
|
1371
|
+
channelName,
|
|
1372
|
+
type,
|
|
1373
|
+
channel,
|
|
1374
|
+
listeners: /* @__PURE__ */ new Map(),
|
|
1375
|
+
presence: {
|
|
1376
|
+
here: /* @__PURE__ */ new Set(),
|
|
1377
|
+
joining: /* @__PURE__ */ new Set(),
|
|
1378
|
+
leaving: /* @__PURE__ */ new Set()
|
|
1379
|
+
},
|
|
1380
|
+
presenceBindings: createPresenceBindings()
|
|
1381
|
+
};
|
|
1382
|
+
this.subscriptions.set(channelName, subscription);
|
|
1383
|
+
return this.createChannelWrapper(subscription);
|
|
1384
|
+
}
|
|
1385
|
+
/**
|
|
1386
|
+
* Create a placeholder channel while initialization is pending.
|
|
1387
|
+
*/
|
|
1388
|
+
createPendingChannel(type) {
|
|
1389
|
+
const channel = {
|
|
1390
|
+
bind: () => void 0,
|
|
1391
|
+
unbind: () => void 0,
|
|
1392
|
+
unbind_all: () => void 0
|
|
1393
|
+
};
|
|
1394
|
+
if (type === "presence") {
|
|
1395
|
+
return {
|
|
1396
|
+
...channel,
|
|
1397
|
+
members: void 0
|
|
1398
|
+
};
|
|
1399
|
+
}
|
|
1400
|
+
return channel;
|
|
1401
|
+
}
|
|
1402
|
+
/**
|
|
1403
|
+
* Create a subscription record before the Pusher client is ready.
|
|
1404
|
+
*/
|
|
1405
|
+
createPendingSubscription(name, channelName, type) {
|
|
1406
|
+
return {
|
|
1407
|
+
name,
|
|
1408
|
+
channelName,
|
|
1409
|
+
type,
|
|
1410
|
+
channel: this.createPendingChannel(type),
|
|
1411
|
+
listeners: /* @__PURE__ */ new Map(),
|
|
1412
|
+
presence: {
|
|
1413
|
+
here: /* @__PURE__ */ new Set(),
|
|
1414
|
+
joining: /* @__PURE__ */ new Set(),
|
|
1415
|
+
leaving: /* @__PURE__ */ new Set()
|
|
1416
|
+
},
|
|
1417
|
+
presenceBindings: createPresenceBindings(),
|
|
1418
|
+
pending: true
|
|
1419
|
+
};
|
|
1420
|
+
}
|
|
1421
|
+
/**
|
|
1422
|
+
* Bind non-presence event listeners to the current channel.
|
|
1423
|
+
* @param subscription - Target subscription record.
|
|
1424
|
+
*/
|
|
1425
|
+
bindListeners(subscription) {
|
|
1426
|
+
const channel = subscription.channel;
|
|
1427
|
+
for (const [event, callbacks] of subscription.listeners.entries()) {
|
|
1428
|
+
for (const callback of callbacks) {
|
|
1429
|
+
channel.bind(event, callback);
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
/**
|
|
1434
|
+
* Rebind presence callbacks to the current channel instance.
|
|
1435
|
+
* @param subscription - Target subscription record.
|
|
1436
|
+
* @param options - Optional rebinding configuration.
|
|
1437
|
+
* @param options.emitHere - When true, emit the current member list immediately.
|
|
1438
|
+
*/
|
|
1439
|
+
rebindPresenceCallbacks(subscription, options = {}) {
|
|
1440
|
+
if (subscription.type !== "presence") {
|
|
1441
|
+
return;
|
|
1442
|
+
}
|
|
1443
|
+
const emitHere = options.emitHere ?? true;
|
|
1444
|
+
subscription.presenceBindings = createPresenceBindings();
|
|
1445
|
+
for (const callback of subscription.presence.here) {
|
|
1446
|
+
this.bindPresenceListener(subscription, "here", callback);
|
|
1447
|
+
}
|
|
1448
|
+
for (const callback of subscription.presence.joining) {
|
|
1449
|
+
this.bindPresenceListener(subscription, "joining", callback);
|
|
1450
|
+
}
|
|
1451
|
+
for (const callback of subscription.presence.leaving) {
|
|
1452
|
+
this.bindPresenceListener(subscription, "leaving", callback);
|
|
1453
|
+
}
|
|
1454
|
+
const presenceChannel = subscription.channel;
|
|
1455
|
+
const members = normalizePresenceMembers(presenceChannel.members);
|
|
1456
|
+
if (emitHere && members.length) {
|
|
1457
|
+
for (const callback of subscription.presence.here) {
|
|
1458
|
+
callback(members);
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
/**
|
|
1463
|
+
* Bind a presence listener for the current subscription channel.
|
|
1464
|
+
*/
|
|
1465
|
+
bindPresenceListener(subscription, type, callback) {
|
|
1466
|
+
const presenceChannel = subscription.channel;
|
|
1467
|
+
if (type === "here") {
|
|
1468
|
+
const bindings2 = subscription.presenceBindings.here;
|
|
1469
|
+
const hereCallback = callback;
|
|
1470
|
+
if (bindings2.has(hereCallback)) {
|
|
1471
|
+
return;
|
|
1472
|
+
}
|
|
1473
|
+
const handler2 = (members) => hereCallback(normalizePresenceMembers(members));
|
|
1474
|
+
presenceChannel.bind("pusher:subscription_succeeded", handler2);
|
|
1475
|
+
bindings2.set(hereCallback, handler2);
|
|
1476
|
+
return;
|
|
1477
|
+
}
|
|
1478
|
+
if (type === "joining") {
|
|
1479
|
+
const bindings2 = subscription.presenceBindings.joining;
|
|
1480
|
+
const joiningCallback = callback;
|
|
1481
|
+
if (bindings2.has(joiningCallback)) {
|
|
1482
|
+
return;
|
|
1483
|
+
}
|
|
1484
|
+
const handler2 = (payload) => joiningCallback(payload);
|
|
1485
|
+
presenceChannel.bind("pusher:member_added", handler2);
|
|
1486
|
+
bindings2.set(joiningCallback, handler2);
|
|
1487
|
+
return;
|
|
1488
|
+
}
|
|
1489
|
+
const bindings = subscription.presenceBindings.leaving;
|
|
1490
|
+
const leavingCallback = callback;
|
|
1491
|
+
if (bindings.has(leavingCallback)) {
|
|
1492
|
+
return;
|
|
1493
|
+
}
|
|
1494
|
+
const handler = (payload) => leavingCallback(payload);
|
|
1495
|
+
presenceChannel.bind("pusher:member_removed", handler);
|
|
1496
|
+
bindings.set(leavingCallback, handler);
|
|
1497
|
+
}
|
|
1498
|
+
/**
|
|
1499
|
+
* Remove a presence listener for the current subscription channel.
|
|
1500
|
+
*/
|
|
1501
|
+
removePresenceListener(subscription, type, callback) {
|
|
1502
|
+
if (subscription.type !== "presence") {
|
|
1503
|
+
return;
|
|
1504
|
+
}
|
|
1505
|
+
const presenceChannel = subscription.channel;
|
|
1506
|
+
if (type === "here") {
|
|
1507
|
+
const hereCallback = callback;
|
|
1508
|
+
subscription.presence.here.delete(hereCallback);
|
|
1509
|
+
const bindings2 = subscription.presenceBindings.here;
|
|
1510
|
+
const handler2 = bindings2.get(hereCallback);
|
|
1511
|
+
if (handler2) {
|
|
1512
|
+
presenceChannel.unbind(
|
|
1513
|
+
"pusher:subscription_succeeded",
|
|
1514
|
+
handler2
|
|
1515
|
+
);
|
|
1516
|
+
bindings2.delete(hereCallback);
|
|
1517
|
+
}
|
|
1518
|
+
return;
|
|
1519
|
+
}
|
|
1520
|
+
if (type === "joining") {
|
|
1521
|
+
const joiningCallback = callback;
|
|
1522
|
+
subscription.presence.joining.delete(joiningCallback);
|
|
1523
|
+
const bindings2 = subscription.presenceBindings.joining;
|
|
1524
|
+
const handler2 = bindings2.get(joiningCallback);
|
|
1525
|
+
if (handler2) {
|
|
1526
|
+
presenceChannel.unbind(
|
|
1527
|
+
"pusher:member_added",
|
|
1528
|
+
handler2
|
|
1529
|
+
);
|
|
1530
|
+
bindings2.delete(joiningCallback);
|
|
1531
|
+
}
|
|
1532
|
+
return;
|
|
1533
|
+
}
|
|
1534
|
+
const leavingCallback = callback;
|
|
1535
|
+
subscription.presence.leaving.delete(leavingCallback);
|
|
1536
|
+
const bindings = subscription.presenceBindings.leaving;
|
|
1537
|
+
const handler = bindings.get(leavingCallback);
|
|
1538
|
+
if (handler) {
|
|
1539
|
+
presenceChannel.unbind(
|
|
1540
|
+
"pusher:member_removed",
|
|
1541
|
+
handler
|
|
1542
|
+
);
|
|
1543
|
+
bindings.delete(leavingCallback);
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
createChannelWrapper(subscription) {
|
|
1547
|
+
if (subscription.type === "presence") {
|
|
1548
|
+
return this.createPresenceChannelWrapper(subscription);
|
|
1549
|
+
}
|
|
1550
|
+
return this.createBaseChannelWrapper(subscription);
|
|
1551
|
+
}
|
|
1552
|
+
createBaseChannelWrapper(subscription) {
|
|
1553
|
+
return {
|
|
1554
|
+
listen: (event, callback) => {
|
|
1555
|
+
this.addListener(subscription, event, callback);
|
|
1556
|
+
},
|
|
1557
|
+
stopListening: (event, callback) => {
|
|
1558
|
+
this.removeListener(subscription, event, callback);
|
|
1559
|
+
}
|
|
1560
|
+
};
|
|
1561
|
+
}
|
|
1562
|
+
/**
|
|
1563
|
+
* Create a presence channel wrapper with unsubscribe support.
|
|
1564
|
+
*/
|
|
1565
|
+
createPresenceChannelWrapper(subscription) {
|
|
1566
|
+
const channel = this.createBaseChannelWrapper(subscription);
|
|
1567
|
+
return {
|
|
1568
|
+
...channel,
|
|
1569
|
+
here: (callback) => {
|
|
1570
|
+
subscription.presence.here.add(callback);
|
|
1571
|
+
this.bindPresenceListener(subscription, "here", callback);
|
|
1572
|
+
const presenceChannel = subscription.channel;
|
|
1573
|
+
const members = normalizePresenceMembers(presenceChannel.members);
|
|
1574
|
+
if (members.length) {
|
|
1575
|
+
callback(members);
|
|
1576
|
+
}
|
|
1577
|
+
return () => {
|
|
1578
|
+
this.removePresenceListener(subscription, "here", callback);
|
|
1579
|
+
};
|
|
1580
|
+
},
|
|
1581
|
+
joining: (callback) => {
|
|
1582
|
+
subscription.presence.joining.add(callback);
|
|
1583
|
+
this.bindPresenceListener(subscription, "joining", callback);
|
|
1584
|
+
return () => {
|
|
1585
|
+
this.removePresenceListener(subscription, "joining", callback);
|
|
1586
|
+
};
|
|
1587
|
+
},
|
|
1588
|
+
leaving: (callback) => {
|
|
1589
|
+
subscription.presence.leaving.add(callback);
|
|
1590
|
+
this.bindPresenceListener(subscription, "leaving", callback);
|
|
1591
|
+
return () => {
|
|
1592
|
+
this.removePresenceListener(subscription, "leaving", callback);
|
|
1593
|
+
};
|
|
1594
|
+
}
|
|
1595
|
+
};
|
|
1596
|
+
}
|
|
1597
|
+
/**
|
|
1598
|
+
* Refresh private and presence subscriptions after auth changes.
|
|
1599
|
+
*/
|
|
1600
|
+
refreshAuthSubscriptions() {
|
|
1601
|
+
if (!this.pusher) {
|
|
1602
|
+
return;
|
|
1603
|
+
}
|
|
1604
|
+
for (const subscription of this.subscriptions.values()) {
|
|
1605
|
+
if (subscription.type === "public") {
|
|
1606
|
+
continue;
|
|
1607
|
+
}
|
|
1608
|
+
this.pusher.unsubscribe(subscription.channelName);
|
|
1609
|
+
if (!this.token) {
|
|
1610
|
+
subscription.channel.unbind_all();
|
|
1611
|
+
subscription.channel = this.createPendingChannel(subscription.type);
|
|
1612
|
+
subscription.presenceBindings = createPresenceBindings();
|
|
1613
|
+
continue;
|
|
1614
|
+
}
|
|
1615
|
+
const channel = this.pusher.subscribe(
|
|
1616
|
+
subscription.channelName
|
|
1617
|
+
);
|
|
1618
|
+
subscription.channel = channel;
|
|
1619
|
+
this.bindListeners(subscription);
|
|
1620
|
+
this.rebindPresenceCallbacks(subscription);
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
/**
|
|
1624
|
+
* Register a listener for a realtime event.
|
|
1625
|
+
* @param subscription - Target subscription record.
|
|
1626
|
+
* @param event - Realtime event name (leading dot is optional).
|
|
1627
|
+
* @param callback - Event handler callback.
|
|
1628
|
+
*/
|
|
1629
|
+
addListener(subscription, event, callback) {
|
|
1630
|
+
const normalizedEvent = event.startsWith(".") ? event.slice(1) : event;
|
|
1631
|
+
let callbacks = subscription.listeners.get(normalizedEvent);
|
|
1632
|
+
if (!callbacks) {
|
|
1633
|
+
callbacks = /* @__PURE__ */ new Set();
|
|
1634
|
+
subscription.listeners.set(normalizedEvent, callbacks);
|
|
1635
|
+
}
|
|
1636
|
+
if (callbacks.has(callback)) {
|
|
1637
|
+
return;
|
|
1638
|
+
}
|
|
1639
|
+
callbacks.add(callback);
|
|
1640
|
+
subscription.channel.bind(
|
|
1641
|
+
normalizedEvent,
|
|
1642
|
+
callback
|
|
1643
|
+
);
|
|
1644
|
+
}
|
|
1645
|
+
/**
|
|
1646
|
+
* Remove listeners for a realtime event.
|
|
1647
|
+
* @param subscription - Target subscription record.
|
|
1648
|
+
* @param event - Realtime event name to stop listening for.
|
|
1649
|
+
* @param callback - Specific handler to remove if provided.
|
|
1650
|
+
*/
|
|
1651
|
+
removeListener(subscription, event, callback) {
|
|
1652
|
+
if (!event) {
|
|
1653
|
+
subscription.listeners.clear();
|
|
1654
|
+
subscription.channel.unbind_all();
|
|
1655
|
+
this.rebindPresenceCallbacks(subscription, { emitHere: false });
|
|
1656
|
+
return;
|
|
1657
|
+
}
|
|
1658
|
+
const normalizedEvent = event.startsWith(".") ? event.slice(1) : event;
|
|
1659
|
+
if (!subscription.listeners.has(normalizedEvent)) {
|
|
1660
|
+
return;
|
|
1661
|
+
}
|
|
1662
|
+
if (callback) {
|
|
1663
|
+
subscription.listeners.get(normalizedEvent)?.delete(callback);
|
|
1664
|
+
subscription.channel.unbind(
|
|
1665
|
+
normalizedEvent,
|
|
1666
|
+
callback
|
|
1667
|
+
);
|
|
1668
|
+
if (subscription.listeners.get(normalizedEvent)?.size === 0) {
|
|
1669
|
+
subscription.listeners.delete(normalizedEvent);
|
|
1670
|
+
}
|
|
1671
|
+
return;
|
|
1672
|
+
}
|
|
1673
|
+
subscription.listeners.delete(normalizedEvent);
|
|
1674
|
+
subscription.channel.unbind(normalizedEvent);
|
|
1675
|
+
}
|
|
1676
|
+
getChannelName(name, type) {
|
|
1677
|
+
switch (type) {
|
|
1678
|
+
case "private":
|
|
1679
|
+
return name.startsWith("private-") ? name : `private-${name}`;
|
|
1680
|
+
case "presence":
|
|
1681
|
+
return name.startsWith("presence-") ? name : `presence-${name}`;
|
|
1682
|
+
default:
|
|
1683
|
+
return name;
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
};
|
|
1687
|
+
var RealtimeNamespace = class {
|
|
1688
|
+
/**
|
|
1689
|
+
* Create a new realtime namespace client.
|
|
1690
|
+
* @param transport - Transport implementation for realtime operations.
|
|
1691
|
+
*/
|
|
1692
|
+
constructor(transport) {
|
|
1693
|
+
__publicField(this, "chat");
|
|
1694
|
+
__publicField(this, "transport");
|
|
1695
|
+
this.transport = transport;
|
|
1696
|
+
this.chat = this.createChatNamespace();
|
|
1697
|
+
}
|
|
1698
|
+
/**
|
|
1699
|
+
* Raw Pusher client instance for advanced usage.
|
|
1700
|
+
*/
|
|
1701
|
+
get pusher() {
|
|
1702
|
+
return this.transport.pusher;
|
|
1703
|
+
}
|
|
1704
|
+
/**
|
|
1705
|
+
* Subscribe to a public channel.
|
|
1706
|
+
*/
|
|
1707
|
+
channel(name) {
|
|
1708
|
+
return this.transport.channel(name);
|
|
1709
|
+
}
|
|
1710
|
+
/**
|
|
1711
|
+
* Subscribe to a private channel.
|
|
1712
|
+
*/
|
|
1713
|
+
"private"(name) {
|
|
1714
|
+
return this.transport.private(name);
|
|
1715
|
+
}
|
|
1716
|
+
/**
|
|
1717
|
+
* Subscribe to a presence channel.
|
|
1718
|
+
*/
|
|
1719
|
+
join(name) {
|
|
1720
|
+
return this.transport.join(name);
|
|
1721
|
+
}
|
|
1722
|
+
/**
|
|
1723
|
+
* Leave a channel.
|
|
1724
|
+
*/
|
|
1725
|
+
leave(name) {
|
|
1726
|
+
this.transport.leave(name);
|
|
1727
|
+
}
|
|
1728
|
+
/**
|
|
1729
|
+
* Disconnect the realtime client.
|
|
1730
|
+
*/
|
|
1731
|
+
disconnect() {
|
|
1732
|
+
this.transport.disconnect();
|
|
1733
|
+
}
|
|
1734
|
+
/**
|
|
1735
|
+
* Update the auth token for realtime subscriptions.
|
|
1736
|
+
*/
|
|
1737
|
+
setToken(token) {
|
|
1738
|
+
this.transport.setToken(token);
|
|
1739
|
+
}
|
|
1740
|
+
/**
|
|
1741
|
+
* Listen for connection state changes.
|
|
1742
|
+
*/
|
|
1743
|
+
onConnectionStateChange(callback) {
|
|
1744
|
+
return this.transport.onConnectionStateChange(callback);
|
|
1745
|
+
}
|
|
1746
|
+
/**
|
|
1747
|
+
* Create the chat realtime helpers.
|
|
1748
|
+
*/
|
|
1749
|
+
createChatNamespace() {
|
|
1750
|
+
return {
|
|
1751
|
+
joinRoom: (channelId) => {
|
|
1752
|
+
const channelName = this.toChatRoom(channelId);
|
|
1753
|
+
return this.join(channelName);
|
|
1754
|
+
},
|
|
1755
|
+
leaveRoom: (channelId) => {
|
|
1756
|
+
this.leave(this.toChatRoom(channelId));
|
|
1757
|
+
},
|
|
1758
|
+
onMessage: (channelId, callback) => this.attachChatListener(channelId, ".SendPublicChatMessage", callback),
|
|
1759
|
+
onMessageUpdated: (channelId, callback) => this.attachChatListener(channelId, ".chat.message.updated", callback),
|
|
1760
|
+
onMessageDeleted: (channelId, callback) => this.attachChatListener(channelId, ".chat.message.deleted", callback)
|
|
1761
|
+
};
|
|
1762
|
+
}
|
|
1763
|
+
/**
|
|
1764
|
+
* Attach a chat listener to the channel room.
|
|
1765
|
+
*/
|
|
1766
|
+
attachChatListener(channelId, event, callback) {
|
|
1767
|
+
const channel = this.join(this.toChatRoom(channelId));
|
|
1768
|
+
channel.listen(event, callback);
|
|
1769
|
+
return () => {
|
|
1770
|
+
channel.stopListening(event, callback);
|
|
1771
|
+
};
|
|
1772
|
+
}
|
|
1773
|
+
/**
|
|
1774
|
+
* Build the chat room name for a channel id.
|
|
1775
|
+
*/
|
|
1776
|
+
toChatRoom(channelId) {
|
|
1777
|
+
return `chat-public.${String(channelId)}`;
|
|
1778
|
+
}
|
|
1779
|
+
};
|
|
1780
|
+
var createRealtimeClient = (options) => {
|
|
1781
|
+
if (!options) {
|
|
1782
|
+
return new RealtimeNamespace(new NoopRealtimeTransport());
|
|
1783
|
+
}
|
|
1784
|
+
try {
|
|
1785
|
+
return new RealtimeNamespace(new PusherRealtimeTransport(options));
|
|
1786
|
+
} catch (error) {
|
|
1787
|
+
if (error instanceof SDKError) {
|
|
1788
|
+
throw error;
|
|
1789
|
+
}
|
|
1790
|
+
const message = error instanceof Error ? error.message : "Unknown realtime error";
|
|
1791
|
+
throw createSdkError(`Failed to initialize realtime client: ${message}`);
|
|
1792
|
+
}
|
|
1793
|
+
};
|
|
1794
|
+
|
|
1795
|
+
// src/streams.ts
|
|
1796
|
+
var StreamsClient = class {
|
|
1797
|
+
/**
|
|
1798
|
+
* Create a new streams client instance.
|
|
1799
|
+
*/
|
|
1800
|
+
constructor(http) {
|
|
1801
|
+
__publicField(this, "http");
|
|
1802
|
+
this.http = http;
|
|
1803
|
+
}
|
|
1804
|
+
/**
|
|
1805
|
+
* List active streams.
|
|
1806
|
+
*/
|
|
1807
|
+
async listActive(options = {}) {
|
|
1808
|
+
return this.list(void 0, options);
|
|
1809
|
+
}
|
|
1810
|
+
/**
|
|
1811
|
+
* List streams with optional query params.
|
|
1812
|
+
*/
|
|
1813
|
+
async list(params, options = {}) {
|
|
1814
|
+
const rest = { ...options, body: void 0 };
|
|
1815
|
+
const query = buildQueryString(params);
|
|
1816
|
+
const path = query ? `/v2/streams?${query}` : "/v2/streams";
|
|
1817
|
+
return this.http.request(path, {
|
|
1818
|
+
...rest,
|
|
1819
|
+
method: "GET"
|
|
1820
|
+
});
|
|
1821
|
+
}
|
|
1822
|
+
/**
|
|
1823
|
+
* Fetch a stream by id.
|
|
1824
|
+
*/
|
|
1825
|
+
async get(streamId, options = {}) {
|
|
1826
|
+
const rest = { ...options, body: void 0 };
|
|
1827
|
+
return this.http.request(
|
|
1828
|
+
`/v2/streams/${encodeURIComponent(String(streamId))}`,
|
|
1829
|
+
{
|
|
1830
|
+
...rest,
|
|
1831
|
+
method: "GET"
|
|
1832
|
+
}
|
|
1833
|
+
);
|
|
1834
|
+
}
|
|
1835
|
+
/**
|
|
1836
|
+
* Fetch a stream by channel slug.
|
|
1837
|
+
* @param userLogin - Channel slug or login handle.
|
|
1838
|
+
* @param options - Request options.
|
|
1839
|
+
* @returns Stream payload when found, otherwise null.
|
|
1840
|
+
*/
|
|
1841
|
+
async getBySlug(userLogin, options = {}) {
|
|
1842
|
+
const rest = { ...options, body: void 0 };
|
|
1843
|
+
try {
|
|
1844
|
+
const channelResponse = await this.http.request(
|
|
1845
|
+
`/v2/channels/${encodeURIComponent(userLogin)}`,
|
|
1846
|
+
{
|
|
1847
|
+
...rest,
|
|
1848
|
+
method: "GET"
|
|
1849
|
+
}
|
|
1850
|
+
);
|
|
1851
|
+
if (channelResponse?.active_stream) {
|
|
1852
|
+
return channelResponse.active_stream;
|
|
1853
|
+
}
|
|
1854
|
+
return null;
|
|
1855
|
+
} catch (error) {
|
|
1856
|
+
if (error instanceof SDKError) {
|
|
1857
|
+
if (error.statusCode === 404) {
|
|
1858
|
+
return null;
|
|
1859
|
+
}
|
|
1860
|
+
throw error;
|
|
1861
|
+
}
|
|
1862
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1863
|
+
throw createSdkError(message);
|
|
1864
|
+
}
|
|
1865
|
+
}
|
|
1866
|
+
/**
|
|
1867
|
+
* Fetch the player source payload for the given stream id.
|
|
1868
|
+
*/
|
|
1869
|
+
async getPlayerSource(streamId, options = {}) {
|
|
1870
|
+
const response = await this.get(streamId, options);
|
|
1871
|
+
const stream = this.extractStreamPayload(response);
|
|
1872
|
+
return stream?.player_source ?? null;
|
|
1873
|
+
}
|
|
1874
|
+
/**
|
|
1875
|
+
* Normalize stream payloads for get operations.
|
|
1876
|
+
*/
|
|
1877
|
+
extractStreamPayload(response) {
|
|
1878
|
+
if (response && typeof response === "object") {
|
|
1879
|
+
if ("data" in response) {
|
|
1880
|
+
return response.data ?? null;
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
return response ?? null;
|
|
1884
|
+
}
|
|
1885
|
+
};
|
|
1886
|
+
|
|
1887
|
+
// src/base-client.ts
|
|
1888
|
+
var BaseSdkClient = class {
|
|
1889
|
+
/**
|
|
1890
|
+
* Create a new SDK client base instance.
|
|
1891
|
+
*/
|
|
1892
|
+
constructor(baseUrl, options) {
|
|
1893
|
+
/**
|
|
1894
|
+
* Auth client instance.
|
|
1895
|
+
*/
|
|
1896
|
+
__publicField(this, "auth");
|
|
1897
|
+
/**
|
|
1898
|
+
* HTTP client instance.
|
|
1899
|
+
*/
|
|
1900
|
+
__publicField(this, "http");
|
|
1901
|
+
/**
|
|
1902
|
+
* Realtime client instance.
|
|
1903
|
+
*/
|
|
1904
|
+
__publicField(this, "realtime");
|
|
1905
|
+
/**
|
|
1906
|
+
* Streams namespace client.
|
|
1907
|
+
*/
|
|
1908
|
+
__publicField(this, "streams");
|
|
1909
|
+
/**
|
|
1910
|
+
* Channels namespace client.
|
|
1911
|
+
*/
|
|
1912
|
+
__publicField(this, "channels");
|
|
1913
|
+
/**
|
|
1914
|
+
* Chat namespace client.
|
|
1915
|
+
*/
|
|
1916
|
+
__publicField(this, "chat");
|
|
1917
|
+
const authOptions = options.auth ?? {};
|
|
1918
|
+
const serviceKey = options.serviceKey === void 0 ? authOptions.serviceKey ?? null : options.serviceKey;
|
|
1919
|
+
const http = new HttpClient({
|
|
1920
|
+
baseUrl,
|
|
1921
|
+
headers: options.headers,
|
|
1922
|
+
fetch: options.fetch
|
|
1923
|
+
});
|
|
1924
|
+
const auth = new AuthClient(http, {
|
|
1925
|
+
...authOptions,
|
|
1926
|
+
storage: options.storage,
|
|
1927
|
+
serviceKey
|
|
1928
|
+
});
|
|
1929
|
+
const realtime = createRealtimeClient(
|
|
1930
|
+
options.realtime ? {
|
|
1931
|
+
...options.realtime,
|
|
1932
|
+
baseUrl,
|
|
1933
|
+
getToken: async () => auth.getSession()
|
|
1934
|
+
} : void 0
|
|
1935
|
+
);
|
|
1936
|
+
auth.onAuthStateChange((event, token) => {
|
|
1937
|
+
if (event === "SIGNED_OUT") {
|
|
1938
|
+
realtime.setToken(null);
|
|
1939
|
+
return;
|
|
1940
|
+
}
|
|
1941
|
+
realtime.setToken(token);
|
|
1942
|
+
});
|
|
1943
|
+
this.http = http;
|
|
1944
|
+
this.auth = auth;
|
|
1945
|
+
this.realtime = realtime;
|
|
1946
|
+
this.streams = new StreamsClient(http);
|
|
1947
|
+
this.channels = new ChannelsClient(http);
|
|
1948
|
+
this.chat = new ChatClient(http);
|
|
1949
|
+
}
|
|
1950
|
+
};
|
|
1951
|
+
|
|
1952
|
+
// src/browser-client.ts
|
|
1953
|
+
var BrowserClient = class extends BaseSdkClient {
|
|
1954
|
+
/**
|
|
1955
|
+
* Create a browser client instance.
|
|
1956
|
+
*/
|
|
1957
|
+
constructor(baseUrl, keyOverride, options = {}) {
|
|
1958
|
+
const authOptions = options.auth ?? {};
|
|
1959
|
+
const serviceKey = keyOverride === void 0 ? authOptions.serviceKey ?? null : keyOverride;
|
|
1960
|
+
const storage = authOptions.storage ?? createDefaultStorageAdapter({
|
|
1961
|
+
cookiePrefix: authOptions.cookiePrefix,
|
|
1962
|
+
cookieOptions: authOptions.cookieOptions,
|
|
1963
|
+
cookies: authOptions.cookies
|
|
1964
|
+
});
|
|
1965
|
+
super(baseUrl, {
|
|
1966
|
+
auth: authOptions,
|
|
1967
|
+
headers: options.headers,
|
|
1968
|
+
fetch: options.fetch,
|
|
1969
|
+
realtime: options.realtime,
|
|
1970
|
+
storage,
|
|
1971
|
+
serviceKey
|
|
1972
|
+
});
|
|
1973
|
+
}
|
|
1974
|
+
};
|
|
1975
|
+
var createBrowserClient = (baseUrl, keyOverride, options = {}) => new BrowserClient(baseUrl, keyOverride, options);
|
|
1976
|
+
var createClient = (baseUrl, keyOverride, options = {}) => createBrowserClient(baseUrl, keyOverride, options);
|
|
1977
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1978
|
+
0 && (module.exports = {
|
|
1979
|
+
BrowserClient,
|
|
1980
|
+
createBrowserClient,
|
|
1981
|
+
createClient
|
|
1982
|
+
});
|
|
1983
|
+
//# sourceMappingURL=browser-client.js.map
|