@wvdsh/sdk-js 1.2.3 → 1.3.0
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/client.d.ts +15 -0
- package/dist/client.js +11 -0
- package/dist/index.d.ts +152 -42
- package/dist/index.js +111 -4235
- package/package.json +15 -6
package/dist/index.js
CHANGED
|
@@ -1,4189 +1,43 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __commonJS = (cb, mod) => function __require() {
|
|
8
|
-
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
9
|
-
};
|
|
10
|
-
var __export = (target, all) => {
|
|
11
|
-
for (var name in all)
|
|
12
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
13
|
-
};
|
|
14
|
-
var __copyProps = (to, from, except, desc) => {
|
|
15
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
16
|
-
for (let key of __getOwnPropNames(from))
|
|
17
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
18
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
19
|
-
}
|
|
20
|
-
return to;
|
|
21
|
-
};
|
|
22
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
23
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
24
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
25
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
26
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
27
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
28
|
-
mod
|
|
29
|
-
));
|
|
30
|
-
|
|
31
|
-
// node_modules/lodash.debounce/index.js
|
|
32
|
-
var require_lodash = __commonJS({
|
|
33
|
-
"node_modules/lodash.debounce/index.js"(exports, module) {
|
|
34
|
-
"use strict";
|
|
35
|
-
var FUNC_ERROR_TEXT = "Expected a function";
|
|
36
|
-
var NAN = 0 / 0;
|
|
37
|
-
var symbolTag = "[object Symbol]";
|
|
38
|
-
var reTrim = /^\s+|\s+$/g;
|
|
39
|
-
var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
|
|
40
|
-
var reIsBinary = /^0b[01]+$/i;
|
|
41
|
-
var reIsOctal = /^0o[0-7]+$/i;
|
|
42
|
-
var freeParseInt = parseInt;
|
|
43
|
-
var freeGlobal = typeof global == "object" && global && global.Object === Object && global;
|
|
44
|
-
var freeSelf = typeof self == "object" && self && self.Object === Object && self;
|
|
45
|
-
var root = freeGlobal || freeSelf || Function("return this")();
|
|
46
|
-
var objectProto = Object.prototype;
|
|
47
|
-
var objectToString = objectProto.toString;
|
|
48
|
-
var nativeMax = Math.max;
|
|
49
|
-
var nativeMin = Math.min;
|
|
50
|
-
var now = function() {
|
|
51
|
-
return root.Date.now();
|
|
52
|
-
};
|
|
53
|
-
function debounce3(func, wait, options) {
|
|
54
|
-
var lastArgs, lastThis, maxWait, result, timerId, lastCallTime, lastInvokeTime = 0, leading = false, maxing = false, trailing = true;
|
|
55
|
-
if (typeof func != "function") {
|
|
56
|
-
throw new TypeError(FUNC_ERROR_TEXT);
|
|
57
|
-
}
|
|
58
|
-
wait = toNumber(wait) || 0;
|
|
59
|
-
if (isObject(options)) {
|
|
60
|
-
leading = !!options.leading;
|
|
61
|
-
maxing = "maxWait" in options;
|
|
62
|
-
maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;
|
|
63
|
-
trailing = "trailing" in options ? !!options.trailing : trailing;
|
|
64
|
-
}
|
|
65
|
-
function invokeFunc(time) {
|
|
66
|
-
var args = lastArgs, thisArg = lastThis;
|
|
67
|
-
lastArgs = lastThis = void 0;
|
|
68
|
-
lastInvokeTime = time;
|
|
69
|
-
result = func.apply(thisArg, args);
|
|
70
|
-
return result;
|
|
71
|
-
}
|
|
72
|
-
function leadingEdge(time) {
|
|
73
|
-
lastInvokeTime = time;
|
|
74
|
-
timerId = setTimeout(timerExpired, wait);
|
|
75
|
-
return leading ? invokeFunc(time) : result;
|
|
76
|
-
}
|
|
77
|
-
function remainingWait(time) {
|
|
78
|
-
var timeSinceLastCall = time - lastCallTime, timeSinceLastInvoke = time - lastInvokeTime, result2 = wait - timeSinceLastCall;
|
|
79
|
-
return maxing ? nativeMin(result2, maxWait - timeSinceLastInvoke) : result2;
|
|
80
|
-
}
|
|
81
|
-
function shouldInvoke(time) {
|
|
82
|
-
var timeSinceLastCall = time - lastCallTime, timeSinceLastInvoke = time - lastInvokeTime;
|
|
83
|
-
return lastCallTime === void 0 || timeSinceLastCall >= wait || timeSinceLastCall < 0 || maxing && timeSinceLastInvoke >= maxWait;
|
|
84
|
-
}
|
|
85
|
-
function timerExpired() {
|
|
86
|
-
var time = now();
|
|
87
|
-
if (shouldInvoke(time)) {
|
|
88
|
-
return trailingEdge(time);
|
|
89
|
-
}
|
|
90
|
-
timerId = setTimeout(timerExpired, remainingWait(time));
|
|
91
|
-
}
|
|
92
|
-
function trailingEdge(time) {
|
|
93
|
-
timerId = void 0;
|
|
94
|
-
if (trailing && lastArgs) {
|
|
95
|
-
return invokeFunc(time);
|
|
96
|
-
}
|
|
97
|
-
lastArgs = lastThis = void 0;
|
|
98
|
-
return result;
|
|
99
|
-
}
|
|
100
|
-
function cancel() {
|
|
101
|
-
if (timerId !== void 0) {
|
|
102
|
-
clearTimeout(timerId);
|
|
103
|
-
}
|
|
104
|
-
lastInvokeTime = 0;
|
|
105
|
-
lastArgs = lastCallTime = lastThis = timerId = void 0;
|
|
106
|
-
}
|
|
107
|
-
function flush() {
|
|
108
|
-
return timerId === void 0 ? result : trailingEdge(now());
|
|
109
|
-
}
|
|
110
|
-
function debounced() {
|
|
111
|
-
var time = now(), isInvoking = shouldInvoke(time);
|
|
112
|
-
lastArgs = arguments;
|
|
113
|
-
lastThis = this;
|
|
114
|
-
lastCallTime = time;
|
|
115
|
-
if (isInvoking) {
|
|
116
|
-
if (timerId === void 0) {
|
|
117
|
-
return leadingEdge(lastCallTime);
|
|
118
|
-
}
|
|
119
|
-
if (maxing) {
|
|
120
|
-
timerId = setTimeout(timerExpired, wait);
|
|
121
|
-
return invokeFunc(lastCallTime);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
if (timerId === void 0) {
|
|
125
|
-
timerId = setTimeout(timerExpired, wait);
|
|
126
|
-
}
|
|
127
|
-
return result;
|
|
128
|
-
}
|
|
129
|
-
debounced.cancel = cancel;
|
|
130
|
-
debounced.flush = flush;
|
|
131
|
-
return debounced;
|
|
132
|
-
}
|
|
133
|
-
function isObject(value) {
|
|
134
|
-
var type = typeof value;
|
|
135
|
-
return !!value && (type == "object" || type == "function");
|
|
136
|
-
}
|
|
137
|
-
function isObjectLike(value) {
|
|
138
|
-
return !!value && typeof value == "object";
|
|
139
|
-
}
|
|
140
|
-
function isSymbol(value) {
|
|
141
|
-
return typeof value == "symbol" || isObjectLike(value) && objectToString.call(value) == symbolTag;
|
|
142
|
-
}
|
|
143
|
-
function toNumber(value) {
|
|
144
|
-
if (typeof value == "number") {
|
|
145
|
-
return value;
|
|
146
|
-
}
|
|
147
|
-
if (isSymbol(value)) {
|
|
148
|
-
return NAN;
|
|
149
|
-
}
|
|
150
|
-
if (isObject(value)) {
|
|
151
|
-
var other = typeof value.valueOf == "function" ? value.valueOf() : value;
|
|
152
|
-
value = isObject(other) ? other + "" : other;
|
|
153
|
-
}
|
|
154
|
-
if (typeof value != "string") {
|
|
155
|
-
return value === 0 ? value : +value;
|
|
156
|
-
}
|
|
157
|
-
value = value.replace(reTrim, "");
|
|
158
|
-
var isBinary = reIsBinary.test(value);
|
|
159
|
-
return isBinary || reIsOctal.test(value) ? freeParseInt(value.slice(2), isBinary ? 2 : 8) : reIsBadHex.test(value) ? NAN : +value;
|
|
160
|
-
}
|
|
161
|
-
module.exports = debounce3;
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
// node_modules/convex/dist/esm/index.js
|
|
166
|
-
var version = "1.30.0";
|
|
167
|
-
|
|
168
|
-
// node_modules/convex/dist/esm/values/base64.js
|
|
169
|
-
var base64_exports = {};
|
|
170
|
-
__export(base64_exports, {
|
|
171
|
-
byteLength: () => byteLength,
|
|
172
|
-
fromByteArray: () => fromByteArray,
|
|
173
|
-
fromByteArrayUrlSafeNoPadding: () => fromByteArrayUrlSafeNoPadding,
|
|
174
|
-
toByteArray: () => toByteArray
|
|
175
|
-
});
|
|
176
|
-
var lookup = [];
|
|
177
|
-
var revLookup = [];
|
|
178
|
-
var Arr = Uint8Array;
|
|
179
|
-
var code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
180
|
-
for (i = 0, len = code.length; i < len; ++i) {
|
|
181
|
-
lookup[i] = code[i];
|
|
182
|
-
revLookup[code.charCodeAt(i)] = i;
|
|
183
|
-
}
|
|
184
|
-
var i;
|
|
185
|
-
var len;
|
|
186
|
-
revLookup["-".charCodeAt(0)] = 62;
|
|
187
|
-
revLookup["_".charCodeAt(0)] = 63;
|
|
188
|
-
function getLens(b64) {
|
|
189
|
-
var len = b64.length;
|
|
190
|
-
if (len % 4 > 0) {
|
|
191
|
-
throw new Error("Invalid string. Length must be a multiple of 4");
|
|
192
|
-
}
|
|
193
|
-
var validLen = b64.indexOf("=");
|
|
194
|
-
if (validLen === -1) validLen = len;
|
|
195
|
-
var placeHoldersLen = validLen === len ? 0 : 4 - validLen % 4;
|
|
196
|
-
return [validLen, placeHoldersLen];
|
|
197
|
-
}
|
|
198
|
-
function byteLength(b64) {
|
|
199
|
-
var lens = getLens(b64);
|
|
200
|
-
var validLen = lens[0];
|
|
201
|
-
var placeHoldersLen = lens[1];
|
|
202
|
-
return (validLen + placeHoldersLen) * 3 / 4 - placeHoldersLen;
|
|
203
|
-
}
|
|
204
|
-
function _byteLength(_b64, validLen, placeHoldersLen) {
|
|
205
|
-
return (validLen + placeHoldersLen) * 3 / 4 - placeHoldersLen;
|
|
206
|
-
}
|
|
207
|
-
function toByteArray(b64) {
|
|
208
|
-
var tmp;
|
|
209
|
-
var lens = getLens(b64);
|
|
210
|
-
var validLen = lens[0];
|
|
211
|
-
var placeHoldersLen = lens[1];
|
|
212
|
-
var arr2 = new Arr(_byteLength(b64, validLen, placeHoldersLen));
|
|
213
|
-
var curByte = 0;
|
|
214
|
-
var len = placeHoldersLen > 0 ? validLen - 4 : validLen;
|
|
215
|
-
var i;
|
|
216
|
-
for (i = 0; i < len; i += 4) {
|
|
217
|
-
tmp = revLookup[b64.charCodeAt(i)] << 18 | revLookup[b64.charCodeAt(i + 1)] << 12 | revLookup[b64.charCodeAt(i + 2)] << 6 | revLookup[b64.charCodeAt(i + 3)];
|
|
218
|
-
arr2[curByte++] = tmp >> 16 & 255;
|
|
219
|
-
arr2[curByte++] = tmp >> 8 & 255;
|
|
220
|
-
arr2[curByte++] = tmp & 255;
|
|
221
|
-
}
|
|
222
|
-
if (placeHoldersLen === 2) {
|
|
223
|
-
tmp = revLookup[b64.charCodeAt(i)] << 2 | revLookup[b64.charCodeAt(i + 1)] >> 4;
|
|
224
|
-
arr2[curByte++] = tmp & 255;
|
|
225
|
-
}
|
|
226
|
-
if (placeHoldersLen === 1) {
|
|
227
|
-
tmp = revLookup[b64.charCodeAt(i)] << 10 | revLookup[b64.charCodeAt(i + 1)] << 4 | revLookup[b64.charCodeAt(i + 2)] >> 2;
|
|
228
|
-
arr2[curByte++] = tmp >> 8 & 255;
|
|
229
|
-
arr2[curByte++] = tmp & 255;
|
|
230
|
-
}
|
|
231
|
-
return arr2;
|
|
232
|
-
}
|
|
233
|
-
function tripletToBase64(num) {
|
|
234
|
-
return lookup[num >> 18 & 63] + lookup[num >> 12 & 63] + lookup[num >> 6 & 63] + lookup[num & 63];
|
|
235
|
-
}
|
|
236
|
-
function encodeChunk(uint8, start, end) {
|
|
237
|
-
var tmp;
|
|
238
|
-
var output = [];
|
|
239
|
-
for (var i = start; i < end; i += 3) {
|
|
240
|
-
tmp = (uint8[i] << 16 & 16711680) + (uint8[i + 1] << 8 & 65280) + (uint8[i + 2] & 255);
|
|
241
|
-
output.push(tripletToBase64(tmp));
|
|
242
|
-
}
|
|
243
|
-
return output.join("");
|
|
244
|
-
}
|
|
245
|
-
function fromByteArray(uint8) {
|
|
246
|
-
var tmp;
|
|
247
|
-
var len = uint8.length;
|
|
248
|
-
var extraBytes = len % 3;
|
|
249
|
-
var parts = [];
|
|
250
|
-
var maxChunkLength = 16383;
|
|
251
|
-
for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
|
|
252
|
-
parts.push(
|
|
253
|
-
encodeChunk(
|
|
254
|
-
uint8,
|
|
255
|
-
i,
|
|
256
|
-
i + maxChunkLength > len2 ? len2 : i + maxChunkLength
|
|
257
|
-
)
|
|
258
|
-
);
|
|
259
|
-
}
|
|
260
|
-
if (extraBytes === 1) {
|
|
261
|
-
tmp = uint8[len - 1];
|
|
262
|
-
parts.push(lookup[tmp >> 2] + lookup[tmp << 4 & 63] + "==");
|
|
263
|
-
} else if (extraBytes === 2) {
|
|
264
|
-
tmp = (uint8[len - 2] << 8) + uint8[len - 1];
|
|
265
|
-
parts.push(
|
|
266
|
-
lookup[tmp >> 10] + lookup[tmp >> 4 & 63] + lookup[tmp << 2 & 63] + "="
|
|
267
|
-
);
|
|
268
|
-
}
|
|
269
|
-
return parts.join("");
|
|
270
|
-
}
|
|
271
|
-
function fromByteArrayUrlSafeNoPadding(uint8) {
|
|
272
|
-
return fromByteArray(uint8).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
// node_modules/convex/dist/esm/common/index.js
|
|
276
|
-
function parseArgs(args) {
|
|
277
|
-
if (args === void 0) {
|
|
278
|
-
return {};
|
|
279
|
-
}
|
|
280
|
-
if (!isSimpleObject(args)) {
|
|
281
|
-
throw new Error(
|
|
282
|
-
`The arguments to a Convex function must be an object. Received: ${args}`
|
|
283
|
-
);
|
|
284
|
-
}
|
|
285
|
-
return args;
|
|
286
|
-
}
|
|
287
|
-
function validateDeploymentUrl(deploymentUrl) {
|
|
288
|
-
if (typeof deploymentUrl === "undefined") {
|
|
289
|
-
throw new Error(
|
|
290
|
-
`Client created with undefined deployment address. If you used an environment variable, check that it's set.`
|
|
291
|
-
);
|
|
292
|
-
}
|
|
293
|
-
if (typeof deploymentUrl !== "string") {
|
|
294
|
-
throw new Error(
|
|
295
|
-
`Invalid deployment address: found ${deploymentUrl}".`
|
|
296
|
-
);
|
|
297
|
-
}
|
|
298
|
-
if (!(deploymentUrl.startsWith("http:") || deploymentUrl.startsWith("https:"))) {
|
|
299
|
-
throw new Error(
|
|
300
|
-
`Invalid deployment address: Must start with "https://" or "http://". Found "${deploymentUrl}".`
|
|
301
|
-
);
|
|
302
|
-
}
|
|
303
|
-
try {
|
|
304
|
-
new URL(deploymentUrl);
|
|
305
|
-
} catch {
|
|
306
|
-
throw new Error(
|
|
307
|
-
`Invalid deployment address: "${deploymentUrl}" is not a valid URL. If you believe this URL is correct, use the \`skipConvexDeploymentUrlCheck\` option to bypass this.`
|
|
308
|
-
);
|
|
309
|
-
}
|
|
310
|
-
if (deploymentUrl.endsWith(".convex.site")) {
|
|
311
|
-
throw new Error(
|
|
312
|
-
`Invalid deployment address: "${deploymentUrl}" ends with .convex.site, which is used for HTTP Actions. Convex deployment URLs typically end with .convex.cloud? If you believe this URL is correct, use the \`skipConvexDeploymentUrlCheck\` option to bypass this.`
|
|
313
|
-
);
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
function isSimpleObject(value) {
|
|
317
|
-
const isObject = typeof value === "object";
|
|
318
|
-
const prototype = Object.getPrototypeOf(value);
|
|
319
|
-
const isSimple = prototype === null || prototype === Object.prototype || // Objects generated from other contexts (e.g. across Node.js `vm` modules) will not satisfy the previous
|
|
320
|
-
// conditions but are still simple objects.
|
|
321
|
-
prototype?.constructor?.name === "Object";
|
|
322
|
-
return isObject && isSimple;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
// node_modules/convex/dist/esm/values/value.js
|
|
326
|
-
var LITTLE_ENDIAN = true;
|
|
327
|
-
var MIN_INT64 = BigInt("-9223372036854775808");
|
|
328
|
-
var MAX_INT64 = BigInt("9223372036854775807");
|
|
329
|
-
var ZERO = BigInt("0");
|
|
330
|
-
var EIGHT = BigInt("8");
|
|
331
|
-
var TWOFIFTYSIX = BigInt("256");
|
|
332
|
-
function isSpecial(n) {
|
|
333
|
-
return Number.isNaN(n) || !Number.isFinite(n) || Object.is(n, -0);
|
|
334
|
-
}
|
|
335
|
-
function slowBigIntToBase64(value) {
|
|
336
|
-
if (value < ZERO) {
|
|
337
|
-
value -= MIN_INT64 + MIN_INT64;
|
|
338
|
-
}
|
|
339
|
-
let hex = value.toString(16);
|
|
340
|
-
if (hex.length % 2 === 1) hex = "0" + hex;
|
|
341
|
-
const bytes = new Uint8Array(new ArrayBuffer(8));
|
|
342
|
-
let i = 0;
|
|
343
|
-
for (const hexByte of hex.match(/.{2}/g).reverse()) {
|
|
344
|
-
bytes.set([parseInt(hexByte, 16)], i++);
|
|
345
|
-
value >>= EIGHT;
|
|
346
|
-
}
|
|
347
|
-
return fromByteArray(bytes);
|
|
348
|
-
}
|
|
349
|
-
function slowBase64ToBigInt(encoded) {
|
|
350
|
-
const integerBytes = toByteArray(encoded);
|
|
351
|
-
if (integerBytes.byteLength !== 8) {
|
|
352
|
-
throw new Error(
|
|
353
|
-
`Received ${integerBytes.byteLength} bytes, expected 8 for $integer`
|
|
354
|
-
);
|
|
355
|
-
}
|
|
356
|
-
let value = ZERO;
|
|
357
|
-
let power = ZERO;
|
|
358
|
-
for (const byte of integerBytes) {
|
|
359
|
-
value += BigInt(byte) * TWOFIFTYSIX ** power;
|
|
360
|
-
power++;
|
|
361
|
-
}
|
|
362
|
-
if (value > MAX_INT64) {
|
|
363
|
-
value += MIN_INT64 + MIN_INT64;
|
|
364
|
-
}
|
|
365
|
-
return value;
|
|
366
|
-
}
|
|
367
|
-
function modernBigIntToBase64(value) {
|
|
368
|
-
if (value < MIN_INT64 || MAX_INT64 < value) {
|
|
369
|
-
throw new Error(
|
|
370
|
-
`BigInt ${value} does not fit into a 64-bit signed integer.`
|
|
371
|
-
);
|
|
372
|
-
}
|
|
373
|
-
const buffer = new ArrayBuffer(8);
|
|
374
|
-
new DataView(buffer).setBigInt64(0, value, true);
|
|
375
|
-
return fromByteArray(new Uint8Array(buffer));
|
|
376
|
-
}
|
|
377
|
-
function modernBase64ToBigInt(encoded) {
|
|
378
|
-
const integerBytes = toByteArray(encoded);
|
|
379
|
-
if (integerBytes.byteLength !== 8) {
|
|
380
|
-
throw new Error(
|
|
381
|
-
`Received ${integerBytes.byteLength} bytes, expected 8 for $integer`
|
|
382
|
-
);
|
|
383
|
-
}
|
|
384
|
-
const intBytesView = new DataView(integerBytes.buffer);
|
|
385
|
-
return intBytesView.getBigInt64(0, true);
|
|
386
|
-
}
|
|
387
|
-
var bigIntToBase64 = DataView.prototype.setBigInt64 ? modernBigIntToBase64 : slowBigIntToBase64;
|
|
388
|
-
var base64ToBigInt = DataView.prototype.getBigInt64 ? modernBase64ToBigInt : slowBase64ToBigInt;
|
|
389
|
-
var MAX_IDENTIFIER_LEN = 1024;
|
|
390
|
-
function validateObjectField(k) {
|
|
391
|
-
if (k.length > MAX_IDENTIFIER_LEN) {
|
|
392
|
-
throw new Error(
|
|
393
|
-
`Field name ${k} exceeds maximum field name length ${MAX_IDENTIFIER_LEN}.`
|
|
394
|
-
);
|
|
395
|
-
}
|
|
396
|
-
if (k.startsWith("$")) {
|
|
397
|
-
throw new Error(`Field name ${k} starts with a '$', which is reserved.`);
|
|
398
|
-
}
|
|
399
|
-
for (let i = 0; i < k.length; i += 1) {
|
|
400
|
-
const charCode = k.charCodeAt(i);
|
|
401
|
-
if (charCode < 32 || charCode >= 127) {
|
|
402
|
-
throw new Error(
|
|
403
|
-
`Field name ${k} has invalid character '${k[i]}': Field names can only contain non-control ASCII characters`
|
|
404
|
-
);
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
function jsonToConvex(value) {
|
|
409
|
-
if (value === null) {
|
|
410
|
-
return value;
|
|
411
|
-
}
|
|
412
|
-
if (typeof value === "boolean") {
|
|
413
|
-
return value;
|
|
414
|
-
}
|
|
415
|
-
if (typeof value === "number") {
|
|
416
|
-
return value;
|
|
417
|
-
}
|
|
418
|
-
if (typeof value === "string") {
|
|
419
|
-
return value;
|
|
420
|
-
}
|
|
421
|
-
if (Array.isArray(value)) {
|
|
422
|
-
return value.map((value2) => jsonToConvex(value2));
|
|
423
|
-
}
|
|
424
|
-
if (typeof value !== "object") {
|
|
425
|
-
throw new Error(`Unexpected type of ${value}`);
|
|
426
|
-
}
|
|
427
|
-
const entries = Object.entries(value);
|
|
428
|
-
if (entries.length === 1) {
|
|
429
|
-
const key = entries[0][0];
|
|
430
|
-
if (key === "$bytes") {
|
|
431
|
-
if (typeof value.$bytes !== "string") {
|
|
432
|
-
throw new Error(`Malformed $bytes field on ${value}`);
|
|
433
|
-
}
|
|
434
|
-
return toByteArray(value.$bytes).buffer;
|
|
435
|
-
}
|
|
436
|
-
if (key === "$integer") {
|
|
437
|
-
if (typeof value.$integer !== "string") {
|
|
438
|
-
throw new Error(`Malformed $integer field on ${value}`);
|
|
439
|
-
}
|
|
440
|
-
return base64ToBigInt(value.$integer);
|
|
441
|
-
}
|
|
442
|
-
if (key === "$float") {
|
|
443
|
-
if (typeof value.$float !== "string") {
|
|
444
|
-
throw new Error(`Malformed $float field on ${value}`);
|
|
445
|
-
}
|
|
446
|
-
const floatBytes = toByteArray(value.$float);
|
|
447
|
-
if (floatBytes.byteLength !== 8) {
|
|
448
|
-
throw new Error(
|
|
449
|
-
`Received ${floatBytes.byteLength} bytes, expected 8 for $float`
|
|
450
|
-
);
|
|
451
|
-
}
|
|
452
|
-
const floatBytesView = new DataView(floatBytes.buffer);
|
|
453
|
-
const float = floatBytesView.getFloat64(0, LITTLE_ENDIAN);
|
|
454
|
-
if (!isSpecial(float)) {
|
|
455
|
-
throw new Error(`Float ${float} should be encoded as a number`);
|
|
456
|
-
}
|
|
457
|
-
return float;
|
|
458
|
-
}
|
|
459
|
-
if (key === "$set") {
|
|
460
|
-
throw new Error(
|
|
461
|
-
`Received a Set which is no longer supported as a Convex type.`
|
|
462
|
-
);
|
|
463
|
-
}
|
|
464
|
-
if (key === "$map") {
|
|
465
|
-
throw new Error(
|
|
466
|
-
`Received a Map which is no longer supported as a Convex type.`
|
|
467
|
-
);
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
const out = {};
|
|
471
|
-
for (const [k, v2] of Object.entries(value)) {
|
|
472
|
-
validateObjectField(k);
|
|
473
|
-
out[k] = jsonToConvex(v2);
|
|
474
|
-
}
|
|
475
|
-
return out;
|
|
476
|
-
}
|
|
477
|
-
var MAX_VALUE_FOR_ERROR_LEN = 16384;
|
|
478
|
-
function stringifyValueForError(value) {
|
|
479
|
-
const str = JSON.stringify(value, (_key, value2) => {
|
|
480
|
-
if (value2 === void 0) {
|
|
481
|
-
return "undefined";
|
|
482
|
-
}
|
|
483
|
-
if (typeof value2 === "bigint") {
|
|
484
|
-
return `${value2.toString()}n`;
|
|
485
|
-
}
|
|
486
|
-
return value2;
|
|
487
|
-
});
|
|
488
|
-
if (str.length > MAX_VALUE_FOR_ERROR_LEN) {
|
|
489
|
-
const rest = "[...truncated]";
|
|
490
|
-
let truncateAt = MAX_VALUE_FOR_ERROR_LEN - rest.length;
|
|
491
|
-
const codePoint = str.codePointAt(truncateAt - 1);
|
|
492
|
-
if (codePoint !== void 0 && codePoint > 65535) {
|
|
493
|
-
truncateAt -= 1;
|
|
494
|
-
}
|
|
495
|
-
return str.substring(0, truncateAt) + rest;
|
|
496
|
-
}
|
|
497
|
-
return str;
|
|
498
|
-
}
|
|
499
|
-
function convexToJsonInternal(value, originalValue, context, includeTopLevelUndefined) {
|
|
500
|
-
if (value === void 0) {
|
|
501
|
-
const contextText = context && ` (present at path ${context} in original object ${stringifyValueForError(
|
|
502
|
-
originalValue
|
|
503
|
-
)})`;
|
|
504
|
-
throw new Error(
|
|
505
|
-
`undefined is not a valid Convex value${contextText}. To learn about Convex's supported types, see https://docs.convex.dev/using/types.`
|
|
506
|
-
);
|
|
507
|
-
}
|
|
508
|
-
if (value === null) {
|
|
509
|
-
return value;
|
|
510
|
-
}
|
|
511
|
-
if (typeof value === "bigint") {
|
|
512
|
-
if (value < MIN_INT64 || MAX_INT64 < value) {
|
|
513
|
-
throw new Error(
|
|
514
|
-
`BigInt ${value} does not fit into a 64-bit signed integer.`
|
|
515
|
-
);
|
|
516
|
-
}
|
|
517
|
-
return { $integer: bigIntToBase64(value) };
|
|
518
|
-
}
|
|
519
|
-
if (typeof value === "number") {
|
|
520
|
-
if (isSpecial(value)) {
|
|
521
|
-
const buffer = new ArrayBuffer(8);
|
|
522
|
-
new DataView(buffer).setFloat64(0, value, LITTLE_ENDIAN);
|
|
523
|
-
return { $float: fromByteArray(new Uint8Array(buffer)) };
|
|
524
|
-
} else {
|
|
525
|
-
return value;
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
if (typeof value === "boolean") {
|
|
529
|
-
return value;
|
|
530
|
-
}
|
|
531
|
-
if (typeof value === "string") {
|
|
532
|
-
return value;
|
|
533
|
-
}
|
|
534
|
-
if (value instanceof ArrayBuffer) {
|
|
535
|
-
return { $bytes: fromByteArray(new Uint8Array(value)) };
|
|
536
|
-
}
|
|
537
|
-
if (Array.isArray(value)) {
|
|
538
|
-
return value.map(
|
|
539
|
-
(value2, i) => convexToJsonInternal(value2, originalValue, context + `[${i}]`, false)
|
|
540
|
-
);
|
|
541
|
-
}
|
|
542
|
-
if (value instanceof Set) {
|
|
543
|
-
throw new Error(
|
|
544
|
-
errorMessageForUnsupportedType(context, "Set", [...value], originalValue)
|
|
545
|
-
);
|
|
546
|
-
}
|
|
547
|
-
if (value instanceof Map) {
|
|
548
|
-
throw new Error(
|
|
549
|
-
errorMessageForUnsupportedType(context, "Map", [...value], originalValue)
|
|
550
|
-
);
|
|
551
|
-
}
|
|
552
|
-
if (!isSimpleObject(value)) {
|
|
553
|
-
const theType = value?.constructor?.name;
|
|
554
|
-
const typeName = theType ? `${theType} ` : "";
|
|
555
|
-
throw new Error(
|
|
556
|
-
errorMessageForUnsupportedType(context, typeName, value, originalValue)
|
|
557
|
-
);
|
|
558
|
-
}
|
|
559
|
-
const out = {};
|
|
560
|
-
const entries = Object.entries(value);
|
|
561
|
-
entries.sort(([k1, _v1], [k2, _v2]) => k1 === k2 ? 0 : k1 < k2 ? -1 : 1);
|
|
562
|
-
for (const [k, v2] of entries) {
|
|
563
|
-
if (v2 !== void 0) {
|
|
564
|
-
validateObjectField(k);
|
|
565
|
-
out[k] = convexToJsonInternal(v2, originalValue, context + `.${k}`, false);
|
|
566
|
-
} else if (includeTopLevelUndefined) {
|
|
567
|
-
validateObjectField(k);
|
|
568
|
-
out[k] = convexOrUndefinedToJsonInternal(
|
|
569
|
-
v2,
|
|
570
|
-
originalValue,
|
|
571
|
-
context + `.${k}`
|
|
572
|
-
);
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
return out;
|
|
576
|
-
}
|
|
577
|
-
function errorMessageForUnsupportedType(context, typeName, value, originalValue) {
|
|
578
|
-
if (context) {
|
|
579
|
-
return `${typeName}${stringifyValueForError(
|
|
580
|
-
value
|
|
581
|
-
)} is not a supported Convex type (present at path ${context} in original object ${stringifyValueForError(
|
|
582
|
-
originalValue
|
|
583
|
-
)}). To learn about Convex's supported types, see https://docs.convex.dev/using/types.`;
|
|
584
|
-
} else {
|
|
585
|
-
return `${typeName}${stringifyValueForError(
|
|
586
|
-
value
|
|
587
|
-
)} is not a supported Convex type.`;
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
function convexOrUndefinedToJsonInternal(value, originalValue, context) {
|
|
591
|
-
if (value === void 0) {
|
|
592
|
-
return { $undefined: null };
|
|
593
|
-
} else {
|
|
594
|
-
if (originalValue === void 0) {
|
|
595
|
-
throw new Error(
|
|
596
|
-
`Programming error. Current value is ${stringifyValueForError(
|
|
597
|
-
value
|
|
598
|
-
)} but original value is undefined`
|
|
599
|
-
);
|
|
600
|
-
}
|
|
601
|
-
return convexToJsonInternal(value, originalValue, context, false);
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
function convexToJson(value) {
|
|
605
|
-
return convexToJsonInternal(value, value, "", false);
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
// node_modules/convex/dist/esm/values/errors.js
|
|
609
|
-
var __defProp2 = Object.defineProperty;
|
|
610
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
611
|
-
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
612
|
-
var _a;
|
|
613
|
-
var _b;
|
|
614
|
-
var IDENTIFYING_FIELD = /* @__PURE__ */ Symbol.for("ConvexError");
|
|
615
|
-
var ConvexError = class extends (_b = Error, _a = IDENTIFYING_FIELD, _b) {
|
|
616
|
-
constructor(data) {
|
|
617
|
-
super(typeof data === "string" ? data : stringifyValueForError(data));
|
|
618
|
-
__publicField(this, "name", "ConvexError");
|
|
619
|
-
__publicField(this, "data");
|
|
620
|
-
__publicField(this, _a, true);
|
|
621
|
-
this.data = data;
|
|
622
|
-
}
|
|
623
|
-
};
|
|
624
|
-
|
|
625
|
-
// node_modules/convex/dist/esm/values/compare_utf8.js
|
|
626
|
-
var arr = () => Array.from({ length: 4 }, () => 0);
|
|
627
|
-
var aBytes = arr();
|
|
628
|
-
var bBytes = arr();
|
|
629
|
-
|
|
630
|
-
// node_modules/convex/dist/esm/browser/logging.js
|
|
631
|
-
var __defProp3 = Object.defineProperty;
|
|
632
|
-
var __defNormalProp2 = (obj, key, value) => key in obj ? __defProp3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
633
|
-
var __publicField2 = (obj, key, value) => __defNormalProp2(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
634
|
-
var INFO_COLOR = "color:rgb(0, 145, 255)";
|
|
635
|
-
function prefix_for_source(source) {
|
|
636
|
-
switch (source) {
|
|
637
|
-
case "query":
|
|
638
|
-
return "Q";
|
|
639
|
-
case "mutation":
|
|
640
|
-
return "M";
|
|
641
|
-
case "action":
|
|
642
|
-
return "A";
|
|
643
|
-
case "any":
|
|
644
|
-
return "?";
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
var DefaultLogger = class {
|
|
648
|
-
constructor(options) {
|
|
649
|
-
__publicField2(this, "_onLogLineFuncs");
|
|
650
|
-
__publicField2(this, "_verbose");
|
|
651
|
-
this._onLogLineFuncs = {};
|
|
652
|
-
this._verbose = options.verbose;
|
|
653
|
-
}
|
|
654
|
-
addLogLineListener(func) {
|
|
655
|
-
let id = Math.random().toString(36).substring(2, 15);
|
|
656
|
-
for (let i = 0; i < 10; i++) {
|
|
657
|
-
if (this._onLogLineFuncs[id] === void 0) {
|
|
658
|
-
break;
|
|
659
|
-
}
|
|
660
|
-
id = Math.random().toString(36).substring(2, 15);
|
|
661
|
-
}
|
|
662
|
-
this._onLogLineFuncs[id] = func;
|
|
663
|
-
return () => {
|
|
664
|
-
delete this._onLogLineFuncs[id];
|
|
665
|
-
};
|
|
666
|
-
}
|
|
667
|
-
logVerbose(...args) {
|
|
668
|
-
if (this._verbose) {
|
|
669
|
-
for (const func of Object.values(this._onLogLineFuncs)) {
|
|
670
|
-
func("debug", `${(/* @__PURE__ */ new Date()).toISOString()}`, ...args);
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
log(...args) {
|
|
675
|
-
for (const func of Object.values(this._onLogLineFuncs)) {
|
|
676
|
-
func("info", ...args);
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
warn(...args) {
|
|
680
|
-
for (const func of Object.values(this._onLogLineFuncs)) {
|
|
681
|
-
func("warn", ...args);
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
error(...args) {
|
|
685
|
-
for (const func of Object.values(this._onLogLineFuncs)) {
|
|
686
|
-
func("error", ...args);
|
|
687
|
-
}
|
|
688
|
-
}
|
|
689
|
-
};
|
|
690
|
-
function instantiateDefaultLogger(options) {
|
|
691
|
-
const logger = new DefaultLogger(options);
|
|
692
|
-
logger.addLogLineListener((level, ...args) => {
|
|
693
|
-
switch (level) {
|
|
694
|
-
case "debug":
|
|
695
|
-
console.debug(...args);
|
|
696
|
-
break;
|
|
697
|
-
case "info":
|
|
698
|
-
console.log(...args);
|
|
699
|
-
break;
|
|
700
|
-
case "warn":
|
|
701
|
-
console.warn(...args);
|
|
702
|
-
break;
|
|
703
|
-
case "error":
|
|
704
|
-
console.error(...args);
|
|
705
|
-
break;
|
|
706
|
-
default: {
|
|
707
|
-
level;
|
|
708
|
-
console.log(...args);
|
|
709
|
-
}
|
|
710
|
-
}
|
|
711
|
-
});
|
|
712
|
-
return logger;
|
|
713
|
-
}
|
|
714
|
-
function instantiateNoopLogger(options) {
|
|
715
|
-
return new DefaultLogger(options);
|
|
716
|
-
}
|
|
717
|
-
function logForFunction(logger, type, source, udfPath, message) {
|
|
718
|
-
const prefix = prefix_for_source(source);
|
|
719
|
-
if (typeof message === "object") {
|
|
720
|
-
message = `ConvexError ${JSON.stringify(message.errorData, null, 2)}`;
|
|
721
|
-
}
|
|
722
|
-
if (type === "info") {
|
|
723
|
-
const match = message.match(/^\[.*?\] /);
|
|
724
|
-
if (match === null) {
|
|
725
|
-
logger.error(
|
|
726
|
-
`[CONVEX ${prefix}(${udfPath})] Could not parse console.log`
|
|
727
|
-
);
|
|
728
|
-
return;
|
|
729
|
-
}
|
|
730
|
-
const level = message.slice(1, match[0].length - 2);
|
|
731
|
-
const args = message.slice(match[0].length);
|
|
732
|
-
logger.log(`%c[CONVEX ${prefix}(${udfPath})] [${level}]`, INFO_COLOR, args);
|
|
733
|
-
} else {
|
|
734
|
-
logger.error(`[CONVEX ${prefix}(${udfPath})] ${message}`);
|
|
735
|
-
}
|
|
736
|
-
}
|
|
737
|
-
function logFatalError(logger, message) {
|
|
738
|
-
const errorMessage = `[CONVEX FATAL ERROR] ${message}`;
|
|
739
|
-
logger.error(errorMessage);
|
|
740
|
-
return new Error(errorMessage);
|
|
741
|
-
}
|
|
742
|
-
function createHybridErrorStacktrace(source, udfPath, result) {
|
|
743
|
-
const prefix = prefix_for_source(source);
|
|
744
|
-
return `[CONVEX ${prefix}(${udfPath})] ${result.errorMessage}
|
|
745
|
-
Called by client`;
|
|
746
|
-
}
|
|
747
|
-
function forwardData(result, error) {
|
|
748
|
-
error.data = result.errorData;
|
|
749
|
-
return error;
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
// node_modules/convex/dist/esm/browser/sync/udf_path_utils.js
|
|
753
|
-
function canonicalizeUdfPath(udfPath) {
|
|
754
|
-
const pieces = udfPath.split(":");
|
|
755
|
-
let moduleName;
|
|
756
|
-
let functionName2;
|
|
757
|
-
if (pieces.length === 1) {
|
|
758
|
-
moduleName = pieces[0];
|
|
759
|
-
functionName2 = "default";
|
|
760
|
-
} else {
|
|
761
|
-
moduleName = pieces.slice(0, pieces.length - 1).join(":");
|
|
762
|
-
functionName2 = pieces[pieces.length - 1];
|
|
763
|
-
}
|
|
764
|
-
if (moduleName.endsWith(".js")) {
|
|
765
|
-
moduleName = moduleName.slice(0, -3);
|
|
766
|
-
}
|
|
767
|
-
return `${moduleName}:${functionName2}`;
|
|
768
|
-
}
|
|
769
|
-
function serializePathAndArgs(udfPath, args) {
|
|
770
|
-
return JSON.stringify({
|
|
771
|
-
udfPath: canonicalizeUdfPath(udfPath),
|
|
772
|
-
args: convexToJson(args)
|
|
773
|
-
});
|
|
774
|
-
}
|
|
775
|
-
function serializePaginatedPathAndArgs(udfPath, args, options) {
|
|
776
|
-
const { initialNumItems, id } = options;
|
|
777
|
-
const result = JSON.stringify({
|
|
778
|
-
type: "paginated",
|
|
779
|
-
udfPath: canonicalizeUdfPath(udfPath),
|
|
780
|
-
args: convexToJson(args),
|
|
781
|
-
options: convexToJson({ initialNumItems, id })
|
|
782
|
-
});
|
|
783
|
-
return result;
|
|
784
|
-
}
|
|
785
|
-
function serializedQueryTokenIsPaginated(token) {
|
|
786
|
-
return JSON.parse(token).type === "paginated";
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
// node_modules/convex/dist/esm/browser/sync/local_state.js
|
|
790
|
-
var __defProp4 = Object.defineProperty;
|
|
791
|
-
var __defNormalProp3 = (obj, key, value) => key in obj ? __defProp4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
792
|
-
var __publicField3 = (obj, key, value) => __defNormalProp3(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
793
|
-
var LocalSyncState = class {
|
|
794
|
-
constructor() {
|
|
795
|
-
__publicField3(this, "nextQueryId");
|
|
796
|
-
__publicField3(this, "querySetVersion");
|
|
797
|
-
__publicField3(this, "querySet");
|
|
798
|
-
__publicField3(this, "queryIdToToken");
|
|
799
|
-
__publicField3(this, "identityVersion");
|
|
800
|
-
__publicField3(this, "auth");
|
|
801
|
-
__publicField3(this, "outstandingQueriesOlderThanRestart");
|
|
802
|
-
__publicField3(this, "outstandingAuthOlderThanRestart");
|
|
803
|
-
__publicField3(this, "paused");
|
|
804
|
-
__publicField3(this, "pendingQuerySetModifications");
|
|
805
|
-
this.nextQueryId = 0;
|
|
806
|
-
this.querySetVersion = 0;
|
|
807
|
-
this.identityVersion = 0;
|
|
808
|
-
this.querySet = /* @__PURE__ */ new Map();
|
|
809
|
-
this.queryIdToToken = /* @__PURE__ */ new Map();
|
|
810
|
-
this.outstandingQueriesOlderThanRestart = /* @__PURE__ */ new Set();
|
|
811
|
-
this.outstandingAuthOlderThanRestart = false;
|
|
812
|
-
this.paused = false;
|
|
813
|
-
this.pendingQuerySetModifications = /* @__PURE__ */ new Map();
|
|
814
|
-
}
|
|
815
|
-
hasSyncedPastLastReconnect() {
|
|
816
|
-
return this.outstandingQueriesOlderThanRestart.size === 0 && !this.outstandingAuthOlderThanRestart;
|
|
817
|
-
}
|
|
818
|
-
markAuthCompletion() {
|
|
819
|
-
this.outstandingAuthOlderThanRestart = false;
|
|
820
|
-
}
|
|
821
|
-
subscribe(udfPath, args, journal, componentPath) {
|
|
822
|
-
const canonicalizedUdfPath = canonicalizeUdfPath(udfPath);
|
|
823
|
-
const queryToken = serializePathAndArgs(canonicalizedUdfPath, args);
|
|
824
|
-
const existingEntry = this.querySet.get(queryToken);
|
|
825
|
-
if (existingEntry !== void 0) {
|
|
826
|
-
existingEntry.numSubscribers += 1;
|
|
827
|
-
return {
|
|
828
|
-
queryToken,
|
|
829
|
-
modification: null,
|
|
830
|
-
unsubscribe: () => this.removeSubscriber(queryToken)
|
|
831
|
-
};
|
|
832
|
-
} else {
|
|
833
|
-
const queryId = this.nextQueryId++;
|
|
834
|
-
const query = {
|
|
835
|
-
id: queryId,
|
|
836
|
-
canonicalizedUdfPath,
|
|
837
|
-
args,
|
|
838
|
-
numSubscribers: 1,
|
|
839
|
-
journal,
|
|
840
|
-
componentPath
|
|
841
|
-
};
|
|
842
|
-
this.querySet.set(queryToken, query);
|
|
843
|
-
this.queryIdToToken.set(queryId, queryToken);
|
|
844
|
-
const baseVersion = this.querySetVersion;
|
|
845
|
-
const newVersion = this.querySetVersion + 1;
|
|
846
|
-
const add = {
|
|
847
|
-
type: "Add",
|
|
848
|
-
queryId,
|
|
849
|
-
udfPath: canonicalizedUdfPath,
|
|
850
|
-
args: [convexToJson(args)],
|
|
851
|
-
journal,
|
|
852
|
-
componentPath
|
|
853
|
-
};
|
|
854
|
-
if (this.paused) {
|
|
855
|
-
this.pendingQuerySetModifications.set(queryId, add);
|
|
856
|
-
} else {
|
|
857
|
-
this.querySetVersion = newVersion;
|
|
858
|
-
}
|
|
859
|
-
const modification = {
|
|
860
|
-
type: "ModifyQuerySet",
|
|
861
|
-
baseVersion,
|
|
862
|
-
newVersion,
|
|
863
|
-
modifications: [add]
|
|
864
|
-
};
|
|
865
|
-
return {
|
|
866
|
-
queryToken,
|
|
867
|
-
modification,
|
|
868
|
-
unsubscribe: () => this.removeSubscriber(queryToken)
|
|
869
|
-
};
|
|
870
|
-
}
|
|
871
|
-
}
|
|
872
|
-
transition(transition) {
|
|
873
|
-
for (const modification of transition.modifications) {
|
|
874
|
-
switch (modification.type) {
|
|
875
|
-
case "QueryUpdated":
|
|
876
|
-
case "QueryFailed": {
|
|
877
|
-
this.outstandingQueriesOlderThanRestart.delete(modification.queryId);
|
|
878
|
-
const journal = modification.journal;
|
|
879
|
-
if (journal !== void 0) {
|
|
880
|
-
const queryToken = this.queryIdToToken.get(modification.queryId);
|
|
881
|
-
if (queryToken !== void 0) {
|
|
882
|
-
this.querySet.get(queryToken).journal = journal;
|
|
883
|
-
}
|
|
884
|
-
}
|
|
885
|
-
break;
|
|
886
|
-
}
|
|
887
|
-
case "QueryRemoved": {
|
|
888
|
-
this.outstandingQueriesOlderThanRestart.delete(modification.queryId);
|
|
889
|
-
break;
|
|
890
|
-
}
|
|
891
|
-
default: {
|
|
892
|
-
modification;
|
|
893
|
-
throw new Error(`Invalid modification ${modification.type}`);
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
}
|
|
897
|
-
}
|
|
898
|
-
queryId(udfPath, args) {
|
|
899
|
-
const canonicalizedUdfPath = canonicalizeUdfPath(udfPath);
|
|
900
|
-
const queryToken = serializePathAndArgs(canonicalizedUdfPath, args);
|
|
901
|
-
const existingEntry = this.querySet.get(queryToken);
|
|
902
|
-
if (existingEntry !== void 0) {
|
|
903
|
-
return existingEntry.id;
|
|
904
|
-
}
|
|
905
|
-
return null;
|
|
906
|
-
}
|
|
907
|
-
isCurrentOrNewerAuthVersion(version2) {
|
|
908
|
-
return version2 >= this.identityVersion;
|
|
909
|
-
}
|
|
910
|
-
getAuth() {
|
|
911
|
-
return this.auth;
|
|
912
|
-
}
|
|
913
|
-
setAuth(value) {
|
|
914
|
-
this.auth = {
|
|
915
|
-
tokenType: "User",
|
|
916
|
-
value
|
|
917
|
-
};
|
|
918
|
-
const baseVersion = this.identityVersion;
|
|
919
|
-
if (!this.paused) {
|
|
920
|
-
this.identityVersion = baseVersion + 1;
|
|
921
|
-
}
|
|
922
|
-
return {
|
|
923
|
-
type: "Authenticate",
|
|
924
|
-
baseVersion,
|
|
925
|
-
...this.auth
|
|
926
|
-
};
|
|
927
|
-
}
|
|
928
|
-
setAdminAuth(value, actingAs) {
|
|
929
|
-
const auth = {
|
|
930
|
-
tokenType: "Admin",
|
|
931
|
-
value,
|
|
932
|
-
impersonating: actingAs
|
|
933
|
-
};
|
|
934
|
-
this.auth = auth;
|
|
935
|
-
const baseVersion = this.identityVersion;
|
|
936
|
-
if (!this.paused) {
|
|
937
|
-
this.identityVersion = baseVersion + 1;
|
|
938
|
-
}
|
|
939
|
-
return {
|
|
940
|
-
type: "Authenticate",
|
|
941
|
-
baseVersion,
|
|
942
|
-
...auth
|
|
943
|
-
};
|
|
944
|
-
}
|
|
945
|
-
clearAuth() {
|
|
946
|
-
this.auth = void 0;
|
|
947
|
-
this.markAuthCompletion();
|
|
948
|
-
const baseVersion = this.identityVersion;
|
|
949
|
-
if (!this.paused) {
|
|
950
|
-
this.identityVersion = baseVersion + 1;
|
|
951
|
-
}
|
|
952
|
-
return {
|
|
953
|
-
type: "Authenticate",
|
|
954
|
-
tokenType: "None",
|
|
955
|
-
baseVersion
|
|
956
|
-
};
|
|
957
|
-
}
|
|
958
|
-
hasAuth() {
|
|
959
|
-
return !!this.auth;
|
|
960
|
-
}
|
|
961
|
-
isNewAuth(value) {
|
|
962
|
-
return this.auth?.value !== value;
|
|
963
|
-
}
|
|
964
|
-
queryPath(queryId) {
|
|
965
|
-
const pathAndArgs = this.queryIdToToken.get(queryId);
|
|
966
|
-
if (pathAndArgs) {
|
|
967
|
-
return this.querySet.get(pathAndArgs).canonicalizedUdfPath;
|
|
968
|
-
}
|
|
969
|
-
return null;
|
|
970
|
-
}
|
|
971
|
-
queryArgs(queryId) {
|
|
972
|
-
const pathAndArgs = this.queryIdToToken.get(queryId);
|
|
973
|
-
if (pathAndArgs) {
|
|
974
|
-
return this.querySet.get(pathAndArgs).args;
|
|
975
|
-
}
|
|
976
|
-
return null;
|
|
977
|
-
}
|
|
978
|
-
queryToken(queryId) {
|
|
979
|
-
return this.queryIdToToken.get(queryId) ?? null;
|
|
980
|
-
}
|
|
981
|
-
queryJournal(queryToken) {
|
|
982
|
-
return this.querySet.get(queryToken)?.journal;
|
|
983
|
-
}
|
|
984
|
-
restart(oldRemoteQueryResults) {
|
|
985
|
-
this.unpause();
|
|
986
|
-
this.outstandingQueriesOlderThanRestart.clear();
|
|
987
|
-
const modifications = [];
|
|
988
|
-
for (const localQuery of this.querySet.values()) {
|
|
989
|
-
const add = {
|
|
990
|
-
type: "Add",
|
|
991
|
-
queryId: localQuery.id,
|
|
992
|
-
udfPath: localQuery.canonicalizedUdfPath,
|
|
993
|
-
args: [convexToJson(localQuery.args)],
|
|
994
|
-
journal: localQuery.journal,
|
|
995
|
-
componentPath: localQuery.componentPath
|
|
996
|
-
};
|
|
997
|
-
modifications.push(add);
|
|
998
|
-
if (!oldRemoteQueryResults.has(localQuery.id)) {
|
|
999
|
-
this.outstandingQueriesOlderThanRestart.add(localQuery.id);
|
|
1000
|
-
}
|
|
1001
|
-
}
|
|
1002
|
-
this.querySetVersion = 1;
|
|
1003
|
-
const querySet = {
|
|
1004
|
-
type: "ModifyQuerySet",
|
|
1005
|
-
baseVersion: 0,
|
|
1006
|
-
newVersion: 1,
|
|
1007
|
-
modifications
|
|
1008
|
-
};
|
|
1009
|
-
if (!this.auth) {
|
|
1010
|
-
this.identityVersion = 0;
|
|
1011
|
-
return [querySet, void 0];
|
|
1012
|
-
}
|
|
1013
|
-
this.outstandingAuthOlderThanRestart = true;
|
|
1014
|
-
const authenticate = {
|
|
1015
|
-
type: "Authenticate",
|
|
1016
|
-
baseVersion: 0,
|
|
1017
|
-
...this.auth
|
|
1018
|
-
};
|
|
1019
|
-
this.identityVersion = 1;
|
|
1020
|
-
return [querySet, authenticate];
|
|
1021
|
-
}
|
|
1022
|
-
pause() {
|
|
1023
|
-
this.paused = true;
|
|
1024
|
-
}
|
|
1025
|
-
resume() {
|
|
1026
|
-
const querySet = this.pendingQuerySetModifications.size > 0 ? {
|
|
1027
|
-
type: "ModifyQuerySet",
|
|
1028
|
-
baseVersion: this.querySetVersion,
|
|
1029
|
-
newVersion: ++this.querySetVersion,
|
|
1030
|
-
modifications: Array.from(
|
|
1031
|
-
this.pendingQuerySetModifications.values()
|
|
1032
|
-
)
|
|
1033
|
-
} : void 0;
|
|
1034
|
-
const authenticate = this.auth !== void 0 ? {
|
|
1035
|
-
type: "Authenticate",
|
|
1036
|
-
baseVersion: this.identityVersion++,
|
|
1037
|
-
...this.auth
|
|
1038
|
-
} : void 0;
|
|
1039
|
-
this.unpause();
|
|
1040
|
-
return [querySet, authenticate];
|
|
1041
|
-
}
|
|
1042
|
-
unpause() {
|
|
1043
|
-
this.paused = false;
|
|
1044
|
-
this.pendingQuerySetModifications.clear();
|
|
1045
|
-
}
|
|
1046
|
-
removeSubscriber(queryToken) {
|
|
1047
|
-
const localQuery = this.querySet.get(queryToken);
|
|
1048
|
-
if (localQuery.numSubscribers > 1) {
|
|
1049
|
-
localQuery.numSubscribers -= 1;
|
|
1050
|
-
return null;
|
|
1051
|
-
} else {
|
|
1052
|
-
this.querySet.delete(queryToken);
|
|
1053
|
-
this.queryIdToToken.delete(localQuery.id);
|
|
1054
|
-
this.outstandingQueriesOlderThanRestart.delete(localQuery.id);
|
|
1055
|
-
const baseVersion = this.querySetVersion;
|
|
1056
|
-
const newVersion = this.querySetVersion + 1;
|
|
1057
|
-
const remove = {
|
|
1058
|
-
type: "Remove",
|
|
1059
|
-
queryId: localQuery.id
|
|
1060
|
-
};
|
|
1061
|
-
if (this.paused) {
|
|
1062
|
-
if (this.pendingQuerySetModifications.has(localQuery.id)) {
|
|
1063
|
-
this.pendingQuerySetModifications.delete(localQuery.id);
|
|
1064
|
-
} else {
|
|
1065
|
-
this.pendingQuerySetModifications.set(localQuery.id, remove);
|
|
1066
|
-
}
|
|
1067
|
-
} else {
|
|
1068
|
-
this.querySetVersion = newVersion;
|
|
1069
|
-
}
|
|
1070
|
-
return {
|
|
1071
|
-
type: "ModifyQuerySet",
|
|
1072
|
-
baseVersion,
|
|
1073
|
-
newVersion,
|
|
1074
|
-
modifications: [remove]
|
|
1075
|
-
};
|
|
1076
|
-
}
|
|
1077
|
-
}
|
|
1078
|
-
};
|
|
1079
|
-
|
|
1080
|
-
// node_modules/convex/dist/esm/browser/sync/request_manager.js
|
|
1081
|
-
var __defProp5 = Object.defineProperty;
|
|
1082
|
-
var __defNormalProp4 = (obj, key, value) => key in obj ? __defProp5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
1083
|
-
var __publicField4 = (obj, key, value) => __defNormalProp4(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1084
|
-
var RequestManager = class {
|
|
1085
|
-
constructor(logger, markConnectionStateDirty) {
|
|
1086
|
-
this.logger = logger;
|
|
1087
|
-
this.markConnectionStateDirty = markConnectionStateDirty;
|
|
1088
|
-
__publicField4(this, "inflightRequests");
|
|
1089
|
-
__publicField4(this, "requestsOlderThanRestart");
|
|
1090
|
-
__publicField4(this, "inflightMutationsCount", 0);
|
|
1091
|
-
__publicField4(this, "inflightActionsCount", 0);
|
|
1092
|
-
this.inflightRequests = /* @__PURE__ */ new Map();
|
|
1093
|
-
this.requestsOlderThanRestart = /* @__PURE__ */ new Set();
|
|
1094
|
-
}
|
|
1095
|
-
request(message, sent) {
|
|
1096
|
-
const result = new Promise((resolve) => {
|
|
1097
|
-
const status = sent ? "Requested" : "NotSent";
|
|
1098
|
-
this.inflightRequests.set(message.requestId, {
|
|
1099
|
-
message,
|
|
1100
|
-
status: { status, requestedAt: /* @__PURE__ */ new Date(), onResult: resolve }
|
|
1101
|
-
});
|
|
1102
|
-
if (message.type === "Mutation") {
|
|
1103
|
-
this.inflightMutationsCount++;
|
|
1104
|
-
} else if (message.type === "Action") {
|
|
1105
|
-
this.inflightActionsCount++;
|
|
1106
|
-
}
|
|
1107
|
-
});
|
|
1108
|
-
this.markConnectionStateDirty();
|
|
1109
|
-
return result;
|
|
1110
|
-
}
|
|
1111
|
-
/**
|
|
1112
|
-
* Update the state after receiving a response.
|
|
1113
|
-
*
|
|
1114
|
-
* @returns A RequestId if the request is complete and its optimistic update
|
|
1115
|
-
* can be dropped, null otherwise.
|
|
1116
|
-
*/
|
|
1117
|
-
onResponse(response) {
|
|
1118
|
-
const requestInfo = this.inflightRequests.get(response.requestId);
|
|
1119
|
-
if (requestInfo === void 0) {
|
|
1120
|
-
return null;
|
|
1121
|
-
}
|
|
1122
|
-
if (requestInfo.status.status === "Completed") {
|
|
1123
|
-
return null;
|
|
1124
|
-
}
|
|
1125
|
-
const udfType = requestInfo.message.type === "Mutation" ? "mutation" : "action";
|
|
1126
|
-
const udfPath = requestInfo.message.udfPath;
|
|
1127
|
-
for (const line of response.logLines) {
|
|
1128
|
-
logForFunction(this.logger, "info", udfType, udfPath, line);
|
|
1129
|
-
}
|
|
1130
|
-
const status = requestInfo.status;
|
|
1131
|
-
let result;
|
|
1132
|
-
let onResolve;
|
|
1133
|
-
if (response.success) {
|
|
1134
|
-
result = {
|
|
1135
|
-
success: true,
|
|
1136
|
-
logLines: response.logLines,
|
|
1137
|
-
value: jsonToConvex(response.result)
|
|
1138
|
-
};
|
|
1139
|
-
onResolve = () => status.onResult(result);
|
|
1140
|
-
} else {
|
|
1141
|
-
const errorMessage = response.result;
|
|
1142
|
-
const { errorData } = response;
|
|
1143
|
-
logForFunction(this.logger, "error", udfType, udfPath, errorMessage);
|
|
1144
|
-
result = {
|
|
1145
|
-
success: false,
|
|
1146
|
-
errorMessage,
|
|
1147
|
-
errorData: errorData !== void 0 ? jsonToConvex(errorData) : void 0,
|
|
1148
|
-
logLines: response.logLines
|
|
1149
|
-
};
|
|
1150
|
-
onResolve = () => status.onResult(result);
|
|
1151
|
-
}
|
|
1152
|
-
if (response.type === "ActionResponse" || !response.success) {
|
|
1153
|
-
onResolve();
|
|
1154
|
-
this.inflightRequests.delete(response.requestId);
|
|
1155
|
-
this.requestsOlderThanRestart.delete(response.requestId);
|
|
1156
|
-
if (requestInfo.message.type === "Action") {
|
|
1157
|
-
this.inflightActionsCount--;
|
|
1158
|
-
} else if (requestInfo.message.type === "Mutation") {
|
|
1159
|
-
this.inflightMutationsCount--;
|
|
1160
|
-
}
|
|
1161
|
-
this.markConnectionStateDirty();
|
|
1162
|
-
return { requestId: response.requestId, result };
|
|
1163
|
-
}
|
|
1164
|
-
requestInfo.status = {
|
|
1165
|
-
status: "Completed",
|
|
1166
|
-
result,
|
|
1167
|
-
ts: response.ts,
|
|
1168
|
-
onResolve
|
|
1169
|
-
};
|
|
1170
|
-
return null;
|
|
1171
|
-
}
|
|
1172
|
-
// Remove and returns completed requests.
|
|
1173
|
-
removeCompleted(ts) {
|
|
1174
|
-
const completeRequests = /* @__PURE__ */ new Map();
|
|
1175
|
-
for (const [requestId, requestInfo] of this.inflightRequests.entries()) {
|
|
1176
|
-
const status = requestInfo.status;
|
|
1177
|
-
if (status.status === "Completed" && status.ts.lessThanOrEqual(ts)) {
|
|
1178
|
-
status.onResolve();
|
|
1179
|
-
completeRequests.set(requestId, status.result);
|
|
1180
|
-
if (requestInfo.message.type === "Mutation") {
|
|
1181
|
-
this.inflightMutationsCount--;
|
|
1182
|
-
} else if (requestInfo.message.type === "Action") {
|
|
1183
|
-
this.inflightActionsCount--;
|
|
1184
|
-
}
|
|
1185
|
-
this.inflightRequests.delete(requestId);
|
|
1186
|
-
this.requestsOlderThanRestart.delete(requestId);
|
|
1187
|
-
}
|
|
1188
|
-
}
|
|
1189
|
-
if (completeRequests.size > 0) {
|
|
1190
|
-
this.markConnectionStateDirty();
|
|
1191
|
-
}
|
|
1192
|
-
return completeRequests;
|
|
1193
|
-
}
|
|
1194
|
-
restart() {
|
|
1195
|
-
this.requestsOlderThanRestart = new Set(this.inflightRequests.keys());
|
|
1196
|
-
const allMessages = [];
|
|
1197
|
-
for (const [requestId, value] of this.inflightRequests) {
|
|
1198
|
-
if (value.status.status === "NotSent") {
|
|
1199
|
-
value.status.status = "Requested";
|
|
1200
|
-
allMessages.push(value.message);
|
|
1201
|
-
continue;
|
|
1202
|
-
}
|
|
1203
|
-
if (value.message.type === "Mutation") {
|
|
1204
|
-
allMessages.push(value.message);
|
|
1205
|
-
} else if (value.message.type === "Action") {
|
|
1206
|
-
this.inflightRequests.delete(requestId);
|
|
1207
|
-
this.requestsOlderThanRestart.delete(requestId);
|
|
1208
|
-
this.inflightActionsCount--;
|
|
1209
|
-
if (value.status.status === "Completed") {
|
|
1210
|
-
throw new Error("Action should never be in 'Completed' state");
|
|
1211
|
-
}
|
|
1212
|
-
value.status.onResult({
|
|
1213
|
-
success: false,
|
|
1214
|
-
errorMessage: "Connection lost while action was in flight",
|
|
1215
|
-
logLines: []
|
|
1216
|
-
});
|
|
1217
|
-
}
|
|
1218
|
-
}
|
|
1219
|
-
this.markConnectionStateDirty();
|
|
1220
|
-
return allMessages;
|
|
1221
|
-
}
|
|
1222
|
-
resume() {
|
|
1223
|
-
const allMessages = [];
|
|
1224
|
-
for (const [, value] of this.inflightRequests) {
|
|
1225
|
-
if (value.status.status === "NotSent") {
|
|
1226
|
-
value.status.status = "Requested";
|
|
1227
|
-
allMessages.push(value.message);
|
|
1228
|
-
continue;
|
|
1229
|
-
}
|
|
1230
|
-
}
|
|
1231
|
-
return allMessages;
|
|
1232
|
-
}
|
|
1233
|
-
/**
|
|
1234
|
-
* @returns true if there are any requests that have been requested but have
|
|
1235
|
-
* not be completed yet.
|
|
1236
|
-
*/
|
|
1237
|
-
hasIncompleteRequests() {
|
|
1238
|
-
for (const requestInfo of this.inflightRequests.values()) {
|
|
1239
|
-
if (requestInfo.status.status === "Requested") {
|
|
1240
|
-
return true;
|
|
1241
|
-
}
|
|
1242
|
-
}
|
|
1243
|
-
return false;
|
|
1244
|
-
}
|
|
1245
|
-
/**
|
|
1246
|
-
* @returns true if there are any inflight requests, including ones that have
|
|
1247
|
-
* completed on the server, but have not been applied.
|
|
1248
|
-
*/
|
|
1249
|
-
hasInflightRequests() {
|
|
1250
|
-
return this.inflightRequests.size > 0;
|
|
1251
|
-
}
|
|
1252
|
-
/**
|
|
1253
|
-
* @returns true if there are any inflight requests, that have been hanging around
|
|
1254
|
-
* since prior to the most recent restart.
|
|
1255
|
-
*/
|
|
1256
|
-
hasSyncedPastLastReconnect() {
|
|
1257
|
-
return this.requestsOlderThanRestart.size === 0;
|
|
1258
|
-
}
|
|
1259
|
-
timeOfOldestInflightRequest() {
|
|
1260
|
-
if (this.inflightRequests.size === 0) {
|
|
1261
|
-
return null;
|
|
1262
|
-
}
|
|
1263
|
-
let oldestInflightRequest = Date.now();
|
|
1264
|
-
for (const request of this.inflightRequests.values()) {
|
|
1265
|
-
if (request.status.status !== "Completed") {
|
|
1266
|
-
if (request.status.requestedAt.getTime() < oldestInflightRequest) {
|
|
1267
|
-
oldestInflightRequest = request.status.requestedAt.getTime();
|
|
1268
|
-
}
|
|
1269
|
-
}
|
|
1270
|
-
}
|
|
1271
|
-
return new Date(oldestInflightRequest);
|
|
1272
|
-
}
|
|
1273
|
-
/**
|
|
1274
|
-
* @returns The number of mutations currently in flight.
|
|
1275
|
-
*/
|
|
1276
|
-
inflightMutations() {
|
|
1277
|
-
return this.inflightMutationsCount;
|
|
1278
|
-
}
|
|
1279
|
-
/**
|
|
1280
|
-
* @returns The number of actions currently in flight.
|
|
1281
|
-
*/
|
|
1282
|
-
inflightActions() {
|
|
1283
|
-
return this.inflightActionsCount;
|
|
1284
|
-
}
|
|
1285
|
-
};
|
|
1286
|
-
|
|
1287
|
-
// node_modules/convex/dist/esm/server/functionName.js
|
|
1288
|
-
var functionName = /* @__PURE__ */ Symbol.for("functionName");
|
|
1289
|
-
|
|
1290
|
-
// node_modules/convex/dist/esm/server/components/paths.js
|
|
1291
|
-
var toReferencePath = /* @__PURE__ */ Symbol.for("toReferencePath");
|
|
1292
|
-
function extractReferencePath(reference) {
|
|
1293
|
-
return reference[toReferencePath] ?? null;
|
|
1294
|
-
}
|
|
1295
|
-
function isFunctionHandle(s) {
|
|
1296
|
-
return s.startsWith("function://");
|
|
1297
|
-
}
|
|
1298
|
-
function getFunctionAddress(functionReference) {
|
|
1299
|
-
let functionAddress;
|
|
1300
|
-
if (typeof functionReference === "string") {
|
|
1301
|
-
if (isFunctionHandle(functionReference)) {
|
|
1302
|
-
functionAddress = { functionHandle: functionReference };
|
|
1303
|
-
} else {
|
|
1304
|
-
functionAddress = { name: functionReference };
|
|
1305
|
-
}
|
|
1306
|
-
} else if (functionReference[functionName]) {
|
|
1307
|
-
functionAddress = { name: functionReference[functionName] };
|
|
1308
|
-
} else {
|
|
1309
|
-
const referencePath = extractReferencePath(functionReference);
|
|
1310
|
-
if (!referencePath) {
|
|
1311
|
-
throw new Error(`${functionReference} is not a functionReference`);
|
|
1312
|
-
}
|
|
1313
|
-
functionAddress = { reference: referencePath };
|
|
1314
|
-
}
|
|
1315
|
-
return functionAddress;
|
|
1316
|
-
}
|
|
1317
|
-
|
|
1318
|
-
// node_modules/convex/dist/esm/server/api.js
|
|
1319
|
-
function getFunctionName(functionReference) {
|
|
1320
|
-
const address = getFunctionAddress(functionReference);
|
|
1321
|
-
if (address.name === void 0) {
|
|
1322
|
-
if (address.functionHandle !== void 0) {
|
|
1323
|
-
throw new Error(
|
|
1324
|
-
`Expected function reference like "api.file.func" or "internal.file.func", but received function handle ${address.functionHandle}`
|
|
1325
|
-
);
|
|
1326
|
-
} else if (address.reference !== void 0) {
|
|
1327
|
-
throw new Error(
|
|
1328
|
-
`Expected function reference in the current component like "api.file.func" or "internal.file.func", but received reference ${address.reference}`
|
|
1329
|
-
);
|
|
1330
|
-
}
|
|
1331
|
-
throw new Error(
|
|
1332
|
-
`Expected function reference like "api.file.func" or "internal.file.func", but received ${JSON.stringify(address)}`
|
|
1333
|
-
);
|
|
1334
|
-
}
|
|
1335
|
-
if (typeof functionReference === "string") return functionReference;
|
|
1336
|
-
const name = functionReference[functionName];
|
|
1337
|
-
if (!name) {
|
|
1338
|
-
throw new Error(`${functionReference} is not a functionReference`);
|
|
1339
|
-
}
|
|
1340
|
-
return name;
|
|
1341
|
-
}
|
|
1342
|
-
function createApi(pathParts = []) {
|
|
1343
|
-
const handler = {
|
|
1344
|
-
get(_, prop) {
|
|
1345
|
-
if (typeof prop === "string") {
|
|
1346
|
-
const newParts = [...pathParts, prop];
|
|
1347
|
-
return createApi(newParts);
|
|
1348
|
-
} else if (prop === functionName) {
|
|
1349
|
-
if (pathParts.length < 2) {
|
|
1350
|
-
const found = ["api", ...pathParts].join(".");
|
|
1351
|
-
throw new Error(
|
|
1352
|
-
`API path is expected to be of the form \`api.moduleName.functionName\`. Found: \`${found}\``
|
|
1353
|
-
);
|
|
1354
|
-
}
|
|
1355
|
-
const path = pathParts.slice(0, -1).join("/");
|
|
1356
|
-
const exportName = pathParts[pathParts.length - 1];
|
|
1357
|
-
if (exportName === "default") {
|
|
1358
|
-
return path;
|
|
1359
|
-
} else {
|
|
1360
|
-
return path + ":" + exportName;
|
|
1361
|
-
}
|
|
1362
|
-
} else if (prop === Symbol.toStringTag) {
|
|
1363
|
-
return "FunctionReference";
|
|
1364
|
-
} else {
|
|
1365
|
-
return void 0;
|
|
1366
|
-
}
|
|
1367
|
-
}
|
|
1368
|
-
};
|
|
1369
|
-
return new Proxy({}, handler);
|
|
1370
|
-
}
|
|
1371
|
-
var anyApi = createApi();
|
|
1372
|
-
|
|
1373
|
-
// node_modules/convex/dist/esm/browser/sync/optimistic_updates_impl.js
|
|
1374
|
-
var __defProp6 = Object.defineProperty;
|
|
1375
|
-
var __defNormalProp5 = (obj, key, value) => key in obj ? __defProp6(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
1376
|
-
var __publicField5 = (obj, key, value) => __defNormalProp5(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1377
|
-
var OptimisticLocalStoreImpl = class _OptimisticLocalStoreImpl {
|
|
1378
|
-
constructor(queryResults) {
|
|
1379
|
-
__publicField5(this, "queryResults");
|
|
1380
|
-
__publicField5(this, "modifiedQueries");
|
|
1381
|
-
this.queryResults = queryResults;
|
|
1382
|
-
this.modifiedQueries = [];
|
|
1383
|
-
}
|
|
1384
|
-
getQuery(query, ...args) {
|
|
1385
|
-
const queryArgs = parseArgs(args[0]);
|
|
1386
|
-
const name = getFunctionName(query);
|
|
1387
|
-
const queryResult = this.queryResults.get(
|
|
1388
|
-
serializePathAndArgs(name, queryArgs)
|
|
1389
|
-
);
|
|
1390
|
-
if (queryResult === void 0) {
|
|
1391
|
-
return void 0;
|
|
1392
|
-
}
|
|
1393
|
-
return _OptimisticLocalStoreImpl.queryValue(queryResult.result);
|
|
1394
|
-
}
|
|
1395
|
-
getAllQueries(query) {
|
|
1396
|
-
const queriesWithName = [];
|
|
1397
|
-
const name = getFunctionName(query);
|
|
1398
|
-
for (const queryResult of this.queryResults.values()) {
|
|
1399
|
-
if (queryResult.udfPath === canonicalizeUdfPath(name)) {
|
|
1400
|
-
queriesWithName.push({
|
|
1401
|
-
args: queryResult.args,
|
|
1402
|
-
value: _OptimisticLocalStoreImpl.queryValue(queryResult.result)
|
|
1403
|
-
});
|
|
1404
|
-
}
|
|
1405
|
-
}
|
|
1406
|
-
return queriesWithName;
|
|
1407
|
-
}
|
|
1408
|
-
setQuery(queryReference, args, value) {
|
|
1409
|
-
const queryArgs = parseArgs(args);
|
|
1410
|
-
const name = getFunctionName(queryReference);
|
|
1411
|
-
const queryToken = serializePathAndArgs(name, queryArgs);
|
|
1412
|
-
let result;
|
|
1413
|
-
if (value === void 0) {
|
|
1414
|
-
result = void 0;
|
|
1415
|
-
} else {
|
|
1416
|
-
result = {
|
|
1417
|
-
success: true,
|
|
1418
|
-
value,
|
|
1419
|
-
// It's an optimistic update, so there are no function logs to show.
|
|
1420
|
-
logLines: []
|
|
1421
|
-
};
|
|
1422
|
-
}
|
|
1423
|
-
const query = {
|
|
1424
|
-
udfPath: name,
|
|
1425
|
-
args: queryArgs,
|
|
1426
|
-
result
|
|
1427
|
-
};
|
|
1428
|
-
this.queryResults.set(queryToken, query);
|
|
1429
|
-
this.modifiedQueries.push(queryToken);
|
|
1430
|
-
}
|
|
1431
|
-
static queryValue(result) {
|
|
1432
|
-
if (result === void 0) {
|
|
1433
|
-
return void 0;
|
|
1434
|
-
} else if (result.success) {
|
|
1435
|
-
return result.value;
|
|
1436
|
-
} else {
|
|
1437
|
-
return void 0;
|
|
1438
|
-
}
|
|
1439
|
-
}
|
|
1440
|
-
};
|
|
1441
|
-
var OptimisticQueryResults = class {
|
|
1442
|
-
constructor() {
|
|
1443
|
-
__publicField5(this, "queryResults");
|
|
1444
|
-
__publicField5(this, "optimisticUpdates");
|
|
1445
|
-
this.queryResults = /* @__PURE__ */ new Map();
|
|
1446
|
-
this.optimisticUpdates = [];
|
|
1447
|
-
}
|
|
1448
|
-
/**
|
|
1449
|
-
* Apply all optimistic updates on top of server query results
|
|
1450
|
-
*/
|
|
1451
|
-
ingestQueryResultsFromServer(serverQueryResults, optimisticUpdatesToDrop) {
|
|
1452
|
-
this.optimisticUpdates = this.optimisticUpdates.filter((updateAndId) => {
|
|
1453
|
-
return !optimisticUpdatesToDrop.has(updateAndId.mutationId);
|
|
1454
|
-
});
|
|
1455
|
-
const oldQueryResults = this.queryResults;
|
|
1456
|
-
this.queryResults = new Map(serverQueryResults);
|
|
1457
|
-
const localStore = new OptimisticLocalStoreImpl(this.queryResults);
|
|
1458
|
-
for (const updateAndId of this.optimisticUpdates) {
|
|
1459
|
-
updateAndId.update(localStore);
|
|
1460
|
-
}
|
|
1461
|
-
const changedQueries = [];
|
|
1462
|
-
for (const [queryToken, query] of this.queryResults) {
|
|
1463
|
-
const oldQuery = oldQueryResults.get(queryToken);
|
|
1464
|
-
if (oldQuery === void 0 || oldQuery.result !== query.result) {
|
|
1465
|
-
changedQueries.push(queryToken);
|
|
1466
|
-
}
|
|
1467
|
-
}
|
|
1468
|
-
return changedQueries;
|
|
1469
|
-
}
|
|
1470
|
-
applyOptimisticUpdate(update, mutationId) {
|
|
1471
|
-
this.optimisticUpdates.push({
|
|
1472
|
-
update,
|
|
1473
|
-
mutationId
|
|
1474
|
-
});
|
|
1475
|
-
const localStore = new OptimisticLocalStoreImpl(this.queryResults);
|
|
1476
|
-
update(localStore);
|
|
1477
|
-
return localStore.modifiedQueries;
|
|
1478
|
-
}
|
|
1479
|
-
/**
|
|
1480
|
-
* "Raw" with respect to errors vs values, but query results still have
|
|
1481
|
-
* optimistic updates applied.
|
|
1482
|
-
*
|
|
1483
|
-
* @internal
|
|
1484
|
-
*/
|
|
1485
|
-
rawQueryResult(queryToken) {
|
|
1486
|
-
const query = this.queryResults.get(queryToken);
|
|
1487
|
-
if (query === void 0) {
|
|
1488
|
-
return void 0;
|
|
1489
|
-
}
|
|
1490
|
-
return query.result;
|
|
1491
|
-
}
|
|
1492
|
-
queryResult(queryToken) {
|
|
1493
|
-
const query = this.queryResults.get(queryToken);
|
|
1494
|
-
if (query === void 0) {
|
|
1495
|
-
return void 0;
|
|
1496
|
-
}
|
|
1497
|
-
const result = query.result;
|
|
1498
|
-
if (result === void 0) {
|
|
1499
|
-
return void 0;
|
|
1500
|
-
} else if (result.success) {
|
|
1501
|
-
return result.value;
|
|
1502
|
-
} else {
|
|
1503
|
-
if (result.errorData !== void 0) {
|
|
1504
|
-
throw forwardData(
|
|
1505
|
-
result,
|
|
1506
|
-
new ConvexError(
|
|
1507
|
-
createHybridErrorStacktrace("query", query.udfPath, result)
|
|
1508
|
-
)
|
|
1509
|
-
);
|
|
1510
|
-
}
|
|
1511
|
-
throw new Error(
|
|
1512
|
-
createHybridErrorStacktrace("query", query.udfPath, result)
|
|
1513
|
-
);
|
|
1514
|
-
}
|
|
1515
|
-
}
|
|
1516
|
-
hasQueryResult(queryToken) {
|
|
1517
|
-
return this.queryResults.get(queryToken) !== void 0;
|
|
1518
|
-
}
|
|
1519
|
-
/**
|
|
1520
|
-
* @internal
|
|
1521
|
-
*/
|
|
1522
|
-
queryLogs(queryToken) {
|
|
1523
|
-
const query = this.queryResults.get(queryToken);
|
|
1524
|
-
return query?.result?.logLines;
|
|
1525
|
-
}
|
|
1526
|
-
};
|
|
1527
|
-
|
|
1528
|
-
// node_modules/convex/dist/esm/vendor/long.js
|
|
1529
|
-
var __defProp7 = Object.defineProperty;
|
|
1530
|
-
var __defNormalProp6 = (obj, key, value) => key in obj ? __defProp7(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
1531
|
-
var __publicField6 = (obj, key, value) => __defNormalProp6(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1532
|
-
var Long = class _Long {
|
|
1533
|
-
constructor(low, high) {
|
|
1534
|
-
__publicField6(this, "low");
|
|
1535
|
-
__publicField6(this, "high");
|
|
1536
|
-
__publicField6(this, "__isUnsignedLong__");
|
|
1537
|
-
this.low = low | 0;
|
|
1538
|
-
this.high = high | 0;
|
|
1539
|
-
this.__isUnsignedLong__ = true;
|
|
1540
|
-
}
|
|
1541
|
-
static isLong(obj) {
|
|
1542
|
-
return (obj && obj.__isUnsignedLong__) === true;
|
|
1543
|
-
}
|
|
1544
|
-
// prettier-ignore
|
|
1545
|
-
static fromBytesLE(bytes) {
|
|
1546
|
-
return new _Long(
|
|
1547
|
-
bytes[0] | bytes[1] << 8 | bytes[2] << 16 | bytes[3] << 24,
|
|
1548
|
-
bytes[4] | bytes[5] << 8 | bytes[6] << 16 | bytes[7] << 24
|
|
1549
|
-
);
|
|
1550
|
-
}
|
|
1551
|
-
// prettier-ignore
|
|
1552
|
-
toBytesLE() {
|
|
1553
|
-
const hi = this.high;
|
|
1554
|
-
const lo = this.low;
|
|
1555
|
-
return [
|
|
1556
|
-
lo & 255,
|
|
1557
|
-
lo >>> 8 & 255,
|
|
1558
|
-
lo >>> 16 & 255,
|
|
1559
|
-
lo >>> 24,
|
|
1560
|
-
hi & 255,
|
|
1561
|
-
hi >>> 8 & 255,
|
|
1562
|
-
hi >>> 16 & 255,
|
|
1563
|
-
hi >>> 24
|
|
1564
|
-
];
|
|
1565
|
-
}
|
|
1566
|
-
static fromNumber(value) {
|
|
1567
|
-
if (isNaN(value)) return UZERO;
|
|
1568
|
-
if (value < 0) return UZERO;
|
|
1569
|
-
if (value >= TWO_PWR_64_DBL) return MAX_UNSIGNED_VALUE;
|
|
1570
|
-
return new _Long(value % TWO_PWR_32_DBL | 0, value / TWO_PWR_32_DBL | 0);
|
|
1571
|
-
}
|
|
1572
|
-
toString() {
|
|
1573
|
-
return (BigInt(this.high) * BigInt(TWO_PWR_32_DBL) + BigInt(this.low)).toString();
|
|
1574
|
-
}
|
|
1575
|
-
equals(other) {
|
|
1576
|
-
if (!_Long.isLong(other)) other = _Long.fromValue(other);
|
|
1577
|
-
if (this.high >>> 31 === 1 && other.high >>> 31 === 1) return false;
|
|
1578
|
-
return this.high === other.high && this.low === other.low;
|
|
1579
|
-
}
|
|
1580
|
-
notEquals(other) {
|
|
1581
|
-
return !this.equals(other);
|
|
1582
|
-
}
|
|
1583
|
-
comp(other) {
|
|
1584
|
-
if (!_Long.isLong(other)) other = _Long.fromValue(other);
|
|
1585
|
-
if (this.equals(other)) return 0;
|
|
1586
|
-
return other.high >>> 0 > this.high >>> 0 || other.high === this.high && other.low >>> 0 > this.low >>> 0 ? -1 : 1;
|
|
1587
|
-
}
|
|
1588
|
-
lessThanOrEqual(other) {
|
|
1589
|
-
return this.comp(
|
|
1590
|
-
/* validates */
|
|
1591
|
-
other
|
|
1592
|
-
) <= 0;
|
|
1593
|
-
}
|
|
1594
|
-
static fromValue(val) {
|
|
1595
|
-
if (typeof val === "number") return _Long.fromNumber(val);
|
|
1596
|
-
return new _Long(val.low, val.high);
|
|
1597
|
-
}
|
|
1598
|
-
};
|
|
1599
|
-
var UZERO = new Long(0, 0);
|
|
1600
|
-
var TWO_PWR_16_DBL = 1 << 16;
|
|
1601
|
-
var TWO_PWR_32_DBL = TWO_PWR_16_DBL * TWO_PWR_16_DBL;
|
|
1602
|
-
var TWO_PWR_64_DBL = TWO_PWR_32_DBL * TWO_PWR_32_DBL;
|
|
1603
|
-
var MAX_UNSIGNED_VALUE = new Long(4294967295 | 0, 4294967295 | 0);
|
|
1604
|
-
|
|
1605
|
-
// node_modules/convex/dist/esm/browser/sync/remote_query_set.js
|
|
1606
|
-
var __defProp8 = Object.defineProperty;
|
|
1607
|
-
var __defNormalProp7 = (obj, key, value) => key in obj ? __defProp8(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
1608
|
-
var __publicField7 = (obj, key, value) => __defNormalProp7(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1609
|
-
var RemoteQuerySet = class {
|
|
1610
|
-
constructor(queryPath, logger) {
|
|
1611
|
-
__publicField7(this, "version");
|
|
1612
|
-
__publicField7(this, "remoteQuerySet");
|
|
1613
|
-
__publicField7(this, "queryPath");
|
|
1614
|
-
__publicField7(this, "logger");
|
|
1615
|
-
this.version = { querySet: 0, ts: Long.fromNumber(0), identity: 0 };
|
|
1616
|
-
this.remoteQuerySet = /* @__PURE__ */ new Map();
|
|
1617
|
-
this.queryPath = queryPath;
|
|
1618
|
-
this.logger = logger;
|
|
1619
|
-
}
|
|
1620
|
-
transition(transition) {
|
|
1621
|
-
const start = transition.startVersion;
|
|
1622
|
-
if (this.version.querySet !== start.querySet || this.version.ts.notEquals(start.ts) || this.version.identity !== start.identity) {
|
|
1623
|
-
throw new Error(
|
|
1624
|
-
`Invalid start version: ${start.ts.toString()}:${start.querySet}:${start.identity}, transitioning from ${this.version.ts.toString()}:${this.version.querySet}:${this.version.identity}`
|
|
1625
|
-
);
|
|
1626
|
-
}
|
|
1627
|
-
for (const modification of transition.modifications) {
|
|
1628
|
-
switch (modification.type) {
|
|
1629
|
-
case "QueryUpdated": {
|
|
1630
|
-
const queryPath = this.queryPath(modification.queryId);
|
|
1631
|
-
if (queryPath) {
|
|
1632
|
-
for (const line of modification.logLines) {
|
|
1633
|
-
logForFunction(this.logger, "info", "query", queryPath, line);
|
|
1634
|
-
}
|
|
1635
|
-
}
|
|
1636
|
-
const value = jsonToConvex(modification.value ?? null);
|
|
1637
|
-
this.remoteQuerySet.set(modification.queryId, {
|
|
1638
|
-
success: true,
|
|
1639
|
-
value,
|
|
1640
|
-
logLines: modification.logLines
|
|
1641
|
-
});
|
|
1642
|
-
break;
|
|
1643
|
-
}
|
|
1644
|
-
case "QueryFailed": {
|
|
1645
|
-
const queryPath = this.queryPath(modification.queryId);
|
|
1646
|
-
if (queryPath) {
|
|
1647
|
-
for (const line of modification.logLines) {
|
|
1648
|
-
logForFunction(this.logger, "info", "query", queryPath, line);
|
|
1649
|
-
}
|
|
1650
|
-
}
|
|
1651
|
-
const { errorData } = modification;
|
|
1652
|
-
this.remoteQuerySet.set(modification.queryId, {
|
|
1653
|
-
success: false,
|
|
1654
|
-
errorMessage: modification.errorMessage,
|
|
1655
|
-
errorData: errorData !== void 0 ? jsonToConvex(errorData) : void 0,
|
|
1656
|
-
logLines: modification.logLines
|
|
1657
|
-
});
|
|
1658
|
-
break;
|
|
1659
|
-
}
|
|
1660
|
-
case "QueryRemoved": {
|
|
1661
|
-
this.remoteQuerySet.delete(modification.queryId);
|
|
1662
|
-
break;
|
|
1663
|
-
}
|
|
1664
|
-
default: {
|
|
1665
|
-
modification;
|
|
1666
|
-
throw new Error(`Invalid modification ${modification.type}`);
|
|
1667
|
-
}
|
|
1668
|
-
}
|
|
1669
|
-
}
|
|
1670
|
-
this.version = transition.endVersion;
|
|
1671
|
-
}
|
|
1672
|
-
remoteQueryResults() {
|
|
1673
|
-
return this.remoteQuerySet;
|
|
1674
|
-
}
|
|
1675
|
-
timestamp() {
|
|
1676
|
-
return this.version.ts;
|
|
1677
|
-
}
|
|
1678
|
-
};
|
|
1679
|
-
|
|
1680
|
-
// node_modules/convex/dist/esm/browser/sync/protocol.js
|
|
1681
|
-
function u64ToLong(encoded) {
|
|
1682
|
-
const integerBytes = base64_exports.toByteArray(encoded);
|
|
1683
|
-
return Long.fromBytesLE(Array.from(integerBytes));
|
|
1684
|
-
}
|
|
1685
|
-
function longToU64(raw) {
|
|
1686
|
-
const integerBytes = new Uint8Array(raw.toBytesLE());
|
|
1687
|
-
return base64_exports.fromByteArray(integerBytes);
|
|
1688
|
-
}
|
|
1689
|
-
function parseServerMessage(encoded) {
|
|
1690
|
-
switch (encoded.type) {
|
|
1691
|
-
case "FatalError":
|
|
1692
|
-
case "AuthError":
|
|
1693
|
-
case "ActionResponse":
|
|
1694
|
-
case "TransitionChunk":
|
|
1695
|
-
case "Ping": {
|
|
1696
|
-
return { ...encoded };
|
|
1697
|
-
}
|
|
1698
|
-
case "MutationResponse": {
|
|
1699
|
-
if (encoded.success) {
|
|
1700
|
-
return { ...encoded, ts: u64ToLong(encoded.ts) };
|
|
1701
|
-
} else {
|
|
1702
|
-
return { ...encoded };
|
|
1703
|
-
}
|
|
1704
|
-
}
|
|
1705
|
-
case "Transition": {
|
|
1706
|
-
return {
|
|
1707
|
-
...encoded,
|
|
1708
|
-
startVersion: {
|
|
1709
|
-
...encoded.startVersion,
|
|
1710
|
-
ts: u64ToLong(encoded.startVersion.ts)
|
|
1711
|
-
},
|
|
1712
|
-
endVersion: {
|
|
1713
|
-
...encoded.endVersion,
|
|
1714
|
-
ts: u64ToLong(encoded.endVersion.ts)
|
|
1715
|
-
}
|
|
1716
|
-
};
|
|
1717
|
-
}
|
|
1718
|
-
default: {
|
|
1719
|
-
encoded;
|
|
1720
|
-
}
|
|
1721
|
-
}
|
|
1722
|
-
return void 0;
|
|
1723
|
-
}
|
|
1724
|
-
function encodeClientMessage(message) {
|
|
1725
|
-
switch (message.type) {
|
|
1726
|
-
case "Authenticate":
|
|
1727
|
-
case "ModifyQuerySet":
|
|
1728
|
-
case "Mutation":
|
|
1729
|
-
case "Action":
|
|
1730
|
-
case "Event": {
|
|
1731
|
-
return { ...message };
|
|
1732
|
-
}
|
|
1733
|
-
case "Connect": {
|
|
1734
|
-
if (message.maxObservedTimestamp !== void 0) {
|
|
1735
|
-
return {
|
|
1736
|
-
...message,
|
|
1737
|
-
maxObservedTimestamp: longToU64(message.maxObservedTimestamp)
|
|
1738
|
-
};
|
|
1739
|
-
} else {
|
|
1740
|
-
return { ...message, maxObservedTimestamp: void 0 };
|
|
1741
|
-
}
|
|
1742
|
-
}
|
|
1743
|
-
default: {
|
|
1744
|
-
message;
|
|
1745
|
-
}
|
|
1746
|
-
}
|
|
1747
|
-
return void 0;
|
|
1748
|
-
}
|
|
1749
|
-
|
|
1750
|
-
// node_modules/convex/dist/esm/browser/sync/web_socket_manager.js
|
|
1751
|
-
var __defProp9 = Object.defineProperty;
|
|
1752
|
-
var __defNormalProp8 = (obj, key, value) => key in obj ? __defProp9(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
1753
|
-
var __publicField8 = (obj, key, value) => __defNormalProp8(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1754
|
-
var CLOSE_NORMAL = 1e3;
|
|
1755
|
-
var CLOSE_GOING_AWAY = 1001;
|
|
1756
|
-
var CLOSE_NO_STATUS = 1005;
|
|
1757
|
-
var CLOSE_NOT_FOUND = 4040;
|
|
1758
|
-
var firstTime;
|
|
1759
|
-
function monotonicMillis() {
|
|
1760
|
-
if (firstTime === void 0) {
|
|
1761
|
-
firstTime = Date.now();
|
|
1762
|
-
}
|
|
1763
|
-
if (typeof performance === "undefined" || !performance.now) {
|
|
1764
|
-
return Date.now();
|
|
1765
|
-
}
|
|
1766
|
-
return Math.round(firstTime + performance.now());
|
|
1767
|
-
}
|
|
1768
|
-
function prettyNow() {
|
|
1769
|
-
return `t=${Math.round((monotonicMillis() - firstTime) / 100) / 10}s`;
|
|
1770
|
-
}
|
|
1771
|
-
var serverDisconnectErrors = {
|
|
1772
|
-
// A known error, e.g. during a restart or push
|
|
1773
|
-
InternalServerError: { timeout: 1e3 },
|
|
1774
|
-
// ErrorMetadata::overloaded() messages that we realy should back off
|
|
1775
|
-
SubscriptionsWorkerFullError: { timeout: 3e3 },
|
|
1776
|
-
TooManyConcurrentRequests: { timeout: 3e3 },
|
|
1777
|
-
CommitterFullError: { timeout: 3e3 },
|
|
1778
|
-
AwsTooManyRequestsException: { timeout: 3e3 },
|
|
1779
|
-
ExecuteFullError: { timeout: 3e3 },
|
|
1780
|
-
SystemTimeoutError: { timeout: 3e3 },
|
|
1781
|
-
ExpiredInQueue: { timeout: 3e3 },
|
|
1782
|
-
// ErrorMetadata::feature_temporarily_unavailable() that typically indicate a deploy just happened
|
|
1783
|
-
VectorIndexesUnavailable: { timeout: 1e3 },
|
|
1784
|
-
SearchIndexesUnavailable: { timeout: 1e3 },
|
|
1785
|
-
TableSummariesUnavailable: { timeout: 1e3 },
|
|
1786
|
-
// More ErrorMetadata::overloaded()
|
|
1787
|
-
VectorIndexTooLarge: { timeout: 3e3 },
|
|
1788
|
-
SearchIndexTooLarge: { timeout: 3e3 },
|
|
1789
|
-
TooManyWritesInTimePeriod: { timeout: 3e3 }
|
|
1790
|
-
};
|
|
1791
|
-
function classifyDisconnectError(s) {
|
|
1792
|
-
if (s === void 0) return "Unknown";
|
|
1793
|
-
for (const prefix of Object.keys(
|
|
1794
|
-
serverDisconnectErrors
|
|
1795
|
-
)) {
|
|
1796
|
-
if (s.startsWith(prefix)) {
|
|
1797
|
-
return prefix;
|
|
1798
|
-
}
|
|
1799
|
-
}
|
|
1800
|
-
return "Unknown";
|
|
1801
|
-
}
|
|
1802
|
-
var WebSocketManager = class {
|
|
1803
|
-
constructor(uri, callbacks, webSocketConstructor, logger, markConnectionStateDirty, debug) {
|
|
1804
|
-
this.markConnectionStateDirty = markConnectionStateDirty;
|
|
1805
|
-
this.debug = debug;
|
|
1806
|
-
__publicField8(this, "socket");
|
|
1807
|
-
__publicField8(this, "connectionCount");
|
|
1808
|
-
__publicField8(this, "_hasEverConnected", false);
|
|
1809
|
-
__publicField8(this, "lastCloseReason");
|
|
1810
|
-
__publicField8(this, "transitionChunkBuffer", null);
|
|
1811
|
-
__publicField8(this, "defaultInitialBackoff");
|
|
1812
|
-
__publicField8(this, "maxBackoff");
|
|
1813
|
-
__publicField8(this, "retries");
|
|
1814
|
-
__publicField8(this, "serverInactivityThreshold");
|
|
1815
|
-
__publicField8(this, "reconnectDueToServerInactivityTimeout");
|
|
1816
|
-
__publicField8(this, "uri");
|
|
1817
|
-
__publicField8(this, "onOpen");
|
|
1818
|
-
__publicField8(this, "onResume");
|
|
1819
|
-
__publicField8(this, "onMessage");
|
|
1820
|
-
__publicField8(this, "webSocketConstructor");
|
|
1821
|
-
__publicField8(this, "logger");
|
|
1822
|
-
__publicField8(this, "onServerDisconnectError");
|
|
1823
|
-
this.webSocketConstructor = webSocketConstructor;
|
|
1824
|
-
this.socket = { state: "disconnected" };
|
|
1825
|
-
this.connectionCount = 0;
|
|
1826
|
-
this.lastCloseReason = "InitialConnect";
|
|
1827
|
-
this.defaultInitialBackoff = 1e3;
|
|
1828
|
-
this.maxBackoff = 16e3;
|
|
1829
|
-
this.retries = 0;
|
|
1830
|
-
this.serverInactivityThreshold = 6e4;
|
|
1831
|
-
this.reconnectDueToServerInactivityTimeout = null;
|
|
1832
|
-
this.uri = uri;
|
|
1833
|
-
this.onOpen = callbacks.onOpen;
|
|
1834
|
-
this.onResume = callbacks.onResume;
|
|
1835
|
-
this.onMessage = callbacks.onMessage;
|
|
1836
|
-
this.onServerDisconnectError = callbacks.onServerDisconnectError;
|
|
1837
|
-
this.logger = logger;
|
|
1838
|
-
this.connect();
|
|
1839
|
-
}
|
|
1840
|
-
setSocketState(state) {
|
|
1841
|
-
this.socket = state;
|
|
1842
|
-
this._logVerbose(
|
|
1843
|
-
`socket state changed: ${this.socket.state}, paused: ${"paused" in this.socket ? this.socket.paused : void 0}`
|
|
1844
|
-
);
|
|
1845
|
-
this.markConnectionStateDirty();
|
|
1846
|
-
}
|
|
1847
|
-
assembleTransition(chunk) {
|
|
1848
|
-
if (chunk.partNumber < 0 || chunk.partNumber >= chunk.totalParts || chunk.totalParts === 0 || this.transitionChunkBuffer && (this.transitionChunkBuffer.totalParts !== chunk.totalParts || this.transitionChunkBuffer.transitionId !== chunk.transitionId)) {
|
|
1849
|
-
this.transitionChunkBuffer = null;
|
|
1850
|
-
throw new Error("Invalid TransitionChunk");
|
|
1851
|
-
}
|
|
1852
|
-
if (this.transitionChunkBuffer === null) {
|
|
1853
|
-
this.transitionChunkBuffer = {
|
|
1854
|
-
chunks: [],
|
|
1855
|
-
totalParts: chunk.totalParts,
|
|
1856
|
-
transitionId: chunk.transitionId
|
|
1857
|
-
};
|
|
1858
|
-
}
|
|
1859
|
-
if (chunk.partNumber !== this.transitionChunkBuffer.chunks.length) {
|
|
1860
|
-
const expectedLength = this.transitionChunkBuffer.chunks.length;
|
|
1861
|
-
this.transitionChunkBuffer = null;
|
|
1862
|
-
throw new Error(
|
|
1863
|
-
`TransitionChunk received out of order: expected part ${expectedLength}, got ${chunk.partNumber}`
|
|
1864
|
-
);
|
|
1865
|
-
}
|
|
1866
|
-
this.transitionChunkBuffer.chunks.push(chunk.chunk);
|
|
1867
|
-
if (this.transitionChunkBuffer.chunks.length === chunk.totalParts) {
|
|
1868
|
-
const fullJson = this.transitionChunkBuffer.chunks.join("");
|
|
1869
|
-
this.transitionChunkBuffer = null;
|
|
1870
|
-
const transition = parseServerMessage(JSON.parse(fullJson));
|
|
1871
|
-
if (transition.type !== "Transition") {
|
|
1872
|
-
throw new Error(
|
|
1873
|
-
`Expected Transition, got ${transition.type} after assembling chunks`
|
|
1874
|
-
);
|
|
1875
|
-
}
|
|
1876
|
-
return transition;
|
|
1877
|
-
}
|
|
1878
|
-
return null;
|
|
1879
|
-
}
|
|
1880
|
-
connect() {
|
|
1881
|
-
if (this.socket.state === "terminated") {
|
|
1882
|
-
return;
|
|
1883
|
-
}
|
|
1884
|
-
if (this.socket.state !== "disconnected" && this.socket.state !== "stopped") {
|
|
1885
|
-
throw new Error(
|
|
1886
|
-
"Didn't start connection from disconnected state: " + this.socket.state
|
|
1887
|
-
);
|
|
1888
|
-
}
|
|
1889
|
-
const ws = new this.webSocketConstructor(this.uri);
|
|
1890
|
-
this._logVerbose("constructed WebSocket");
|
|
1891
|
-
this.setSocketState({
|
|
1892
|
-
state: "connecting",
|
|
1893
|
-
ws,
|
|
1894
|
-
paused: "no"
|
|
1895
|
-
});
|
|
1896
|
-
this.resetServerInactivityTimeout();
|
|
1897
|
-
ws.onopen = () => {
|
|
1898
|
-
this.logger.logVerbose("begin ws.onopen");
|
|
1899
|
-
if (this.socket.state !== "connecting") {
|
|
1900
|
-
throw new Error("onopen called with socket not in connecting state");
|
|
1901
|
-
}
|
|
1902
|
-
this.setSocketState({
|
|
1903
|
-
state: "ready",
|
|
1904
|
-
ws,
|
|
1905
|
-
paused: this.socket.paused === "yes" ? "uninitialized" : "no"
|
|
1906
|
-
});
|
|
1907
|
-
this.resetServerInactivityTimeout();
|
|
1908
|
-
if (this.socket.paused === "no") {
|
|
1909
|
-
this._hasEverConnected = true;
|
|
1910
|
-
this.onOpen({
|
|
1911
|
-
connectionCount: this.connectionCount,
|
|
1912
|
-
lastCloseReason: this.lastCloseReason,
|
|
1913
|
-
clientTs: monotonicMillis()
|
|
1914
|
-
});
|
|
1915
|
-
}
|
|
1916
|
-
if (this.lastCloseReason !== "InitialConnect") {
|
|
1917
|
-
if (this.lastCloseReason) {
|
|
1918
|
-
this.logger.log(
|
|
1919
|
-
"WebSocket reconnected at",
|
|
1920
|
-
prettyNow(),
|
|
1921
|
-
"after disconnect due to",
|
|
1922
|
-
this.lastCloseReason
|
|
1923
|
-
);
|
|
1924
|
-
} else {
|
|
1925
|
-
this.logger.log("WebSocket reconnected at", prettyNow());
|
|
1926
|
-
}
|
|
1927
|
-
}
|
|
1928
|
-
this.connectionCount += 1;
|
|
1929
|
-
this.lastCloseReason = null;
|
|
1930
|
-
};
|
|
1931
|
-
ws.onerror = (error) => {
|
|
1932
|
-
this.transitionChunkBuffer = null;
|
|
1933
|
-
const message = error.message;
|
|
1934
|
-
if (message) {
|
|
1935
|
-
this.logger.log(`WebSocket error message: ${message}`);
|
|
1936
|
-
}
|
|
1937
|
-
};
|
|
1938
|
-
ws.onmessage = (message) => {
|
|
1939
|
-
this.resetServerInactivityTimeout();
|
|
1940
|
-
const messageLength = message.data.length;
|
|
1941
|
-
let serverMessage = parseServerMessage(JSON.parse(message.data));
|
|
1942
|
-
this._logVerbose(`received ws message with type ${serverMessage.type}`);
|
|
1943
|
-
if (serverMessage.type === "Ping") {
|
|
1944
|
-
return;
|
|
1945
|
-
}
|
|
1946
|
-
if (serverMessage.type === "TransitionChunk") {
|
|
1947
|
-
const transition = this.assembleTransition(serverMessage);
|
|
1948
|
-
if (!transition) {
|
|
1949
|
-
return;
|
|
1950
|
-
}
|
|
1951
|
-
serverMessage = transition;
|
|
1952
|
-
this._logVerbose(
|
|
1953
|
-
`assembled full ws message of type ${serverMessage.type}`
|
|
1954
|
-
);
|
|
1955
|
-
}
|
|
1956
|
-
if (this.transitionChunkBuffer !== null) {
|
|
1957
|
-
this.transitionChunkBuffer = null;
|
|
1958
|
-
this.logger.log(
|
|
1959
|
-
`Received unexpected ${serverMessage.type} while buffering TransitionChunks`
|
|
1960
|
-
);
|
|
1961
|
-
}
|
|
1962
|
-
if (serverMessage.type === "Transition") {
|
|
1963
|
-
this.reportLargeTransition({
|
|
1964
|
-
messageLength,
|
|
1965
|
-
transition: serverMessage
|
|
1966
|
-
});
|
|
1967
|
-
}
|
|
1968
|
-
const response = this.onMessage(serverMessage);
|
|
1969
|
-
if (response.hasSyncedPastLastReconnect) {
|
|
1970
|
-
this.retries = 0;
|
|
1971
|
-
this.markConnectionStateDirty();
|
|
1972
|
-
}
|
|
1973
|
-
};
|
|
1974
|
-
ws.onclose = (event) => {
|
|
1975
|
-
this._logVerbose("begin ws.onclose");
|
|
1976
|
-
this.transitionChunkBuffer = null;
|
|
1977
|
-
if (this.lastCloseReason === null) {
|
|
1978
|
-
this.lastCloseReason = event.reason || `closed with code ${event.code}`;
|
|
1979
|
-
}
|
|
1980
|
-
if (event.code !== CLOSE_NORMAL && event.code !== CLOSE_GOING_AWAY && // This commonly gets fired on mobile apps when the app is backgrounded
|
|
1981
|
-
event.code !== CLOSE_NO_STATUS && event.code !== CLOSE_NOT_FOUND) {
|
|
1982
|
-
let msg = `WebSocket closed with code ${event.code}`;
|
|
1983
|
-
if (event.reason) {
|
|
1984
|
-
msg += `: ${event.reason}`;
|
|
1985
|
-
}
|
|
1986
|
-
this.logger.log(msg);
|
|
1987
|
-
if (this.onServerDisconnectError && event.reason) {
|
|
1988
|
-
this.onServerDisconnectError(msg);
|
|
1989
|
-
}
|
|
1990
|
-
}
|
|
1991
|
-
const reason = classifyDisconnectError(event.reason);
|
|
1992
|
-
this.scheduleReconnect(reason);
|
|
1993
|
-
return;
|
|
1994
|
-
};
|
|
1995
|
-
}
|
|
1996
|
-
/**
|
|
1997
|
-
* @returns The state of the {@link Socket}.
|
|
1998
|
-
*/
|
|
1999
|
-
socketState() {
|
|
2000
|
-
return this.socket.state;
|
|
2001
|
-
}
|
|
2002
|
-
/**
|
|
2003
|
-
* @param message - A ClientMessage to send.
|
|
2004
|
-
* @returns Whether the message (might have been) sent.
|
|
2005
|
-
*/
|
|
2006
|
-
sendMessage(message) {
|
|
2007
|
-
const messageForLog = {
|
|
2008
|
-
type: message.type,
|
|
2009
|
-
...message.type === "Authenticate" && message.tokenType === "User" ? {
|
|
2010
|
-
value: `...${message.value.slice(-7)}`
|
|
2011
|
-
} : {}
|
|
2012
|
-
};
|
|
2013
|
-
if (this.socket.state === "ready" && this.socket.paused === "no") {
|
|
2014
|
-
const encodedMessage = encodeClientMessage(message);
|
|
2015
|
-
const request = JSON.stringify(encodedMessage);
|
|
2016
|
-
let sent = false;
|
|
2017
|
-
try {
|
|
2018
|
-
this.socket.ws.send(request);
|
|
2019
|
-
sent = true;
|
|
2020
|
-
} catch (error) {
|
|
2021
|
-
this.logger.log(
|
|
2022
|
-
`Failed to send message on WebSocket, reconnecting: ${error}`
|
|
2023
|
-
);
|
|
2024
|
-
this.closeAndReconnect("FailedToSendMessage");
|
|
2025
|
-
}
|
|
2026
|
-
this._logVerbose(
|
|
2027
|
-
`${sent ? "sent" : "failed to send"} message with type ${message.type}: ${JSON.stringify(
|
|
2028
|
-
messageForLog
|
|
2029
|
-
)}`
|
|
2030
|
-
);
|
|
2031
|
-
return true;
|
|
2032
|
-
}
|
|
2033
|
-
this._logVerbose(
|
|
2034
|
-
`message not sent (socket state: ${this.socket.state}, paused: ${"paused" in this.socket ? this.socket.paused : void 0}): ${JSON.stringify(
|
|
2035
|
-
messageForLog
|
|
2036
|
-
)}`
|
|
2037
|
-
);
|
|
2038
|
-
return false;
|
|
2039
|
-
}
|
|
2040
|
-
resetServerInactivityTimeout() {
|
|
2041
|
-
if (this.socket.state === "terminated") {
|
|
2042
|
-
return;
|
|
2043
|
-
}
|
|
2044
|
-
if (this.reconnectDueToServerInactivityTimeout !== null) {
|
|
2045
|
-
clearTimeout(this.reconnectDueToServerInactivityTimeout);
|
|
2046
|
-
this.reconnectDueToServerInactivityTimeout = null;
|
|
2047
|
-
}
|
|
2048
|
-
this.reconnectDueToServerInactivityTimeout = setTimeout(() => {
|
|
2049
|
-
this.closeAndReconnect("InactiveServer");
|
|
2050
|
-
}, this.serverInactivityThreshold);
|
|
2051
|
-
}
|
|
2052
|
-
scheduleReconnect(reason) {
|
|
2053
|
-
this.socket = { state: "disconnected" };
|
|
2054
|
-
const backoff = this.nextBackoff(reason);
|
|
2055
|
-
this.markConnectionStateDirty();
|
|
2056
|
-
this.logger.log(`Attempting reconnect in ${Math.round(backoff)}ms`);
|
|
2057
|
-
setTimeout(() => this.connect(), backoff);
|
|
2058
|
-
}
|
|
2059
|
-
/**
|
|
2060
|
-
* Close the WebSocket and schedule a reconnect.
|
|
2061
|
-
*
|
|
2062
|
-
* This should be used when we hit an error and would like to restart the session.
|
|
2063
|
-
*/
|
|
2064
|
-
closeAndReconnect(closeReason) {
|
|
2065
|
-
this._logVerbose(`begin closeAndReconnect with reason ${closeReason}`);
|
|
2066
|
-
switch (this.socket.state) {
|
|
2067
|
-
case "disconnected":
|
|
2068
|
-
case "terminated":
|
|
2069
|
-
case "stopped":
|
|
2070
|
-
return;
|
|
2071
|
-
case "connecting":
|
|
2072
|
-
case "ready": {
|
|
2073
|
-
this.lastCloseReason = closeReason;
|
|
2074
|
-
void this.close();
|
|
2075
|
-
this.scheduleReconnect("client");
|
|
2076
|
-
return;
|
|
2077
|
-
}
|
|
2078
|
-
default: {
|
|
2079
|
-
this.socket;
|
|
2080
|
-
}
|
|
2081
|
-
}
|
|
2082
|
-
}
|
|
2083
|
-
/**
|
|
2084
|
-
* Close the WebSocket, being careful to clear the onclose handler to avoid re-entrant
|
|
2085
|
-
* calls. Use this instead of directly calling `ws.close()`
|
|
2086
|
-
*
|
|
2087
|
-
* It is the callers responsibility to update the state after this method is called so that the
|
|
2088
|
-
* closed socket is not accessible or used again after this method is called
|
|
2089
|
-
*/
|
|
2090
|
-
close() {
|
|
2091
|
-
this.transitionChunkBuffer = null;
|
|
2092
|
-
switch (this.socket.state) {
|
|
2093
|
-
case "disconnected":
|
|
2094
|
-
case "terminated":
|
|
2095
|
-
case "stopped":
|
|
2096
|
-
return Promise.resolve();
|
|
2097
|
-
case "connecting": {
|
|
2098
|
-
const ws = this.socket.ws;
|
|
2099
|
-
ws.onmessage = (_message) => {
|
|
2100
|
-
this._logVerbose("Ignoring message received after close");
|
|
2101
|
-
};
|
|
2102
|
-
return new Promise((r) => {
|
|
2103
|
-
ws.onclose = () => {
|
|
2104
|
-
this._logVerbose("Closed after connecting");
|
|
2105
|
-
r();
|
|
2106
|
-
};
|
|
2107
|
-
ws.onopen = () => {
|
|
2108
|
-
this._logVerbose("Opened after connecting");
|
|
2109
|
-
ws.close();
|
|
2110
|
-
};
|
|
2111
|
-
});
|
|
2112
|
-
}
|
|
2113
|
-
case "ready": {
|
|
2114
|
-
this._logVerbose("ws.close called");
|
|
2115
|
-
const ws = this.socket.ws;
|
|
2116
|
-
ws.onmessage = (_message) => {
|
|
2117
|
-
this._logVerbose("Ignoring message received after close");
|
|
2118
|
-
};
|
|
2119
|
-
const result = new Promise((r) => {
|
|
2120
|
-
ws.onclose = () => {
|
|
2121
|
-
r();
|
|
2122
|
-
};
|
|
2123
|
-
});
|
|
2124
|
-
ws.close();
|
|
2125
|
-
return result;
|
|
2126
|
-
}
|
|
2127
|
-
default: {
|
|
2128
|
-
this.socket;
|
|
2129
|
-
return Promise.resolve();
|
|
2130
|
-
}
|
|
2131
|
-
}
|
|
2132
|
-
}
|
|
2133
|
-
/**
|
|
2134
|
-
* Close the WebSocket and do not reconnect.
|
|
2135
|
-
* @returns A Promise that resolves when the WebSocket `onClose` callback is called.
|
|
2136
|
-
*/
|
|
2137
|
-
terminate() {
|
|
2138
|
-
if (this.reconnectDueToServerInactivityTimeout) {
|
|
2139
|
-
clearTimeout(this.reconnectDueToServerInactivityTimeout);
|
|
2140
|
-
}
|
|
2141
|
-
switch (this.socket.state) {
|
|
2142
|
-
case "terminated":
|
|
2143
|
-
case "stopped":
|
|
2144
|
-
case "disconnected":
|
|
2145
|
-
case "connecting":
|
|
2146
|
-
case "ready": {
|
|
2147
|
-
const result = this.close();
|
|
2148
|
-
this.setSocketState({ state: "terminated" });
|
|
2149
|
-
return result;
|
|
2150
|
-
}
|
|
2151
|
-
default: {
|
|
2152
|
-
this.socket;
|
|
2153
|
-
throw new Error(
|
|
2154
|
-
`Invalid websocket state: ${this.socket.state}`
|
|
2155
|
-
);
|
|
2156
|
-
}
|
|
2157
|
-
}
|
|
2158
|
-
}
|
|
2159
|
-
stop() {
|
|
2160
|
-
switch (this.socket.state) {
|
|
2161
|
-
case "terminated":
|
|
2162
|
-
return Promise.resolve();
|
|
2163
|
-
case "connecting":
|
|
2164
|
-
case "stopped":
|
|
2165
|
-
case "disconnected":
|
|
2166
|
-
case "ready": {
|
|
2167
|
-
const result = this.close();
|
|
2168
|
-
this.socket = { state: "stopped" };
|
|
2169
|
-
return result;
|
|
2170
|
-
}
|
|
2171
|
-
default: {
|
|
2172
|
-
this.socket;
|
|
2173
|
-
return Promise.resolve();
|
|
2174
|
-
}
|
|
2175
|
-
}
|
|
2176
|
-
}
|
|
2177
|
-
/**
|
|
2178
|
-
* Create a new WebSocket after a previous `stop()`, unless `terminate()` was
|
|
2179
|
-
* called before.
|
|
2180
|
-
*/
|
|
2181
|
-
tryRestart() {
|
|
2182
|
-
switch (this.socket.state) {
|
|
2183
|
-
case "stopped":
|
|
2184
|
-
break;
|
|
2185
|
-
case "terminated":
|
|
2186
|
-
case "connecting":
|
|
2187
|
-
case "ready":
|
|
2188
|
-
case "disconnected":
|
|
2189
|
-
this.logger.logVerbose("Restart called without stopping first");
|
|
2190
|
-
return;
|
|
2191
|
-
default: {
|
|
2192
|
-
this.socket;
|
|
2193
|
-
}
|
|
2194
|
-
}
|
|
2195
|
-
this.connect();
|
|
2196
|
-
}
|
|
2197
|
-
pause() {
|
|
2198
|
-
switch (this.socket.state) {
|
|
2199
|
-
case "disconnected":
|
|
2200
|
-
case "stopped":
|
|
2201
|
-
case "terminated":
|
|
2202
|
-
return;
|
|
2203
|
-
case "connecting":
|
|
2204
|
-
case "ready": {
|
|
2205
|
-
this.socket = { ...this.socket, paused: "yes" };
|
|
2206
|
-
return;
|
|
2207
|
-
}
|
|
2208
|
-
default: {
|
|
2209
|
-
this.socket;
|
|
2210
|
-
return;
|
|
2211
|
-
}
|
|
2212
|
-
}
|
|
2213
|
-
}
|
|
2214
|
-
/**
|
|
2215
|
-
* Resume the state machine if previously paused.
|
|
2216
|
-
*/
|
|
2217
|
-
resume() {
|
|
2218
|
-
switch (this.socket.state) {
|
|
2219
|
-
case "connecting":
|
|
2220
|
-
this.socket = { ...this.socket, paused: "no" };
|
|
2221
|
-
return;
|
|
2222
|
-
case "ready":
|
|
2223
|
-
if (this.socket.paused === "uninitialized") {
|
|
2224
|
-
this.socket = { ...this.socket, paused: "no" };
|
|
2225
|
-
this.onOpen({
|
|
2226
|
-
connectionCount: this.connectionCount,
|
|
2227
|
-
lastCloseReason: this.lastCloseReason,
|
|
2228
|
-
clientTs: monotonicMillis()
|
|
2229
|
-
});
|
|
2230
|
-
} else if (this.socket.paused === "yes") {
|
|
2231
|
-
this.socket = { ...this.socket, paused: "no" };
|
|
2232
|
-
this.onResume();
|
|
2233
|
-
}
|
|
2234
|
-
return;
|
|
2235
|
-
case "terminated":
|
|
2236
|
-
case "stopped":
|
|
2237
|
-
case "disconnected":
|
|
2238
|
-
return;
|
|
2239
|
-
default: {
|
|
2240
|
-
this.socket;
|
|
2241
|
-
}
|
|
2242
|
-
}
|
|
2243
|
-
this.connect();
|
|
2244
|
-
}
|
|
2245
|
-
connectionState() {
|
|
2246
|
-
return {
|
|
2247
|
-
isConnected: this.socket.state === "ready",
|
|
2248
|
-
hasEverConnected: this._hasEverConnected,
|
|
2249
|
-
connectionCount: this.connectionCount,
|
|
2250
|
-
connectionRetries: this.retries
|
|
2251
|
-
};
|
|
2252
|
-
}
|
|
2253
|
-
_logVerbose(message) {
|
|
2254
|
-
this.logger.logVerbose(message);
|
|
2255
|
-
}
|
|
2256
|
-
nextBackoff(reason) {
|
|
2257
|
-
const initialBackoff = reason === "client" ? 100 : reason === "Unknown" ? this.defaultInitialBackoff : serverDisconnectErrors[reason].timeout;
|
|
2258
|
-
const baseBackoff = initialBackoff * Math.pow(2, this.retries);
|
|
2259
|
-
this.retries += 1;
|
|
2260
|
-
const actualBackoff = Math.min(baseBackoff, this.maxBackoff);
|
|
2261
|
-
const jitter = actualBackoff * (Math.random() - 0.5);
|
|
2262
|
-
return actualBackoff + jitter;
|
|
2263
|
-
}
|
|
2264
|
-
reportLargeTransition({
|
|
2265
|
-
transition,
|
|
2266
|
-
messageLength
|
|
2267
|
-
}) {
|
|
2268
|
-
if (transition.clientClockSkew === void 0 || transition.serverTs === void 0) {
|
|
2269
|
-
return;
|
|
2270
|
-
}
|
|
2271
|
-
const transitionTransitTime = monotonicMillis() - // client time now
|
|
2272
|
-
// clientClockSkew = (server time + upstream latency) - client time
|
|
2273
|
-
// clientClockSkew is "how many milliseconds behind (slow) is the client clock"
|
|
2274
|
-
// but the latency of the Connect message inflates this, making it appear further behind
|
|
2275
|
-
transition.clientClockSkew - transition.serverTs / 1e6;
|
|
2276
|
-
const prettyTransitionTime = `${Math.round(transitionTransitTime)}ms`;
|
|
2277
|
-
const prettyMessageMB = `${Math.round(messageLength / 1e4) / 100}MB`;
|
|
2278
|
-
const bytesPerSecond = messageLength / (transitionTransitTime / 1e3);
|
|
2279
|
-
const prettyBytesPerSecond = `${Math.round(bytesPerSecond / 1e4) / 100}MB per second`;
|
|
2280
|
-
this._logVerbose(
|
|
2281
|
-
`received ${prettyMessageMB} transition in ${prettyTransitionTime} at ${prettyBytesPerSecond}`
|
|
2282
|
-
);
|
|
2283
|
-
if (messageLength > 2e7) {
|
|
2284
|
-
this.logger.log(
|
|
2285
|
-
`received query results totaling more that 20MB (${prettyMessageMB}) which will take a long time to download on slower connections`
|
|
2286
|
-
);
|
|
2287
|
-
} else if (transitionTransitTime > 2e4) {
|
|
2288
|
-
this.logger.log(
|
|
2289
|
-
`received query results totaling ${prettyMessageMB} which took more than 20s to arrive (${prettyTransitionTime})`
|
|
2290
|
-
);
|
|
2291
|
-
}
|
|
2292
|
-
if (this.debug) {
|
|
2293
|
-
this.sendMessage({
|
|
2294
|
-
type: "Event",
|
|
2295
|
-
eventType: "ClientReceivedTransition",
|
|
2296
|
-
event: { transitionTransitTime, messageLength }
|
|
2297
|
-
});
|
|
2298
|
-
}
|
|
2299
|
-
}
|
|
2300
|
-
};
|
|
2301
|
-
|
|
2302
|
-
// node_modules/convex/dist/esm/browser/sync/session.js
|
|
2303
|
-
function newSessionId() {
|
|
2304
|
-
return uuidv4();
|
|
2305
|
-
}
|
|
2306
|
-
function uuidv4() {
|
|
2307
|
-
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
2308
|
-
const r = Math.random() * 16 | 0, v2 = c === "x" ? r : r & 3 | 8;
|
|
2309
|
-
return v2.toString(16);
|
|
2310
|
-
});
|
|
2311
|
-
}
|
|
2312
|
-
|
|
2313
|
-
// node_modules/convex/dist/esm/vendor/jwt-decode/index.js
|
|
2314
|
-
var InvalidTokenError = class extends Error {
|
|
2315
|
-
};
|
|
2316
|
-
InvalidTokenError.prototype.name = "InvalidTokenError";
|
|
2317
|
-
function b64DecodeUnicode(str) {
|
|
2318
|
-
return decodeURIComponent(
|
|
2319
|
-
atob(str).replace(/(.)/g, (_m, p) => {
|
|
2320
|
-
let code2 = p.charCodeAt(0).toString(16).toUpperCase();
|
|
2321
|
-
if (code2.length < 2) {
|
|
2322
|
-
code2 = "0" + code2;
|
|
2323
|
-
}
|
|
2324
|
-
return "%" + code2;
|
|
2325
|
-
})
|
|
2326
|
-
);
|
|
2327
|
-
}
|
|
2328
|
-
function base64UrlDecode(str) {
|
|
2329
|
-
let output = str.replace(/-/g, "+").replace(/_/g, "/");
|
|
2330
|
-
switch (output.length % 4) {
|
|
2331
|
-
case 0:
|
|
2332
|
-
break;
|
|
2333
|
-
case 2:
|
|
2334
|
-
output += "==";
|
|
2335
|
-
break;
|
|
2336
|
-
case 3:
|
|
2337
|
-
output += "=";
|
|
2338
|
-
break;
|
|
2339
|
-
default:
|
|
2340
|
-
throw new Error("base64 string is not of the correct length");
|
|
2341
|
-
}
|
|
2342
|
-
try {
|
|
2343
|
-
return b64DecodeUnicode(output);
|
|
2344
|
-
} catch {
|
|
2345
|
-
return atob(output);
|
|
2346
|
-
}
|
|
2347
|
-
}
|
|
2348
|
-
function jwtDecode(token, options) {
|
|
2349
|
-
if (typeof token !== "string") {
|
|
2350
|
-
throw new InvalidTokenError("Invalid token specified: must be a string");
|
|
2351
|
-
}
|
|
2352
|
-
options || (options = {});
|
|
2353
|
-
const pos = options.header === true ? 0 : 1;
|
|
2354
|
-
const part = token.split(".")[pos];
|
|
2355
|
-
if (typeof part !== "string") {
|
|
2356
|
-
throw new InvalidTokenError(
|
|
2357
|
-
`Invalid token specified: missing part #${pos + 1}`
|
|
2358
|
-
);
|
|
2359
|
-
}
|
|
2360
|
-
let decoded;
|
|
2361
|
-
try {
|
|
2362
|
-
decoded = base64UrlDecode(part);
|
|
2363
|
-
} catch (e) {
|
|
2364
|
-
throw new InvalidTokenError(
|
|
2365
|
-
`Invalid token specified: invalid base64 for part #${pos + 1} (${e.message})`
|
|
2366
|
-
);
|
|
2367
|
-
}
|
|
2368
|
-
try {
|
|
2369
|
-
return JSON.parse(decoded);
|
|
2370
|
-
} catch (e) {
|
|
2371
|
-
throw new InvalidTokenError(
|
|
2372
|
-
`Invalid token specified: invalid json for part #${pos + 1} (${e.message})`
|
|
2373
|
-
);
|
|
2374
|
-
}
|
|
2375
|
-
}
|
|
2376
|
-
|
|
2377
|
-
// node_modules/convex/dist/esm/browser/sync/authentication_manager.js
|
|
2378
|
-
var __defProp10 = Object.defineProperty;
|
|
2379
|
-
var __defNormalProp9 = (obj, key, value) => key in obj ? __defProp10(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
2380
|
-
var __publicField9 = (obj, key, value) => __defNormalProp9(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
2381
|
-
var MAXIMUM_REFRESH_DELAY = 20 * 24 * 60 * 60 * 1e3;
|
|
2382
|
-
var MAX_TOKEN_CONFIRMATION_ATTEMPTS = 2;
|
|
2383
|
-
var AuthenticationManager = class {
|
|
2384
|
-
constructor(syncState, callbacks, config) {
|
|
2385
|
-
__publicField9(this, "authState", { state: "noAuth" });
|
|
2386
|
-
__publicField9(this, "configVersion", 0);
|
|
2387
|
-
__publicField9(this, "syncState");
|
|
2388
|
-
__publicField9(this, "authenticate");
|
|
2389
|
-
__publicField9(this, "stopSocket");
|
|
2390
|
-
__publicField9(this, "tryRestartSocket");
|
|
2391
|
-
__publicField9(this, "pauseSocket");
|
|
2392
|
-
__publicField9(this, "resumeSocket");
|
|
2393
|
-
__publicField9(this, "clearAuth");
|
|
2394
|
-
__publicField9(this, "logger");
|
|
2395
|
-
__publicField9(this, "refreshTokenLeewaySeconds");
|
|
2396
|
-
__publicField9(this, "tokenConfirmationAttempts", 0);
|
|
2397
|
-
this.syncState = syncState;
|
|
2398
|
-
this.authenticate = callbacks.authenticate;
|
|
2399
|
-
this.stopSocket = callbacks.stopSocket;
|
|
2400
|
-
this.tryRestartSocket = callbacks.tryRestartSocket;
|
|
2401
|
-
this.pauseSocket = callbacks.pauseSocket;
|
|
2402
|
-
this.resumeSocket = callbacks.resumeSocket;
|
|
2403
|
-
this.clearAuth = callbacks.clearAuth;
|
|
2404
|
-
this.logger = config.logger;
|
|
2405
|
-
this.refreshTokenLeewaySeconds = config.refreshTokenLeewaySeconds;
|
|
2406
|
-
}
|
|
2407
|
-
async setConfig(fetchToken, onChange) {
|
|
2408
|
-
this.resetAuthState();
|
|
2409
|
-
this._logVerbose("pausing WS for auth token fetch");
|
|
2410
|
-
this.pauseSocket();
|
|
2411
|
-
const token = await this.fetchTokenAndGuardAgainstRace(fetchToken, {
|
|
2412
|
-
forceRefreshToken: false
|
|
2413
|
-
});
|
|
2414
|
-
if (token.isFromOutdatedConfig) {
|
|
2415
|
-
return;
|
|
2416
|
-
}
|
|
2417
|
-
if (token.value) {
|
|
2418
|
-
this.setAuthState({
|
|
2419
|
-
state: "waitingForServerConfirmationOfCachedToken",
|
|
2420
|
-
config: { fetchToken, onAuthChange: onChange },
|
|
2421
|
-
hasRetried: false
|
|
2422
|
-
});
|
|
2423
|
-
this.authenticate(token.value);
|
|
2424
|
-
} else {
|
|
2425
|
-
this.setAuthState({
|
|
2426
|
-
state: "initialRefetch",
|
|
2427
|
-
config: { fetchToken, onAuthChange: onChange }
|
|
2428
|
-
});
|
|
2429
|
-
await this.refetchToken();
|
|
2430
|
-
}
|
|
2431
|
-
this._logVerbose("resuming WS after auth token fetch");
|
|
2432
|
-
this.resumeSocket();
|
|
2433
|
-
}
|
|
2434
|
-
onTransition(serverMessage) {
|
|
2435
|
-
if (!this.syncState.isCurrentOrNewerAuthVersion(
|
|
2436
|
-
serverMessage.endVersion.identity
|
|
2437
|
-
)) {
|
|
2438
|
-
return;
|
|
2439
|
-
}
|
|
2440
|
-
if (serverMessage.endVersion.identity <= serverMessage.startVersion.identity) {
|
|
2441
|
-
return;
|
|
2442
|
-
}
|
|
2443
|
-
if (this.authState.state === "waitingForServerConfirmationOfCachedToken") {
|
|
2444
|
-
this._logVerbose("server confirmed auth token is valid");
|
|
2445
|
-
void this.refetchToken();
|
|
2446
|
-
this.authState.config.onAuthChange(true);
|
|
2447
|
-
return;
|
|
2448
|
-
}
|
|
2449
|
-
if (this.authState.state === "waitingForServerConfirmationOfFreshToken") {
|
|
2450
|
-
this._logVerbose("server confirmed new auth token is valid");
|
|
2451
|
-
this.scheduleTokenRefetch(this.authState.token);
|
|
2452
|
-
this.tokenConfirmationAttempts = 0;
|
|
2453
|
-
if (!this.authState.hadAuth) {
|
|
2454
|
-
this.authState.config.onAuthChange(true);
|
|
2455
|
-
}
|
|
2456
|
-
}
|
|
2457
|
-
}
|
|
2458
|
-
onAuthError(serverMessage) {
|
|
2459
|
-
if (serverMessage.authUpdateAttempted === false && (this.authState.state === "waitingForServerConfirmationOfFreshToken" || this.authState.state === "waitingForServerConfirmationOfCachedToken")) {
|
|
2460
|
-
this._logVerbose("ignoring non-auth token expired error");
|
|
2461
|
-
return;
|
|
2462
|
-
}
|
|
2463
|
-
const { baseVersion } = serverMessage;
|
|
2464
|
-
if (!this.syncState.isCurrentOrNewerAuthVersion(baseVersion + 1)) {
|
|
2465
|
-
this._logVerbose("ignoring auth error for previous auth attempt");
|
|
2466
|
-
return;
|
|
2467
|
-
}
|
|
2468
|
-
void this.tryToReauthenticate(serverMessage);
|
|
2469
|
-
return;
|
|
2470
|
-
}
|
|
2471
|
-
// This is similar to `refetchToken` defined below, in fact we
|
|
2472
|
-
// don't represent them as different states, but it is different
|
|
2473
|
-
// in that we pause the WebSocket so that mutations
|
|
2474
|
-
// don't retry with bad auth.
|
|
2475
|
-
async tryToReauthenticate(serverMessage) {
|
|
2476
|
-
this._logVerbose(`attempting to reauthenticate: ${serverMessage.error}`);
|
|
2477
|
-
if (
|
|
2478
|
-
// No way to fetch another token, kaboom
|
|
2479
|
-
this.authState.state === "noAuth" || // We failed on a fresh token. After a small number of retries, we give up
|
|
2480
|
-
// and clear the auth state to avoid infinite retries.
|
|
2481
|
-
this.authState.state === "waitingForServerConfirmationOfFreshToken" && this.tokenConfirmationAttempts >= MAX_TOKEN_CONFIRMATION_ATTEMPTS
|
|
2482
|
-
) {
|
|
2483
|
-
this.logger.error(
|
|
2484
|
-
`Failed to authenticate: "${serverMessage.error}", check your server auth config`
|
|
2485
|
-
);
|
|
2486
|
-
if (this.syncState.hasAuth()) {
|
|
2487
|
-
this.syncState.clearAuth();
|
|
2488
|
-
}
|
|
2489
|
-
if (this.authState.state !== "noAuth") {
|
|
2490
|
-
this.setAndReportAuthFailed(this.authState.config.onAuthChange);
|
|
2491
|
-
}
|
|
2492
|
-
return;
|
|
2493
|
-
}
|
|
2494
|
-
if (this.authState.state === "waitingForServerConfirmationOfFreshToken") {
|
|
2495
|
-
this.tokenConfirmationAttempts++;
|
|
2496
|
-
this._logVerbose(
|
|
2497
|
-
`retrying reauthentication, ${MAX_TOKEN_CONFIRMATION_ATTEMPTS - this.tokenConfirmationAttempts} attempts remaining`
|
|
2498
|
-
);
|
|
2499
|
-
}
|
|
2500
|
-
await this.stopSocket();
|
|
2501
|
-
const token = await this.fetchTokenAndGuardAgainstRace(
|
|
2502
|
-
this.authState.config.fetchToken,
|
|
2503
|
-
{
|
|
2504
|
-
forceRefreshToken: true
|
|
2505
|
-
}
|
|
2506
|
-
);
|
|
2507
|
-
if (token.isFromOutdatedConfig) {
|
|
2508
|
-
return;
|
|
2509
|
-
}
|
|
2510
|
-
if (token.value && this.syncState.isNewAuth(token.value)) {
|
|
2511
|
-
this.authenticate(token.value);
|
|
2512
|
-
this.setAuthState({
|
|
2513
|
-
state: "waitingForServerConfirmationOfFreshToken",
|
|
2514
|
-
config: this.authState.config,
|
|
2515
|
-
token: token.value,
|
|
2516
|
-
hadAuth: this.authState.state === "notRefetching" || this.authState.state === "waitingForScheduledRefetch"
|
|
2517
|
-
});
|
|
2518
|
-
} else {
|
|
2519
|
-
this._logVerbose("reauthentication failed, could not fetch a new token");
|
|
2520
|
-
if (this.syncState.hasAuth()) {
|
|
2521
|
-
this.syncState.clearAuth();
|
|
2522
|
-
}
|
|
2523
|
-
this.setAndReportAuthFailed(this.authState.config.onAuthChange);
|
|
2524
|
-
}
|
|
2525
|
-
this.tryRestartSocket();
|
|
2526
|
-
}
|
|
2527
|
-
// Force refetch the token and schedule another refetch
|
|
2528
|
-
// before the token expires - an active client should never
|
|
2529
|
-
// need to reauthenticate.
|
|
2530
|
-
async refetchToken() {
|
|
2531
|
-
if (this.authState.state === "noAuth") {
|
|
2532
|
-
return;
|
|
2533
|
-
}
|
|
2534
|
-
this._logVerbose("refetching auth token");
|
|
2535
|
-
const token = await this.fetchTokenAndGuardAgainstRace(
|
|
2536
|
-
this.authState.config.fetchToken,
|
|
2537
|
-
{
|
|
2538
|
-
forceRefreshToken: true
|
|
2539
|
-
}
|
|
2540
|
-
);
|
|
2541
|
-
if (token.isFromOutdatedConfig) {
|
|
2542
|
-
return;
|
|
2543
|
-
}
|
|
2544
|
-
if (token.value) {
|
|
2545
|
-
if (this.syncState.isNewAuth(token.value)) {
|
|
2546
|
-
this.setAuthState({
|
|
2547
|
-
state: "waitingForServerConfirmationOfFreshToken",
|
|
2548
|
-
hadAuth: this.syncState.hasAuth(),
|
|
2549
|
-
token: token.value,
|
|
2550
|
-
config: this.authState.config
|
|
2551
|
-
});
|
|
2552
|
-
this.authenticate(token.value);
|
|
2553
|
-
} else {
|
|
2554
|
-
this.setAuthState({
|
|
2555
|
-
state: "notRefetching",
|
|
2556
|
-
config: this.authState.config
|
|
2557
|
-
});
|
|
2558
|
-
}
|
|
2559
|
-
} else {
|
|
2560
|
-
this._logVerbose("refetching token failed");
|
|
2561
|
-
if (this.syncState.hasAuth()) {
|
|
2562
|
-
this.clearAuth();
|
|
2563
|
-
}
|
|
2564
|
-
this.setAndReportAuthFailed(this.authState.config.onAuthChange);
|
|
2565
|
-
}
|
|
2566
|
-
this._logVerbose(
|
|
2567
|
-
"restarting WS after auth token fetch (if currently stopped)"
|
|
2568
|
-
);
|
|
2569
|
-
this.tryRestartSocket();
|
|
2570
|
-
}
|
|
2571
|
-
scheduleTokenRefetch(token) {
|
|
2572
|
-
if (this.authState.state === "noAuth") {
|
|
2573
|
-
return;
|
|
2574
|
-
}
|
|
2575
|
-
const decodedToken = this.decodeToken(token);
|
|
2576
|
-
if (!decodedToken) {
|
|
2577
|
-
this.logger.error(
|
|
2578
|
-
"Auth token is not a valid JWT, cannot refetch the token"
|
|
2579
|
-
);
|
|
2580
|
-
return;
|
|
2581
|
-
}
|
|
2582
|
-
const { iat, exp } = decodedToken;
|
|
2583
|
-
if (!iat || !exp) {
|
|
2584
|
-
this.logger.error(
|
|
2585
|
-
"Auth token does not have required fields, cannot refetch the token"
|
|
2586
|
-
);
|
|
2587
|
-
return;
|
|
2588
|
-
}
|
|
2589
|
-
const tokenValiditySeconds = exp - iat;
|
|
2590
|
-
if (tokenValiditySeconds <= 2) {
|
|
2591
|
-
this.logger.error(
|
|
2592
|
-
"Auth token does not live long enough, cannot refetch the token"
|
|
2593
|
-
);
|
|
2594
|
-
return;
|
|
2595
|
-
}
|
|
2596
|
-
let delay = Math.min(
|
|
2597
|
-
MAXIMUM_REFRESH_DELAY,
|
|
2598
|
-
(tokenValiditySeconds - this.refreshTokenLeewaySeconds) * 1e3
|
|
2599
|
-
);
|
|
2600
|
-
if (delay <= 0) {
|
|
2601
|
-
this.logger.warn(
|
|
2602
|
-
`Refetching auth token immediately, configured leeway ${this.refreshTokenLeewaySeconds}s is larger than the token's lifetime ${tokenValiditySeconds}s`
|
|
2603
|
-
);
|
|
2604
|
-
delay = 0;
|
|
2605
|
-
}
|
|
2606
|
-
const refetchTokenTimeoutId = setTimeout(() => {
|
|
2607
|
-
this._logVerbose("running scheduled token refetch");
|
|
2608
|
-
void this.refetchToken();
|
|
2609
|
-
}, delay);
|
|
2610
|
-
this.setAuthState({
|
|
2611
|
-
state: "waitingForScheduledRefetch",
|
|
2612
|
-
refetchTokenTimeoutId,
|
|
2613
|
-
config: this.authState.config
|
|
2614
|
-
});
|
|
2615
|
-
this._logVerbose(
|
|
2616
|
-
`scheduled preemptive auth token refetching in ${delay}ms`
|
|
2617
|
-
);
|
|
2618
|
-
}
|
|
2619
|
-
// Protects against simultaneous calls to `setConfig`
|
|
2620
|
-
// while we're fetching a token
|
|
2621
|
-
async fetchTokenAndGuardAgainstRace(fetchToken, fetchArgs) {
|
|
2622
|
-
const originalConfigVersion = ++this.configVersion;
|
|
2623
|
-
this._logVerbose(
|
|
2624
|
-
`fetching token with config version ${originalConfigVersion}`
|
|
2625
|
-
);
|
|
2626
|
-
const token = await fetchToken(fetchArgs);
|
|
2627
|
-
if (this.configVersion !== originalConfigVersion) {
|
|
2628
|
-
this._logVerbose(
|
|
2629
|
-
`stale config version, expected ${originalConfigVersion}, got ${this.configVersion}`
|
|
2630
|
-
);
|
|
2631
|
-
return { isFromOutdatedConfig: true };
|
|
2632
|
-
}
|
|
2633
|
-
return { isFromOutdatedConfig: false, value: token };
|
|
2634
|
-
}
|
|
2635
|
-
stop() {
|
|
2636
|
-
this.resetAuthState();
|
|
2637
|
-
this.configVersion++;
|
|
2638
|
-
this._logVerbose(`config version bumped to ${this.configVersion}`);
|
|
2639
|
-
}
|
|
2640
|
-
setAndReportAuthFailed(onAuthChange) {
|
|
2641
|
-
onAuthChange(false);
|
|
2642
|
-
this.resetAuthState();
|
|
2643
|
-
}
|
|
2644
|
-
resetAuthState() {
|
|
2645
|
-
this.setAuthState({ state: "noAuth" });
|
|
2646
|
-
}
|
|
2647
|
-
setAuthState(newAuth) {
|
|
2648
|
-
const authStateForLog = newAuth.state === "waitingForServerConfirmationOfFreshToken" ? {
|
|
2649
|
-
hadAuth: newAuth.hadAuth,
|
|
2650
|
-
state: newAuth.state,
|
|
2651
|
-
token: `...${newAuth.token.slice(-7)}`
|
|
2652
|
-
} : { state: newAuth.state };
|
|
2653
|
-
this._logVerbose(
|
|
2654
|
-
`setting auth state to ${JSON.stringify(authStateForLog)}`
|
|
2655
|
-
);
|
|
2656
|
-
switch (newAuth.state) {
|
|
2657
|
-
case "waitingForScheduledRefetch":
|
|
2658
|
-
case "notRefetching":
|
|
2659
|
-
case "noAuth":
|
|
2660
|
-
this.tokenConfirmationAttempts = 0;
|
|
2661
|
-
break;
|
|
2662
|
-
case "waitingForServerConfirmationOfFreshToken":
|
|
2663
|
-
case "waitingForServerConfirmationOfCachedToken":
|
|
2664
|
-
case "initialRefetch":
|
|
2665
|
-
break;
|
|
2666
|
-
default: {
|
|
2667
|
-
newAuth;
|
|
2668
|
-
}
|
|
2669
|
-
}
|
|
2670
|
-
if (this.authState.state === "waitingForScheduledRefetch") {
|
|
2671
|
-
clearTimeout(this.authState.refetchTokenTimeoutId);
|
|
2672
|
-
this.syncState.markAuthCompletion();
|
|
2673
|
-
}
|
|
2674
|
-
this.authState = newAuth;
|
|
2675
|
-
}
|
|
2676
|
-
decodeToken(token) {
|
|
2677
|
-
try {
|
|
2678
|
-
return jwtDecode(token);
|
|
2679
|
-
} catch (e) {
|
|
2680
|
-
this._logVerbose(
|
|
2681
|
-
`Error decoding token: ${e instanceof Error ? e.message : "Unknown error"}`
|
|
2682
|
-
);
|
|
2683
|
-
return null;
|
|
2684
|
-
}
|
|
2685
|
-
}
|
|
2686
|
-
_logVerbose(message) {
|
|
2687
|
-
this.logger.logVerbose(`${message} [v${this.configVersion}]`);
|
|
2688
|
-
}
|
|
2689
|
-
};
|
|
2690
|
-
|
|
2691
|
-
// node_modules/convex/dist/esm/browser/sync/metrics.js
|
|
2692
|
-
var markNames = [
|
|
2693
|
-
"convexClientConstructed",
|
|
2694
|
-
"convexWebSocketOpen",
|
|
2695
|
-
"convexFirstMessageReceived"
|
|
2696
|
-
];
|
|
2697
|
-
function mark(name, sessionId) {
|
|
2698
|
-
const detail = { sessionId };
|
|
2699
|
-
if (typeof performance === "undefined" || !performance.mark) return;
|
|
2700
|
-
performance.mark(name, { detail });
|
|
2701
|
-
}
|
|
2702
|
-
function performanceMarkToJson(mark2) {
|
|
2703
|
-
let name = mark2.name.slice("convex".length);
|
|
2704
|
-
name = name.charAt(0).toLowerCase() + name.slice(1);
|
|
2705
|
-
return {
|
|
2706
|
-
name,
|
|
2707
|
-
startTime: mark2.startTime
|
|
2708
|
-
};
|
|
2709
|
-
}
|
|
2710
|
-
function getMarksReport(sessionId) {
|
|
2711
|
-
if (typeof performance === "undefined" || !performance.getEntriesByName) {
|
|
2712
|
-
return [];
|
|
2713
|
-
}
|
|
2714
|
-
const allMarks = [];
|
|
2715
|
-
for (const name of markNames) {
|
|
2716
|
-
const marks = performance.getEntriesByName(name).filter((entry) => entry.entryType === "mark").filter((mark2) => mark2.detail.sessionId === sessionId);
|
|
2717
|
-
allMarks.push(...marks);
|
|
2718
|
-
}
|
|
2719
|
-
return allMarks.map(performanceMarkToJson);
|
|
2720
|
-
}
|
|
2721
|
-
|
|
2722
|
-
// node_modules/convex/dist/esm/browser/sync/client.js
|
|
2723
|
-
var __defProp11 = Object.defineProperty;
|
|
2724
|
-
var __defNormalProp10 = (obj, key, value) => key in obj ? __defProp11(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
2725
|
-
var __publicField10 = (obj, key, value) => __defNormalProp10(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
2726
|
-
var BaseConvexClient = class {
|
|
2727
|
-
/**
|
|
2728
|
-
* @param address - The url of your Convex deployment, often provided
|
|
2729
|
-
* by an environment variable. E.g. `https://small-mouse-123.convex.cloud`.
|
|
2730
|
-
* @param onTransition - A callback receiving an array of query tokens
|
|
2731
|
-
* corresponding to query results that have changed -- additional handlers
|
|
2732
|
-
* can be added via `addOnTransitionHandler`.
|
|
2733
|
-
* @param options - See {@link BaseConvexClientOptions} for a full description.
|
|
2734
|
-
*/
|
|
2735
|
-
constructor(address, onTransition, options) {
|
|
2736
|
-
__publicField10(this, "address");
|
|
2737
|
-
__publicField10(this, "state");
|
|
2738
|
-
__publicField10(this, "requestManager");
|
|
2739
|
-
__publicField10(this, "webSocketManager");
|
|
2740
|
-
__publicField10(this, "authenticationManager");
|
|
2741
|
-
__publicField10(this, "remoteQuerySet");
|
|
2742
|
-
__publicField10(this, "optimisticQueryResults");
|
|
2743
|
-
__publicField10(this, "_transitionHandlerCounter", 0);
|
|
2744
|
-
__publicField10(this, "_nextRequestId");
|
|
2745
|
-
__publicField10(this, "_onTransitionFns", /* @__PURE__ */ new Map());
|
|
2746
|
-
__publicField10(this, "_sessionId");
|
|
2747
|
-
__publicField10(this, "firstMessageReceived", false);
|
|
2748
|
-
__publicField10(this, "debug");
|
|
2749
|
-
__publicField10(this, "logger");
|
|
2750
|
-
__publicField10(this, "maxObservedTimestamp");
|
|
2751
|
-
__publicField10(this, "connectionStateSubscribers", /* @__PURE__ */ new Map());
|
|
2752
|
-
__publicField10(this, "nextConnectionStateSubscriberId", 0);
|
|
2753
|
-
__publicField10(this, "_lastPublishedConnectionState");
|
|
2754
|
-
__publicField10(this, "markConnectionStateDirty", () => {
|
|
2755
|
-
void Promise.resolve().then(() => {
|
|
2756
|
-
const curConnectionState = this.connectionState();
|
|
2757
|
-
if (JSON.stringify(curConnectionState) !== JSON.stringify(this._lastPublishedConnectionState)) {
|
|
2758
|
-
this._lastPublishedConnectionState = curConnectionState;
|
|
2759
|
-
for (const cb of this.connectionStateSubscribers.values()) {
|
|
2760
|
-
cb(curConnectionState);
|
|
2761
|
-
}
|
|
2762
|
-
}
|
|
2763
|
-
});
|
|
2764
|
-
});
|
|
2765
|
-
__publicField10(this, "mark", (name) => {
|
|
2766
|
-
if (this.debug) {
|
|
2767
|
-
mark(name, this.sessionId);
|
|
2768
|
-
}
|
|
2769
|
-
});
|
|
2770
|
-
if (typeof address === "object") {
|
|
2771
|
-
throw new Error(
|
|
2772
|
-
"Passing a ClientConfig object is no longer supported. Pass the URL of the Convex deployment as a string directly."
|
|
2773
|
-
);
|
|
2774
|
-
}
|
|
2775
|
-
if (options?.skipConvexDeploymentUrlCheck !== true) {
|
|
2776
|
-
validateDeploymentUrl(address);
|
|
2777
|
-
}
|
|
2778
|
-
options = { ...options };
|
|
2779
|
-
const authRefreshTokenLeewaySeconds = options.authRefreshTokenLeewaySeconds ?? 2;
|
|
2780
|
-
let webSocketConstructor = options.webSocketConstructor;
|
|
2781
|
-
if (!webSocketConstructor && typeof WebSocket === "undefined") {
|
|
2782
|
-
throw new Error(
|
|
2783
|
-
"No WebSocket global variable defined! To use Convex in an environment without WebSocket try the HTTP client: https://docs.convex.dev/api/classes/browser.ConvexHttpClient"
|
|
2784
|
-
);
|
|
2785
|
-
}
|
|
2786
|
-
webSocketConstructor = webSocketConstructor || WebSocket;
|
|
2787
|
-
this.debug = options.reportDebugInfoToConvex ?? false;
|
|
2788
|
-
this.address = address;
|
|
2789
|
-
this.logger = options.logger === false ? instantiateNoopLogger({ verbose: options.verbose ?? false }) : options.logger !== true && options.logger ? options.logger : instantiateDefaultLogger({ verbose: options.verbose ?? false });
|
|
2790
|
-
const i = address.search("://");
|
|
2791
|
-
if (i === -1) {
|
|
2792
|
-
throw new Error("Provided address was not an absolute URL.");
|
|
2793
|
-
}
|
|
2794
|
-
const origin = address.substring(i + 3);
|
|
2795
|
-
const protocol = address.substring(0, i);
|
|
2796
|
-
let wsProtocol;
|
|
2797
|
-
if (protocol === "http") {
|
|
2798
|
-
wsProtocol = "ws";
|
|
2799
|
-
} else if (protocol === "https") {
|
|
2800
|
-
wsProtocol = "wss";
|
|
2801
|
-
} else {
|
|
2802
|
-
throw new Error(`Unknown parent protocol ${protocol}`);
|
|
2803
|
-
}
|
|
2804
|
-
const wsUri = `${wsProtocol}://${origin}/api/${version}/sync`;
|
|
2805
|
-
this.state = new LocalSyncState();
|
|
2806
|
-
this.remoteQuerySet = new RemoteQuerySet(
|
|
2807
|
-
(queryId) => this.state.queryPath(queryId),
|
|
2808
|
-
this.logger
|
|
2809
|
-
);
|
|
2810
|
-
this.requestManager = new RequestManager(
|
|
2811
|
-
this.logger,
|
|
2812
|
-
this.markConnectionStateDirty
|
|
2813
|
-
);
|
|
2814
|
-
const pauseSocket = () => {
|
|
2815
|
-
this.webSocketManager.pause();
|
|
2816
|
-
this.state.pause();
|
|
2817
|
-
};
|
|
2818
|
-
this.authenticationManager = new AuthenticationManager(
|
|
2819
|
-
this.state,
|
|
2820
|
-
{
|
|
2821
|
-
authenticate: (token) => {
|
|
2822
|
-
const message = this.state.setAuth(token);
|
|
2823
|
-
this.webSocketManager.sendMessage(message);
|
|
2824
|
-
return message.baseVersion;
|
|
2825
|
-
},
|
|
2826
|
-
stopSocket: () => this.webSocketManager.stop(),
|
|
2827
|
-
tryRestartSocket: () => this.webSocketManager.tryRestart(),
|
|
2828
|
-
pauseSocket,
|
|
2829
|
-
resumeSocket: () => this.webSocketManager.resume(),
|
|
2830
|
-
clearAuth: () => {
|
|
2831
|
-
this.clearAuth();
|
|
2832
|
-
}
|
|
2833
|
-
},
|
|
2834
|
-
{
|
|
2835
|
-
logger: this.logger,
|
|
2836
|
-
refreshTokenLeewaySeconds: authRefreshTokenLeewaySeconds
|
|
2837
|
-
}
|
|
2838
|
-
);
|
|
2839
|
-
this.optimisticQueryResults = new OptimisticQueryResults();
|
|
2840
|
-
this.addOnTransitionHandler((transition) => {
|
|
2841
|
-
onTransition(transition.queries.map((q) => q.token));
|
|
2842
|
-
});
|
|
2843
|
-
this._nextRequestId = 0;
|
|
2844
|
-
this._sessionId = newSessionId();
|
|
2845
|
-
const { unsavedChangesWarning } = options;
|
|
2846
|
-
if (typeof window === "undefined" || typeof window.addEventListener === "undefined") {
|
|
2847
|
-
if (unsavedChangesWarning === true) {
|
|
2848
|
-
throw new Error(
|
|
2849
|
-
"unsavedChangesWarning requested, but window.addEventListener not found! Remove {unsavedChangesWarning: true} from Convex client options."
|
|
2850
|
-
);
|
|
2851
|
-
}
|
|
2852
|
-
} else if (unsavedChangesWarning !== false) {
|
|
2853
|
-
window.addEventListener("beforeunload", (e) => {
|
|
2854
|
-
if (this.requestManager.hasIncompleteRequests()) {
|
|
2855
|
-
e.preventDefault();
|
|
2856
|
-
const confirmationMessage = "Are you sure you want to leave? Your changes may not be saved.";
|
|
2857
|
-
(e || window.event).returnValue = confirmationMessage;
|
|
2858
|
-
return confirmationMessage;
|
|
2859
|
-
}
|
|
2860
|
-
});
|
|
2861
|
-
}
|
|
2862
|
-
this.webSocketManager = new WebSocketManager(
|
|
2863
|
-
wsUri,
|
|
2864
|
-
{
|
|
2865
|
-
onOpen: (reconnectMetadata) => {
|
|
2866
|
-
this.mark("convexWebSocketOpen");
|
|
2867
|
-
this.webSocketManager.sendMessage({
|
|
2868
|
-
...reconnectMetadata,
|
|
2869
|
-
type: "Connect",
|
|
2870
|
-
sessionId: this._sessionId,
|
|
2871
|
-
maxObservedTimestamp: this.maxObservedTimestamp
|
|
2872
|
-
});
|
|
2873
|
-
const oldRemoteQueryResults = new Set(
|
|
2874
|
-
this.remoteQuerySet.remoteQueryResults().keys()
|
|
2875
|
-
);
|
|
2876
|
-
this.remoteQuerySet = new RemoteQuerySet(
|
|
2877
|
-
(queryId) => this.state.queryPath(queryId),
|
|
2878
|
-
this.logger
|
|
2879
|
-
);
|
|
2880
|
-
const [querySetModification, authModification] = this.state.restart(
|
|
2881
|
-
oldRemoteQueryResults
|
|
2882
|
-
);
|
|
2883
|
-
if (authModification) {
|
|
2884
|
-
this.webSocketManager.sendMessage(authModification);
|
|
2885
|
-
}
|
|
2886
|
-
this.webSocketManager.sendMessage(querySetModification);
|
|
2887
|
-
for (const message of this.requestManager.restart()) {
|
|
2888
|
-
this.webSocketManager.sendMessage(message);
|
|
2889
|
-
}
|
|
2890
|
-
},
|
|
2891
|
-
onResume: () => {
|
|
2892
|
-
const [querySetModification, authModification] = this.state.resume();
|
|
2893
|
-
if (authModification) {
|
|
2894
|
-
this.webSocketManager.sendMessage(authModification);
|
|
2895
|
-
}
|
|
2896
|
-
if (querySetModification) {
|
|
2897
|
-
this.webSocketManager.sendMessage(querySetModification);
|
|
2898
|
-
}
|
|
2899
|
-
for (const message of this.requestManager.resume()) {
|
|
2900
|
-
this.webSocketManager.sendMessage(message);
|
|
2901
|
-
}
|
|
2902
|
-
},
|
|
2903
|
-
onMessage: (serverMessage) => {
|
|
2904
|
-
if (!this.firstMessageReceived) {
|
|
2905
|
-
this.firstMessageReceived = true;
|
|
2906
|
-
this.mark("convexFirstMessageReceived");
|
|
2907
|
-
this.reportMarks();
|
|
2908
|
-
}
|
|
2909
|
-
switch (serverMessage.type) {
|
|
2910
|
-
case "Transition": {
|
|
2911
|
-
this.observedTimestamp(serverMessage.endVersion.ts);
|
|
2912
|
-
this.authenticationManager.onTransition(serverMessage);
|
|
2913
|
-
this.remoteQuerySet.transition(serverMessage);
|
|
2914
|
-
this.state.transition(serverMessage);
|
|
2915
|
-
const completedRequests = this.requestManager.removeCompleted(
|
|
2916
|
-
this.remoteQuerySet.timestamp()
|
|
2917
|
-
);
|
|
2918
|
-
this.notifyOnQueryResultChanges(completedRequests);
|
|
2919
|
-
break;
|
|
2920
|
-
}
|
|
2921
|
-
case "MutationResponse": {
|
|
2922
|
-
if (serverMessage.success) {
|
|
2923
|
-
this.observedTimestamp(serverMessage.ts);
|
|
2924
|
-
}
|
|
2925
|
-
const completedMutationInfo = this.requestManager.onResponse(serverMessage);
|
|
2926
|
-
if (completedMutationInfo !== null) {
|
|
2927
|
-
this.notifyOnQueryResultChanges(
|
|
2928
|
-
/* @__PURE__ */ new Map([
|
|
2929
|
-
[
|
|
2930
|
-
completedMutationInfo.requestId,
|
|
2931
|
-
completedMutationInfo.result
|
|
2932
|
-
]
|
|
2933
|
-
])
|
|
2934
|
-
);
|
|
2935
|
-
}
|
|
2936
|
-
break;
|
|
2937
|
-
}
|
|
2938
|
-
case "ActionResponse": {
|
|
2939
|
-
this.requestManager.onResponse(serverMessage);
|
|
2940
|
-
break;
|
|
2941
|
-
}
|
|
2942
|
-
case "AuthError": {
|
|
2943
|
-
this.authenticationManager.onAuthError(serverMessage);
|
|
2944
|
-
break;
|
|
2945
|
-
}
|
|
2946
|
-
case "FatalError": {
|
|
2947
|
-
const error = logFatalError(this.logger, serverMessage.error);
|
|
2948
|
-
void this.webSocketManager.terminate();
|
|
2949
|
-
throw error;
|
|
2950
|
-
}
|
|
2951
|
-
default: {
|
|
2952
|
-
serverMessage;
|
|
2953
|
-
}
|
|
2954
|
-
}
|
|
2955
|
-
return {
|
|
2956
|
-
hasSyncedPastLastReconnect: this.hasSyncedPastLastReconnect()
|
|
2957
|
-
};
|
|
2958
|
-
},
|
|
2959
|
-
onServerDisconnectError: options.onServerDisconnectError
|
|
2960
|
-
},
|
|
2961
|
-
webSocketConstructor,
|
|
2962
|
-
this.logger,
|
|
2963
|
-
this.markConnectionStateDirty,
|
|
2964
|
-
this.debug
|
|
2965
|
-
);
|
|
2966
|
-
this.mark("convexClientConstructed");
|
|
2967
|
-
if (options.expectAuth) {
|
|
2968
|
-
pauseSocket();
|
|
2969
|
-
}
|
|
2970
|
-
}
|
|
2971
|
-
/**
|
|
2972
|
-
* Return true if there is outstanding work from prior to the time of the most recent restart.
|
|
2973
|
-
* This indicates that the client has not proven itself to have gotten past the issue that
|
|
2974
|
-
* potentially led to the restart. Use this to influence when to reset backoff after a failure.
|
|
2975
|
-
*/
|
|
2976
|
-
hasSyncedPastLastReconnect() {
|
|
2977
|
-
const hasSyncedPastLastReconnect = this.requestManager.hasSyncedPastLastReconnect() || this.state.hasSyncedPastLastReconnect();
|
|
2978
|
-
return hasSyncedPastLastReconnect;
|
|
2979
|
-
}
|
|
2980
|
-
observedTimestamp(observedTs) {
|
|
2981
|
-
if (this.maxObservedTimestamp === void 0 || this.maxObservedTimestamp.lessThanOrEqual(observedTs)) {
|
|
2982
|
-
this.maxObservedTimestamp = observedTs;
|
|
2983
|
-
}
|
|
2984
|
-
}
|
|
2985
|
-
getMaxObservedTimestamp() {
|
|
2986
|
-
return this.maxObservedTimestamp;
|
|
2987
|
-
}
|
|
2988
|
-
/**
|
|
2989
|
-
* Compute the current query results based on the remoteQuerySet and the
|
|
2990
|
-
* current optimistic updates and call `onTransition` for all the changed
|
|
2991
|
-
* queries.
|
|
2992
|
-
*
|
|
2993
|
-
* @param completedMutations - A set of mutation IDs whose optimistic updates
|
|
2994
|
-
* are no longer needed.
|
|
2995
|
-
*/
|
|
2996
|
-
notifyOnQueryResultChanges(completedRequests) {
|
|
2997
|
-
const remoteQueryResults = this.remoteQuerySet.remoteQueryResults();
|
|
2998
|
-
const queryTokenToValue = /* @__PURE__ */ new Map();
|
|
2999
|
-
for (const [queryId, result] of remoteQueryResults) {
|
|
3000
|
-
const queryToken = this.state.queryToken(queryId);
|
|
3001
|
-
if (queryToken !== null) {
|
|
3002
|
-
const query = {
|
|
3003
|
-
result,
|
|
3004
|
-
udfPath: this.state.queryPath(queryId),
|
|
3005
|
-
args: this.state.queryArgs(queryId)
|
|
3006
|
-
};
|
|
3007
|
-
queryTokenToValue.set(queryToken, query);
|
|
3008
|
-
}
|
|
3009
|
-
}
|
|
3010
|
-
const changedQueryTokens = this.optimisticQueryResults.ingestQueryResultsFromServer(
|
|
3011
|
-
queryTokenToValue,
|
|
3012
|
-
new Set(completedRequests.keys())
|
|
3013
|
-
);
|
|
3014
|
-
this.handleTransition({
|
|
3015
|
-
queries: changedQueryTokens.map((token) => {
|
|
3016
|
-
const optimisticResult = this.optimisticQueryResults.rawQueryResult(token);
|
|
3017
|
-
return {
|
|
3018
|
-
token,
|
|
3019
|
-
modification: {
|
|
3020
|
-
kind: "Updated",
|
|
3021
|
-
result: optimisticResult
|
|
3022
|
-
}
|
|
3023
|
-
};
|
|
3024
|
-
}),
|
|
3025
|
-
reflectedMutations: Array.from(completedRequests).map(
|
|
3026
|
-
([requestId, result]) => ({
|
|
3027
|
-
requestId,
|
|
3028
|
-
result
|
|
3029
|
-
})
|
|
3030
|
-
),
|
|
3031
|
-
timestamp: this.remoteQuerySet.timestamp()
|
|
3032
|
-
});
|
|
3033
|
-
}
|
|
3034
|
-
handleTransition(transition) {
|
|
3035
|
-
for (const fn of this._onTransitionFns.values()) {
|
|
3036
|
-
fn(transition);
|
|
3037
|
-
}
|
|
3038
|
-
}
|
|
3039
|
-
/**
|
|
3040
|
-
* Add a handler that will be called on a transition.
|
|
3041
|
-
*
|
|
3042
|
-
* Any external side effects (e.g. setting React state) should be handled here.
|
|
3043
|
-
*
|
|
3044
|
-
* @param fn
|
|
3045
|
-
*
|
|
3046
|
-
* @returns
|
|
3047
|
-
*/
|
|
3048
|
-
addOnTransitionHandler(fn) {
|
|
3049
|
-
const id = this._transitionHandlerCounter++;
|
|
3050
|
-
this._onTransitionFns.set(id, fn);
|
|
3051
|
-
return () => this._onTransitionFns.delete(id);
|
|
3052
|
-
}
|
|
3053
|
-
/**
|
|
3054
|
-
* Get the current JWT auth token and decoded claims.
|
|
3055
|
-
*/
|
|
3056
|
-
getCurrentAuthClaims() {
|
|
3057
|
-
const authToken = this.state.getAuth();
|
|
3058
|
-
let decoded = {};
|
|
3059
|
-
if (authToken && authToken.tokenType === "User") {
|
|
3060
|
-
try {
|
|
3061
|
-
decoded = authToken ? jwtDecode(authToken.value) : {};
|
|
3062
|
-
} catch {
|
|
3063
|
-
decoded = {};
|
|
3064
|
-
}
|
|
3065
|
-
} else {
|
|
3066
|
-
return void 0;
|
|
3067
|
-
}
|
|
3068
|
-
return { token: authToken.value, decoded };
|
|
3069
|
-
}
|
|
3070
|
-
/**
|
|
3071
|
-
* Set the authentication token to be used for subsequent queries and mutations.
|
|
3072
|
-
* `fetchToken` will be called automatically again if a token expires.
|
|
3073
|
-
* `fetchToken` should return `null` if the token cannot be retrieved, for example
|
|
3074
|
-
* when the user's rights were permanently revoked.
|
|
3075
|
-
* @param fetchToken - an async function returning the JWT-encoded OpenID Connect Identity Token
|
|
3076
|
-
* @param onChange - a callback that will be called when the authentication status changes
|
|
3077
|
-
*/
|
|
3078
|
-
setAuth(fetchToken, onChange) {
|
|
3079
|
-
void this.authenticationManager.setConfig(fetchToken, onChange);
|
|
3080
|
-
}
|
|
3081
|
-
hasAuth() {
|
|
3082
|
-
return this.state.hasAuth();
|
|
3083
|
-
}
|
|
3084
|
-
/** @internal */
|
|
3085
|
-
setAdminAuth(value, fakeUserIdentity) {
|
|
3086
|
-
const message = this.state.setAdminAuth(value, fakeUserIdentity);
|
|
3087
|
-
this.webSocketManager.sendMessage(message);
|
|
3088
|
-
}
|
|
3089
|
-
clearAuth() {
|
|
3090
|
-
const message = this.state.clearAuth();
|
|
3091
|
-
this.webSocketManager.sendMessage(message);
|
|
3092
|
-
}
|
|
3093
|
-
/**
|
|
3094
|
-
* Subscribe to a query function.
|
|
3095
|
-
*
|
|
3096
|
-
* Whenever this query's result changes, the `onTransition` callback
|
|
3097
|
-
* passed into the constructor will be called.
|
|
3098
|
-
*
|
|
3099
|
-
* @param name - The name of the query.
|
|
3100
|
-
* @param args - An arguments object for the query. If this is omitted, the
|
|
3101
|
-
* arguments will be `{}`.
|
|
3102
|
-
* @param options - A {@link SubscribeOptions} options object for this query.
|
|
3103
|
-
|
|
3104
|
-
* @returns An object containing a {@link QueryToken} corresponding to this
|
|
3105
|
-
* query and an `unsubscribe` callback.
|
|
3106
|
-
*/
|
|
3107
|
-
subscribe(name, args, options) {
|
|
3108
|
-
const argsObject = parseArgs(args);
|
|
3109
|
-
const { modification, queryToken, unsubscribe } = this.state.subscribe(
|
|
3110
|
-
name,
|
|
3111
|
-
argsObject,
|
|
3112
|
-
options?.journal,
|
|
3113
|
-
options?.componentPath
|
|
3114
|
-
);
|
|
3115
|
-
if (modification !== null) {
|
|
3116
|
-
this.webSocketManager.sendMessage(modification);
|
|
3117
|
-
}
|
|
3118
|
-
return {
|
|
3119
|
-
queryToken,
|
|
3120
|
-
unsubscribe: () => {
|
|
3121
|
-
const modification2 = unsubscribe();
|
|
3122
|
-
if (modification2) {
|
|
3123
|
-
this.webSocketManager.sendMessage(modification2);
|
|
3124
|
-
}
|
|
3125
|
-
}
|
|
3126
|
-
};
|
|
3127
|
-
}
|
|
3128
|
-
/**
|
|
3129
|
-
* A query result based only on the current, local state.
|
|
3130
|
-
*
|
|
3131
|
-
* The only way this will return a value is if we're already subscribed to the
|
|
3132
|
-
* query or its value has been set optimistically.
|
|
3133
|
-
*/
|
|
3134
|
-
localQueryResult(udfPath, args) {
|
|
3135
|
-
const argsObject = parseArgs(args);
|
|
3136
|
-
const queryToken = serializePathAndArgs(udfPath, argsObject);
|
|
3137
|
-
return this.optimisticQueryResults.queryResult(queryToken);
|
|
3138
|
-
}
|
|
3139
|
-
/**
|
|
3140
|
-
* Get query result by query token based on current, local state
|
|
3141
|
-
*
|
|
3142
|
-
* The only way this will return a value is if we're already subscribed to the
|
|
3143
|
-
* query or its value has been set optimistically.
|
|
3144
|
-
*
|
|
3145
|
-
* @internal
|
|
3146
|
-
*/
|
|
3147
|
-
localQueryResultByToken(queryToken) {
|
|
3148
|
-
return this.optimisticQueryResults.queryResult(queryToken);
|
|
3149
|
-
}
|
|
3150
|
-
/**
|
|
3151
|
-
* Whether local query result is available for a token.
|
|
3152
|
-
*
|
|
3153
|
-
* This method does not throw if the result is an error.
|
|
3154
|
-
*
|
|
3155
|
-
* @internal
|
|
3156
|
-
*/
|
|
3157
|
-
hasLocalQueryResultByToken(queryToken) {
|
|
3158
|
-
return this.optimisticQueryResults.hasQueryResult(queryToken);
|
|
3159
|
-
}
|
|
3160
|
-
/**
|
|
3161
|
-
* @internal
|
|
3162
|
-
*/
|
|
3163
|
-
localQueryLogs(udfPath, args) {
|
|
3164
|
-
const argsObject = parseArgs(args);
|
|
3165
|
-
const queryToken = serializePathAndArgs(udfPath, argsObject);
|
|
3166
|
-
return this.optimisticQueryResults.queryLogs(queryToken);
|
|
3167
|
-
}
|
|
3168
|
-
/**
|
|
3169
|
-
* Retrieve the current {@link QueryJournal} for this query function.
|
|
3170
|
-
*
|
|
3171
|
-
* If we have not yet received a result for this query, this will be `undefined`.
|
|
3172
|
-
*
|
|
3173
|
-
* @param name - The name of the query.
|
|
3174
|
-
* @param args - The arguments object for this query.
|
|
3175
|
-
* @returns The query's {@link QueryJournal} or `undefined`.
|
|
3176
|
-
*/
|
|
3177
|
-
queryJournal(name, args) {
|
|
3178
|
-
const argsObject = parseArgs(args);
|
|
3179
|
-
const queryToken = serializePathAndArgs(name, argsObject);
|
|
3180
|
-
return this.state.queryJournal(queryToken);
|
|
3181
|
-
}
|
|
3182
|
-
/**
|
|
3183
|
-
* Get the current {@link ConnectionState} between the client and the Convex
|
|
3184
|
-
* backend.
|
|
3185
|
-
*
|
|
3186
|
-
* @returns The {@link ConnectionState} with the Convex backend.
|
|
3187
|
-
*/
|
|
3188
|
-
connectionState() {
|
|
3189
|
-
const wsConnectionState = this.webSocketManager.connectionState();
|
|
3190
|
-
return {
|
|
3191
|
-
hasInflightRequests: this.requestManager.hasInflightRequests(),
|
|
3192
|
-
isWebSocketConnected: wsConnectionState.isConnected,
|
|
3193
|
-
hasEverConnected: wsConnectionState.hasEverConnected,
|
|
3194
|
-
connectionCount: wsConnectionState.connectionCount,
|
|
3195
|
-
connectionRetries: wsConnectionState.connectionRetries,
|
|
3196
|
-
timeOfOldestInflightRequest: this.requestManager.timeOfOldestInflightRequest(),
|
|
3197
|
-
inflightMutations: this.requestManager.inflightMutations(),
|
|
3198
|
-
inflightActions: this.requestManager.inflightActions()
|
|
3199
|
-
};
|
|
3200
|
-
}
|
|
3201
|
-
/**
|
|
3202
|
-
* Subscribe to the {@link ConnectionState} between the client and the Convex
|
|
3203
|
-
* backend, calling a callback each time it changes.
|
|
3204
|
-
*
|
|
3205
|
-
* Subscribed callbacks will be called when any part of ConnectionState changes.
|
|
3206
|
-
* ConnectionState may grow in future versions (e.g. to provide a array of
|
|
3207
|
-
* inflight requests) in which case callbacks would be called more frequently.
|
|
3208
|
-
*
|
|
3209
|
-
* @returns An unsubscribe function to stop listening.
|
|
3210
|
-
*/
|
|
3211
|
-
subscribeToConnectionState(cb) {
|
|
3212
|
-
const id = this.nextConnectionStateSubscriberId++;
|
|
3213
|
-
this.connectionStateSubscribers.set(id, cb);
|
|
3214
|
-
return () => {
|
|
3215
|
-
this.connectionStateSubscribers.delete(id);
|
|
3216
|
-
};
|
|
3217
|
-
}
|
|
3218
|
-
/**
|
|
3219
|
-
* Execute a mutation function.
|
|
3220
|
-
*
|
|
3221
|
-
* @param name - The name of the mutation.
|
|
3222
|
-
* @param args - An arguments object for the mutation. If this is omitted,
|
|
3223
|
-
* the arguments will be `{}`.
|
|
3224
|
-
* @param options - A {@link MutationOptions} options object for this mutation.
|
|
3225
|
-
|
|
3226
|
-
* @returns - A promise of the mutation's result.
|
|
3227
|
-
*/
|
|
3228
|
-
async mutation(name, args, options) {
|
|
3229
|
-
const result = await this.mutationInternal(name, args, options);
|
|
3230
|
-
if (!result.success) {
|
|
3231
|
-
if (result.errorData !== void 0) {
|
|
3232
|
-
throw forwardData(
|
|
3233
|
-
result,
|
|
3234
|
-
new ConvexError(
|
|
3235
|
-
createHybridErrorStacktrace("mutation", name, result)
|
|
3236
|
-
)
|
|
3237
|
-
);
|
|
3238
|
-
}
|
|
3239
|
-
throw new Error(createHybridErrorStacktrace("mutation", name, result));
|
|
3240
|
-
}
|
|
3241
|
-
return result.value;
|
|
3242
|
-
}
|
|
3243
|
-
/**
|
|
3244
|
-
* @internal
|
|
3245
|
-
*/
|
|
3246
|
-
async mutationInternal(udfPath, args, options, componentPath) {
|
|
3247
|
-
const { mutationPromise } = this.enqueueMutation(
|
|
3248
|
-
udfPath,
|
|
3249
|
-
args,
|
|
3250
|
-
options,
|
|
3251
|
-
componentPath
|
|
3252
|
-
);
|
|
3253
|
-
return mutationPromise;
|
|
3254
|
-
}
|
|
3255
|
-
/**
|
|
3256
|
-
* @internal
|
|
3257
|
-
*/
|
|
3258
|
-
enqueueMutation(udfPath, args, options, componentPath) {
|
|
3259
|
-
const mutationArgs = parseArgs(args);
|
|
3260
|
-
this.tryReportLongDisconnect();
|
|
3261
|
-
const requestId = this.nextRequestId;
|
|
3262
|
-
this._nextRequestId++;
|
|
3263
|
-
if (options !== void 0) {
|
|
3264
|
-
const optimisticUpdate = options.optimisticUpdate;
|
|
3265
|
-
if (optimisticUpdate !== void 0) {
|
|
3266
|
-
const wrappedUpdate = (localQueryStore) => {
|
|
3267
|
-
const result = optimisticUpdate(
|
|
3268
|
-
localQueryStore,
|
|
3269
|
-
mutationArgs
|
|
3270
|
-
);
|
|
3271
|
-
if (result instanceof Promise) {
|
|
3272
|
-
this.logger.warn(
|
|
3273
|
-
"Optimistic update handler returned a Promise. Optimistic updates should be synchronous."
|
|
3274
|
-
);
|
|
3275
|
-
}
|
|
3276
|
-
};
|
|
3277
|
-
const changedQueryTokens = this.optimisticQueryResults.applyOptimisticUpdate(
|
|
3278
|
-
wrappedUpdate,
|
|
3279
|
-
requestId
|
|
3280
|
-
);
|
|
3281
|
-
const changedQueries = changedQueryTokens.map((token) => {
|
|
3282
|
-
const localResult = this.localQueryResultByToken(token);
|
|
3283
|
-
return {
|
|
3284
|
-
token,
|
|
3285
|
-
modification: {
|
|
3286
|
-
kind: "Updated",
|
|
3287
|
-
result: localResult === void 0 ? void 0 : {
|
|
3288
|
-
success: true,
|
|
3289
|
-
value: localResult,
|
|
3290
|
-
logLines: []
|
|
3291
|
-
}
|
|
3292
|
-
}
|
|
3293
|
-
};
|
|
3294
|
-
});
|
|
3295
|
-
this.handleTransition({
|
|
3296
|
-
queries: changedQueries,
|
|
3297
|
-
reflectedMutations: [],
|
|
3298
|
-
timestamp: this.remoteQuerySet.timestamp()
|
|
3299
|
-
});
|
|
3300
|
-
}
|
|
3301
|
-
}
|
|
3302
|
-
const message = {
|
|
3303
|
-
type: "Mutation",
|
|
3304
|
-
requestId,
|
|
3305
|
-
udfPath,
|
|
3306
|
-
componentPath,
|
|
3307
|
-
args: [convexToJson(mutationArgs)]
|
|
3308
|
-
};
|
|
3309
|
-
const mightBeSent = this.webSocketManager.sendMessage(message);
|
|
3310
|
-
const mutationPromise = this.requestManager.request(message, mightBeSent);
|
|
3311
|
-
return {
|
|
3312
|
-
requestId,
|
|
3313
|
-
mutationPromise
|
|
3314
|
-
};
|
|
3315
|
-
}
|
|
3316
|
-
/**
|
|
3317
|
-
* Execute an action function.
|
|
3318
|
-
*
|
|
3319
|
-
* @param name - The name of the action.
|
|
3320
|
-
* @param args - An arguments object for the action. If this is omitted,
|
|
3321
|
-
* the arguments will be `{}`.
|
|
3322
|
-
* @returns A promise of the action's result.
|
|
3323
|
-
*/
|
|
3324
|
-
async action(name, args) {
|
|
3325
|
-
const result = await this.actionInternal(name, args);
|
|
3326
|
-
if (!result.success) {
|
|
3327
|
-
if (result.errorData !== void 0) {
|
|
3328
|
-
throw forwardData(
|
|
3329
|
-
result,
|
|
3330
|
-
new ConvexError(createHybridErrorStacktrace("action", name, result))
|
|
3331
|
-
);
|
|
3332
|
-
}
|
|
3333
|
-
throw new Error(createHybridErrorStacktrace("action", name, result));
|
|
3334
|
-
}
|
|
3335
|
-
return result.value;
|
|
3336
|
-
}
|
|
3337
|
-
/**
|
|
3338
|
-
* @internal
|
|
3339
|
-
*/
|
|
3340
|
-
async actionInternal(udfPath, args, componentPath) {
|
|
3341
|
-
const actionArgs = parseArgs(args);
|
|
3342
|
-
const requestId = this.nextRequestId;
|
|
3343
|
-
this._nextRequestId++;
|
|
3344
|
-
this.tryReportLongDisconnect();
|
|
3345
|
-
const message = {
|
|
3346
|
-
type: "Action",
|
|
3347
|
-
requestId,
|
|
3348
|
-
udfPath,
|
|
3349
|
-
componentPath,
|
|
3350
|
-
args: [convexToJson(actionArgs)]
|
|
3351
|
-
};
|
|
3352
|
-
const mightBeSent = this.webSocketManager.sendMessage(message);
|
|
3353
|
-
return this.requestManager.request(message, mightBeSent);
|
|
3354
|
-
}
|
|
3355
|
-
/**
|
|
3356
|
-
* Close any network handles associated with this client and stop all subscriptions.
|
|
3357
|
-
*
|
|
3358
|
-
* Call this method when you're done with an {@link BaseConvexClient} to
|
|
3359
|
-
* dispose of its sockets and resources.
|
|
3360
|
-
*
|
|
3361
|
-
* @returns A `Promise` fulfilled when the connection has been completely closed.
|
|
3362
|
-
*/
|
|
3363
|
-
async close() {
|
|
3364
|
-
this.authenticationManager.stop();
|
|
3365
|
-
return this.webSocketManager.terminate();
|
|
3366
|
-
}
|
|
3367
|
-
/**
|
|
3368
|
-
* Return the address for this client, useful for creating a new client.
|
|
3369
|
-
*
|
|
3370
|
-
* Not guaranteed to match the address with which this client was constructed:
|
|
3371
|
-
* it may be canonicalized.
|
|
3372
|
-
*/
|
|
3373
|
-
get url() {
|
|
3374
|
-
return this.address;
|
|
3375
|
-
}
|
|
3376
|
-
/**
|
|
3377
|
-
* @internal
|
|
3378
|
-
*/
|
|
3379
|
-
get nextRequestId() {
|
|
3380
|
-
return this._nextRequestId;
|
|
3381
|
-
}
|
|
3382
|
-
/**
|
|
3383
|
-
* @internal
|
|
3384
|
-
*/
|
|
3385
|
-
get sessionId() {
|
|
3386
|
-
return this._sessionId;
|
|
3387
|
-
}
|
|
3388
|
-
/**
|
|
3389
|
-
* Reports performance marks to the server. This should only be called when
|
|
3390
|
-
* we have a functional websocket.
|
|
3391
|
-
*/
|
|
3392
|
-
reportMarks() {
|
|
3393
|
-
if (this.debug) {
|
|
3394
|
-
const report = getMarksReport(this.sessionId);
|
|
3395
|
-
this.webSocketManager.sendMessage({
|
|
3396
|
-
type: "Event",
|
|
3397
|
-
eventType: "ClientConnect",
|
|
3398
|
-
event: report
|
|
3399
|
-
});
|
|
3400
|
-
}
|
|
3401
|
-
}
|
|
3402
|
-
tryReportLongDisconnect() {
|
|
3403
|
-
if (!this.debug) {
|
|
3404
|
-
return;
|
|
3405
|
-
}
|
|
3406
|
-
const timeOfOldestRequest = this.connectionState().timeOfOldestInflightRequest;
|
|
3407
|
-
if (timeOfOldestRequest === null || Date.now() - timeOfOldestRequest.getTime() <= 60 * 1e3) {
|
|
3408
|
-
return;
|
|
3409
|
-
}
|
|
3410
|
-
const endpoint = `${this.address}/api/debug_event`;
|
|
3411
|
-
fetch(endpoint, {
|
|
3412
|
-
method: "POST",
|
|
3413
|
-
headers: {
|
|
3414
|
-
"Content-Type": "application/json",
|
|
3415
|
-
"Convex-Client": `npm-${version}`
|
|
3416
|
-
},
|
|
3417
|
-
body: JSON.stringify({ event: "LongWebsocketDisconnect" })
|
|
3418
|
-
}).then((response) => {
|
|
3419
|
-
if (!response.ok) {
|
|
3420
|
-
this.logger.warn(
|
|
3421
|
-
"Analytics request failed with response:",
|
|
3422
|
-
response.body
|
|
3423
|
-
);
|
|
3424
|
-
}
|
|
3425
|
-
}).catch((error) => {
|
|
3426
|
-
this.logger.warn("Analytics response failed with error:", error);
|
|
3427
|
-
});
|
|
3428
|
-
}
|
|
3429
|
-
};
|
|
3430
|
-
|
|
3431
|
-
// node_modules/convex/dist/esm/browser/sync/pagination.js
|
|
3432
|
-
function asPaginationResult(value) {
|
|
3433
|
-
if (typeof value !== "object" || value === null || !Array.isArray(value.page) || typeof value.isDone !== "boolean" || typeof value.continueCursor !== "string") {
|
|
3434
|
-
throw new Error(`Not a valid paginated query result: ${value?.toString()}`);
|
|
3435
|
-
}
|
|
3436
|
-
return value;
|
|
3437
|
-
}
|
|
3438
|
-
|
|
3439
|
-
// node_modules/convex/dist/esm/browser/sync/paginated_query_client.js
|
|
3440
|
-
var __defProp12 = Object.defineProperty;
|
|
3441
|
-
var __defNormalProp11 = (obj, key, value) => key in obj ? __defProp12(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3442
|
-
var __publicField11 = (obj, key, value) => __defNormalProp11(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
3443
|
-
var PaginatedQueryClient = class {
|
|
3444
|
-
constructor(client, onTransition) {
|
|
3445
|
-
this.client = client;
|
|
3446
|
-
this.onTransition = onTransition;
|
|
3447
|
-
__publicField11(this, "paginatedQuerySet", /* @__PURE__ */ new Map());
|
|
3448
|
-
__publicField11(this, "lastTransitionTs");
|
|
3449
|
-
this.lastTransitionTs = Long.fromNumber(0);
|
|
3450
|
-
this.client.addOnTransitionHandler(
|
|
3451
|
-
(transition) => this.onBaseTransition(transition)
|
|
3452
|
-
);
|
|
3453
|
-
}
|
|
3454
|
-
/**
|
|
3455
|
-
* Subscribe to a paginated query.
|
|
3456
|
-
*
|
|
3457
|
-
* @param name - The name of the paginated query function
|
|
3458
|
-
* @param args - Arguments for the query (excluding paginationOpts)
|
|
3459
|
-
* @param options - Pagination options including initialNumItems
|
|
3460
|
-
* @returns Object with paginatedQueryToken and unsubscribe function
|
|
3461
|
-
*/
|
|
3462
|
-
subscribe(name, args, options) {
|
|
3463
|
-
const canonicalizedUdfPath = canonicalizeUdfPath(name);
|
|
3464
|
-
const token = serializePaginatedPathAndArgs(
|
|
3465
|
-
canonicalizedUdfPath,
|
|
3466
|
-
args,
|
|
3467
|
-
options
|
|
3468
|
-
);
|
|
3469
|
-
const unsubscribe = () => this.removePaginatedQuerySubscriber(token);
|
|
3470
|
-
const existingEntry = this.paginatedQuerySet.get(token);
|
|
3471
|
-
if (existingEntry) {
|
|
3472
|
-
existingEntry.numSubscribers += 1;
|
|
3473
|
-
return {
|
|
3474
|
-
paginatedQueryToken: token,
|
|
3475
|
-
unsubscribe
|
|
3476
|
-
};
|
|
3477
|
-
}
|
|
3478
|
-
this.paginatedQuerySet.set(token, {
|
|
3479
|
-
token,
|
|
3480
|
-
canonicalizedUdfPath,
|
|
3481
|
-
args,
|
|
3482
|
-
numSubscribers: 1,
|
|
3483
|
-
options: { initialNumItems: options.initialNumItems },
|
|
3484
|
-
nextPageKey: 0,
|
|
3485
|
-
pageKeys: [],
|
|
3486
|
-
pageKeyToQuery: /* @__PURE__ */ new Map(),
|
|
3487
|
-
ongoingSplits: /* @__PURE__ */ new Map(),
|
|
3488
|
-
skip: false,
|
|
3489
|
-
id: options.id
|
|
3490
|
-
});
|
|
3491
|
-
this.addPageToPaginatedQuery(token, null, options.initialNumItems);
|
|
3492
|
-
return {
|
|
3493
|
-
paginatedQueryToken: token,
|
|
3494
|
-
unsubscribe
|
|
3495
|
-
};
|
|
3496
|
-
}
|
|
3497
|
-
/**
|
|
3498
|
-
* Get current results for a paginated query based on local state.
|
|
3499
|
-
*
|
|
3500
|
-
* Throws an error when one of the pages has errored.
|
|
3501
|
-
*/
|
|
3502
|
-
localQueryResult(name, args, options) {
|
|
3503
|
-
const canonicalizedUdfPath = canonicalizeUdfPath(name);
|
|
3504
|
-
const token = serializePaginatedPathAndArgs(
|
|
3505
|
-
canonicalizedUdfPath,
|
|
3506
|
-
args,
|
|
3507
|
-
options
|
|
3508
|
-
);
|
|
3509
|
-
return this.localQueryResultByToken(token);
|
|
3510
|
-
}
|
|
3511
|
-
/**
|
|
3512
|
-
* @internal
|
|
3513
|
-
*/
|
|
3514
|
-
localQueryResultByToken(token) {
|
|
3515
|
-
const paginatedQuery = this.paginatedQuerySet.get(token);
|
|
3516
|
-
if (!paginatedQuery) {
|
|
3517
|
-
return void 0;
|
|
3518
|
-
}
|
|
3519
|
-
const activePages = this.activePageQueryTokens(paginatedQuery);
|
|
3520
|
-
if (activePages.length === 0) {
|
|
3521
|
-
return {
|
|
3522
|
-
results: [],
|
|
3523
|
-
status: "LoadingFirstPage",
|
|
3524
|
-
loadMore: (numItems) => {
|
|
3525
|
-
return this.loadMoreOfPaginatedQuery(token, numItems);
|
|
3526
|
-
}
|
|
3527
|
-
};
|
|
3528
|
-
}
|
|
3529
|
-
let allResults = [];
|
|
3530
|
-
let hasUndefined = false;
|
|
3531
|
-
let isDone = false;
|
|
3532
|
-
for (const pageToken of activePages) {
|
|
3533
|
-
const result = this.client.localQueryResultByToken(pageToken);
|
|
3534
|
-
if (result === void 0) {
|
|
3535
|
-
hasUndefined = true;
|
|
3536
|
-
isDone = false;
|
|
3537
|
-
continue;
|
|
3538
|
-
}
|
|
3539
|
-
const paginationResult = asPaginationResult(result);
|
|
3540
|
-
allResults = allResults.concat(paginationResult.page);
|
|
3541
|
-
isDone = !!paginationResult.isDone;
|
|
3542
|
-
}
|
|
3543
|
-
let status;
|
|
3544
|
-
if (hasUndefined) {
|
|
3545
|
-
status = allResults.length === 0 ? "LoadingFirstPage" : "LoadingMore";
|
|
3546
|
-
} else if (isDone) {
|
|
3547
|
-
status = "Exhausted";
|
|
3548
|
-
} else {
|
|
3549
|
-
status = "CanLoadMore";
|
|
3550
|
-
}
|
|
3551
|
-
return {
|
|
3552
|
-
results: allResults,
|
|
3553
|
-
status,
|
|
3554
|
-
loadMore: (numItems) => {
|
|
3555
|
-
return this.loadMoreOfPaginatedQuery(token, numItems);
|
|
3556
|
-
}
|
|
3557
|
-
};
|
|
3558
|
-
}
|
|
3559
|
-
onBaseTransition(transition) {
|
|
3560
|
-
const changedBaseTokens = transition.queries.map((q) => q.token);
|
|
3561
|
-
const changed = this.queriesContainingTokens(changedBaseTokens);
|
|
3562
|
-
let paginatedQueries = [];
|
|
3563
|
-
if (changed.length > 0) {
|
|
3564
|
-
this.processPaginatedQuerySplits(
|
|
3565
|
-
changed,
|
|
3566
|
-
(token) => this.client.localQueryResultByToken(token)
|
|
3567
|
-
);
|
|
3568
|
-
paginatedQueries = changed.map((token) => ({
|
|
3569
|
-
token,
|
|
3570
|
-
modification: {
|
|
3571
|
-
kind: "Updated",
|
|
3572
|
-
result: this.localQueryResultByToken(token)
|
|
3573
|
-
}
|
|
3574
|
-
}));
|
|
3575
|
-
}
|
|
3576
|
-
const extendedTransition = {
|
|
3577
|
-
...transition,
|
|
3578
|
-
paginatedQueries
|
|
3579
|
-
};
|
|
3580
|
-
this.onTransition(extendedTransition);
|
|
3581
|
-
}
|
|
3582
|
-
/**
|
|
3583
|
-
* Load more items for a paginated query.
|
|
3584
|
-
*
|
|
3585
|
-
* This *always* causes a transition, the status of the query
|
|
3586
|
-
* has probably changed from "CanLoadMore" to "LoadingMore".
|
|
3587
|
-
* Data might have changed too: maybe a subscription to this page
|
|
3588
|
-
* query already exists (unlikely but possible) or this page query
|
|
3589
|
-
* has an optimistic update providing some initial data.
|
|
3590
|
-
*
|
|
3591
|
-
* @internal
|
|
3592
|
-
*/
|
|
3593
|
-
loadMoreOfPaginatedQuery(token, numItems) {
|
|
3594
|
-
this.mustGetPaginatedQuery(token);
|
|
3595
|
-
const lastPageToken = this.queryTokenForLastPageOfPaginatedQuery(token);
|
|
3596
|
-
const lastPageResult = this.client.localQueryResultByToken(lastPageToken);
|
|
3597
|
-
if (!lastPageResult) {
|
|
3598
|
-
return false;
|
|
3599
|
-
}
|
|
3600
|
-
const paginationResult = asPaginationResult(lastPageResult);
|
|
3601
|
-
if (paginationResult.isDone) {
|
|
3602
|
-
return false;
|
|
3603
|
-
}
|
|
3604
|
-
this.addPageToPaginatedQuery(
|
|
3605
|
-
token,
|
|
3606
|
-
paginationResult.continueCursor,
|
|
3607
|
-
numItems
|
|
3608
|
-
);
|
|
3609
|
-
const loadMoreTransition = {
|
|
3610
|
-
timestamp: this.lastTransitionTs,
|
|
3611
|
-
reflectedMutations: [],
|
|
3612
|
-
queries: [],
|
|
3613
|
-
paginatedQueries: [
|
|
3614
|
-
{
|
|
3615
|
-
token,
|
|
3616
|
-
modification: {
|
|
3617
|
-
kind: "Updated",
|
|
3618
|
-
result: this.localQueryResultByToken(token)
|
|
3619
|
-
}
|
|
3620
|
-
}
|
|
3621
|
-
]
|
|
3622
|
-
};
|
|
3623
|
-
this.onTransition(loadMoreTransition);
|
|
3624
|
-
return true;
|
|
3625
|
-
}
|
|
3626
|
-
/**
|
|
3627
|
-
* @internal
|
|
3628
|
-
*/
|
|
3629
|
-
queriesContainingTokens(queryTokens) {
|
|
3630
|
-
if (queryTokens.length === 0) {
|
|
3631
|
-
return [];
|
|
3632
|
-
}
|
|
3633
|
-
const changed = [];
|
|
3634
|
-
const queryTokenSet = new Set(queryTokens);
|
|
3635
|
-
for (const [paginatedToken, paginatedQuery] of this.paginatedQuerySet) {
|
|
3636
|
-
for (const pageToken of this.allQueryTokens(paginatedQuery)) {
|
|
3637
|
-
if (queryTokenSet.has(pageToken)) {
|
|
3638
|
-
changed.push(paginatedToken);
|
|
3639
|
-
break;
|
|
3640
|
-
}
|
|
3641
|
-
}
|
|
3642
|
-
}
|
|
3643
|
-
return changed;
|
|
3644
|
-
}
|
|
3645
|
-
/**
|
|
3646
|
-
* @internal
|
|
3647
|
-
*/
|
|
3648
|
-
processPaginatedQuerySplits(changed, getResult) {
|
|
3649
|
-
for (const paginatedQueryToken of changed) {
|
|
3650
|
-
const paginatedQuery = this.mustGetPaginatedQuery(paginatedQueryToken);
|
|
3651
|
-
const { ongoingSplits, pageKeyToQuery, pageKeys } = paginatedQuery;
|
|
3652
|
-
for (const [pageKey, [splitKey1, splitKey2]] of ongoingSplits) {
|
|
3653
|
-
const bothNewPagesLoaded = getResult(pageKeyToQuery.get(splitKey1).queryToken) !== void 0 && getResult(pageKeyToQuery.get(splitKey2).queryToken) !== void 0;
|
|
3654
|
-
if (bothNewPagesLoaded) {
|
|
3655
|
-
this.completePaginatedQuerySplit(
|
|
3656
|
-
paginatedQuery,
|
|
3657
|
-
pageKey,
|
|
3658
|
-
splitKey1,
|
|
3659
|
-
splitKey2
|
|
3660
|
-
);
|
|
3661
|
-
}
|
|
3662
|
-
}
|
|
3663
|
-
for (const pageKey of pageKeys) {
|
|
3664
|
-
if (ongoingSplits.has(pageKey)) {
|
|
3665
|
-
continue;
|
|
3666
|
-
}
|
|
3667
|
-
const pageToken = pageKeyToQuery.get(pageKey).queryToken;
|
|
3668
|
-
const pageResult = getResult(pageToken);
|
|
3669
|
-
if (!pageResult) {
|
|
3670
|
-
continue;
|
|
3671
|
-
}
|
|
3672
|
-
const result = asPaginationResult(pageResult);
|
|
3673
|
-
const shouldSplit = result.splitCursor && (result.pageStatus === "SplitRecommended" || result.pageStatus === "SplitRequired" || // This client-driven page splitting condition will change in the future.
|
|
3674
|
-
result.page.length > paginatedQuery.options.initialNumItems * 2);
|
|
3675
|
-
if (shouldSplit) {
|
|
3676
|
-
this.splitPaginatedQueryPage(
|
|
3677
|
-
paginatedQuery,
|
|
3678
|
-
pageKey,
|
|
3679
|
-
result.splitCursor,
|
|
3680
|
-
// we just checked
|
|
3681
|
-
result.continueCursor
|
|
3682
|
-
);
|
|
3683
|
-
}
|
|
3684
|
-
}
|
|
3685
|
-
}
|
|
3686
|
-
}
|
|
3687
|
-
splitPaginatedQueryPage(paginatedQuery, pageKey, splitCursor, continueCursor) {
|
|
3688
|
-
const splitKey1 = paginatedQuery.nextPageKey++;
|
|
3689
|
-
const splitKey2 = paginatedQuery.nextPageKey++;
|
|
3690
|
-
const paginationOpts = {
|
|
3691
|
-
cursor: continueCursor,
|
|
3692
|
-
numItems: paginatedQuery.options.initialNumItems,
|
|
3693
|
-
id: paginatedQuery.id
|
|
3694
|
-
};
|
|
3695
|
-
const firstSubscription = this.client.subscribe(
|
|
3696
|
-
paginatedQuery.canonicalizedUdfPath,
|
|
3697
|
-
{
|
|
3698
|
-
...paginatedQuery.args,
|
|
3699
|
-
paginationOpts: {
|
|
3700
|
-
...paginationOpts,
|
|
3701
|
-
cursor: null,
|
|
3702
|
-
// Start from beginning for first split
|
|
3703
|
-
endCursor: splitCursor
|
|
3704
|
-
}
|
|
3705
|
-
}
|
|
3706
|
-
);
|
|
3707
|
-
paginatedQuery.pageKeyToQuery.set(splitKey1, firstSubscription);
|
|
3708
|
-
const secondSubscription = this.client.subscribe(
|
|
3709
|
-
paginatedQuery.canonicalizedUdfPath,
|
|
3710
|
-
{
|
|
3711
|
-
...paginatedQuery.args,
|
|
3712
|
-
paginationOpts: {
|
|
3713
|
-
...paginationOpts,
|
|
3714
|
-
cursor: splitCursor,
|
|
3715
|
-
endCursor: continueCursor
|
|
3716
|
-
}
|
|
3717
|
-
}
|
|
3718
|
-
);
|
|
3719
|
-
paginatedQuery.pageKeyToQuery.set(splitKey2, secondSubscription);
|
|
3720
|
-
paginatedQuery.ongoingSplits.set(pageKey, [splitKey1, splitKey2]);
|
|
3721
|
-
}
|
|
3722
|
-
/**
|
|
3723
|
-
* @internal
|
|
3724
|
-
*/
|
|
3725
|
-
addPageToPaginatedQuery(token, continueCursor, numItems) {
|
|
3726
|
-
const paginatedQuery = this.mustGetPaginatedQuery(token);
|
|
3727
|
-
const pageKey = paginatedQuery.nextPageKey++;
|
|
3728
|
-
const paginationOpts = {
|
|
3729
|
-
cursor: continueCursor,
|
|
3730
|
-
numItems,
|
|
3731
|
-
id: paginatedQuery.id
|
|
3732
|
-
};
|
|
3733
|
-
const pageArgs = {
|
|
3734
|
-
...paginatedQuery.args,
|
|
3735
|
-
paginationOpts
|
|
3736
|
-
};
|
|
3737
|
-
const subscription = this.client.subscribe(
|
|
3738
|
-
paginatedQuery.canonicalizedUdfPath,
|
|
3739
|
-
pageArgs
|
|
3740
|
-
);
|
|
3741
|
-
paginatedQuery.pageKeys.push(pageKey);
|
|
3742
|
-
paginatedQuery.pageKeyToQuery.set(pageKey, subscription);
|
|
3743
|
-
return subscription;
|
|
3744
|
-
}
|
|
3745
|
-
removePaginatedQuerySubscriber(token) {
|
|
3746
|
-
const paginatedQuery = this.paginatedQuerySet.get(token);
|
|
3747
|
-
if (!paginatedQuery) {
|
|
3748
|
-
return;
|
|
3749
|
-
}
|
|
3750
|
-
paginatedQuery.numSubscribers -= 1;
|
|
3751
|
-
if (paginatedQuery.numSubscribers > 0) {
|
|
3752
|
-
return;
|
|
3753
|
-
}
|
|
3754
|
-
for (const subscription of paginatedQuery.pageKeyToQuery.values()) {
|
|
3755
|
-
subscription.unsubscribe();
|
|
3756
|
-
}
|
|
3757
|
-
this.paginatedQuerySet.delete(token);
|
|
3758
|
-
}
|
|
3759
|
-
completePaginatedQuerySplit(paginatedQuery, pageKey, splitKey1, splitKey2) {
|
|
3760
|
-
const originalQuery = paginatedQuery.pageKeyToQuery.get(pageKey);
|
|
3761
|
-
paginatedQuery.pageKeyToQuery.delete(pageKey);
|
|
3762
|
-
const pageIndex = paginatedQuery.pageKeys.indexOf(pageKey);
|
|
3763
|
-
paginatedQuery.pageKeys.splice(pageIndex, 1, splitKey1, splitKey2);
|
|
3764
|
-
paginatedQuery.ongoingSplits.delete(pageKey);
|
|
3765
|
-
originalQuery.unsubscribe();
|
|
3766
|
-
}
|
|
3767
|
-
/** The query tokens for all active pages, in result order */
|
|
3768
|
-
activePageQueryTokens(paginatedQuery) {
|
|
3769
|
-
return paginatedQuery.pageKeys.map(
|
|
3770
|
-
(pageKey) => paginatedQuery.pageKeyToQuery.get(pageKey).queryToken
|
|
3771
|
-
);
|
|
3772
|
-
}
|
|
3773
|
-
allQueryTokens(paginatedQuery) {
|
|
3774
|
-
return Array.from(paginatedQuery.pageKeyToQuery.values()).map(
|
|
3775
|
-
(sub) => sub.queryToken
|
|
3776
|
-
);
|
|
3777
|
-
}
|
|
3778
|
-
queryTokenForLastPageOfPaginatedQuery(token) {
|
|
3779
|
-
const paginatedQuery = this.mustGetPaginatedQuery(token);
|
|
3780
|
-
const lastPageKey = paginatedQuery.pageKeys[paginatedQuery.pageKeys.length - 1];
|
|
3781
|
-
if (lastPageKey === void 0) {
|
|
3782
|
-
throw new Error(`No pages for paginated query ${token}`);
|
|
3783
|
-
}
|
|
3784
|
-
return paginatedQuery.pageKeyToQuery.get(lastPageKey).queryToken;
|
|
3785
|
-
}
|
|
3786
|
-
mustGetPaginatedQuery(token) {
|
|
3787
|
-
const paginatedQuery = this.paginatedQuerySet.get(token);
|
|
3788
|
-
if (!paginatedQuery) {
|
|
3789
|
-
throw new Error("paginated query no longer exists for token " + token);
|
|
3790
|
-
}
|
|
3791
|
-
return paginatedQuery;
|
|
3792
|
-
}
|
|
3793
|
-
};
|
|
3794
|
-
|
|
3795
|
-
// node_modules/convex/dist/esm/browser/simple_client.js
|
|
3796
|
-
var __defProp13 = Object.defineProperty;
|
|
3797
|
-
var __defNormalProp12 = (obj, key, value) => key in obj ? __defProp13(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3798
|
-
var __publicField12 = (obj, key, value) => __defNormalProp12(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
3799
|
-
var defaultWebSocketConstructor;
|
|
3800
|
-
var ConvexClient = class {
|
|
3801
|
-
/**
|
|
3802
|
-
* Construct a client and immediately initiate a WebSocket connection to the passed address.
|
|
3803
|
-
*
|
|
3804
|
-
* @public
|
|
3805
|
-
*/
|
|
3806
|
-
constructor(address, options = {}) {
|
|
3807
|
-
__publicField12(this, "listeners");
|
|
3808
|
-
__publicField12(this, "_client");
|
|
3809
|
-
__publicField12(this, "_paginatedClient");
|
|
3810
|
-
__publicField12(this, "callNewListenersWithCurrentValuesTimer");
|
|
3811
|
-
__publicField12(this, "_closed");
|
|
3812
|
-
__publicField12(this, "_disabled");
|
|
3813
|
-
if (options.skipConvexDeploymentUrlCheck !== true) {
|
|
3814
|
-
validateDeploymentUrl(address);
|
|
3815
|
-
}
|
|
3816
|
-
const { disabled, ...baseOptions } = options;
|
|
3817
|
-
this._closed = false;
|
|
3818
|
-
this._disabled = !!disabled;
|
|
3819
|
-
if (defaultWebSocketConstructor && !("webSocketConstructor" in baseOptions) && typeof WebSocket === "undefined") {
|
|
3820
|
-
baseOptions.webSocketConstructor = defaultWebSocketConstructor;
|
|
3821
|
-
}
|
|
3822
|
-
if (typeof window === "undefined" && !("unsavedChangesWarning" in baseOptions)) {
|
|
3823
|
-
baseOptions.unsavedChangesWarning = false;
|
|
3824
|
-
}
|
|
3825
|
-
if (!this.disabled) {
|
|
3826
|
-
this._client = new BaseConvexClient(
|
|
3827
|
-
address,
|
|
3828
|
-
() => {
|
|
3829
|
-
},
|
|
3830
|
-
// NOP, let the paginated query client do it all
|
|
3831
|
-
baseOptions
|
|
3832
|
-
);
|
|
3833
|
-
this._paginatedClient = new PaginatedQueryClient(
|
|
3834
|
-
this._client,
|
|
3835
|
-
(transition) => this._transition(transition)
|
|
3836
|
-
);
|
|
3837
|
-
}
|
|
3838
|
-
this.listeners = /* @__PURE__ */ new Set();
|
|
3839
|
-
}
|
|
3840
|
-
/**
|
|
3841
|
-
* Once closed no registered callbacks will fire again.
|
|
3842
|
-
*/
|
|
3843
|
-
get closed() {
|
|
3844
|
-
return this._closed;
|
|
3845
|
-
}
|
|
3846
|
-
get client() {
|
|
3847
|
-
if (this._client) return this._client;
|
|
3848
|
-
throw new Error("ConvexClient is disabled");
|
|
3849
|
-
}
|
|
3850
|
-
/**
|
|
3851
|
-
* @internal
|
|
3852
|
-
*/
|
|
3853
|
-
get paginatedClient() {
|
|
3854
|
-
if (this._paginatedClient) return this._paginatedClient;
|
|
3855
|
-
throw new Error("ConvexClient is disabled");
|
|
3856
|
-
}
|
|
3857
|
-
get disabled() {
|
|
3858
|
-
return this._disabled;
|
|
3859
|
-
}
|
|
3860
|
-
/**
|
|
3861
|
-
* Call a callback whenever a new result for a query is received. The callback
|
|
3862
|
-
* will run soon after being registered if a result for the query is already
|
|
3863
|
-
* in memory.
|
|
3864
|
-
*
|
|
3865
|
-
* The return value is an {@link Unsubscribe} object which is both a function
|
|
3866
|
-
* an an object with properties. Both of the patterns below work with this object:
|
|
3867
|
-
*
|
|
3868
|
-
*```ts
|
|
3869
|
-
* // call the return value as a function
|
|
3870
|
-
* const unsubscribe = client.onUpdate(api.messages.list, {}, (messages) => {
|
|
3871
|
-
* console.log(messages);
|
|
3872
|
-
* });
|
|
3873
|
-
* unsubscribe();
|
|
3874
|
-
*
|
|
3875
|
-
* // unpack the return value into its properties
|
|
3876
|
-
* const {
|
|
3877
|
-
* getCurrentValue,
|
|
3878
|
-
* unsubscribe,
|
|
3879
|
-
* } = client.onUpdate(api.messages.list, {}, (messages) => {
|
|
3880
|
-
* console.log(messages);
|
|
3881
|
-
* });
|
|
3882
|
-
*```
|
|
3883
|
-
*
|
|
3884
|
-
* @param query - A {@link server.FunctionReference} for the public query to run.
|
|
3885
|
-
* @param args - The arguments to run the query with.
|
|
3886
|
-
* @param callback - Function to call when the query result updates.
|
|
3887
|
-
* @param onError - Function to call when the query result updates with an error.
|
|
3888
|
-
* If not provided, errors will be thrown instead of calling the callback.
|
|
3889
|
-
*
|
|
3890
|
-
* @return an {@link Unsubscribe} function to stop calling the onUpdate function.
|
|
3891
|
-
*/
|
|
3892
|
-
onUpdate(query, args, callback, onError) {
|
|
3893
|
-
if (this.disabled) {
|
|
3894
|
-
return this.createDisabledUnsubscribe();
|
|
3895
|
-
}
|
|
3896
|
-
const { queryToken, unsubscribe } = this.client.subscribe(
|
|
3897
|
-
getFunctionName(query),
|
|
3898
|
-
args
|
|
3899
|
-
);
|
|
3900
|
-
const queryInfo = {
|
|
3901
|
-
queryToken,
|
|
3902
|
-
callback,
|
|
3903
|
-
onError,
|
|
3904
|
-
unsubscribe,
|
|
3905
|
-
hasEverRun: false,
|
|
3906
|
-
query,
|
|
3907
|
-
args,
|
|
3908
|
-
paginationOptions: void 0
|
|
3909
|
-
};
|
|
3910
|
-
this.listeners.add(queryInfo);
|
|
3911
|
-
if (this.queryResultReady(queryToken) && this.callNewListenersWithCurrentValuesTimer === void 0) {
|
|
3912
|
-
this.callNewListenersWithCurrentValuesTimer = setTimeout(
|
|
3913
|
-
() => this.callNewListenersWithCurrentValues(),
|
|
3914
|
-
0
|
|
3915
|
-
);
|
|
3916
|
-
}
|
|
3917
|
-
const unsubscribeProps = {
|
|
3918
|
-
unsubscribe: () => {
|
|
3919
|
-
if (this.closed) {
|
|
3920
|
-
return;
|
|
3921
|
-
}
|
|
3922
|
-
this.listeners.delete(queryInfo);
|
|
3923
|
-
unsubscribe();
|
|
3924
|
-
},
|
|
3925
|
-
getCurrentValue: () => this.client.localQueryResultByToken(queryToken),
|
|
3926
|
-
getQueryLogs: () => this.client.localQueryLogs(queryToken)
|
|
3927
|
-
};
|
|
3928
|
-
const ret = unsubscribeProps.unsubscribe;
|
|
3929
|
-
Object.assign(ret, unsubscribeProps);
|
|
3930
|
-
return ret;
|
|
3931
|
-
}
|
|
3932
|
-
/**
|
|
3933
|
-
* Call a callback whenever a new result for a paginated query is received.
|
|
3934
|
-
*
|
|
3935
|
-
* This is an experimental preview: the final API may change.
|
|
3936
|
-
* In particular, caching behavior, page splitting, and required paginated query options
|
|
3937
|
-
* may change.
|
|
3938
|
-
*
|
|
3939
|
-
* @param query - A {@link server.FunctionReference} for the public query to run.
|
|
3940
|
-
* @param args - The arguments to run the query with.
|
|
3941
|
-
* @param options - Options for the paginated query including initialNumItems and id.
|
|
3942
|
-
* @param callback - Function to call when the query result updates.
|
|
3943
|
-
* @param onError - Function to call when the query result updates with an error.
|
|
3944
|
-
*
|
|
3945
|
-
* @return an {@link Unsubscribe} function to stop calling the callback.
|
|
3946
|
-
*/
|
|
3947
|
-
onPaginatedUpdate_experimental(query, args, options, callback, onError) {
|
|
3948
|
-
if (this.disabled) {
|
|
3949
|
-
return this.createDisabledUnsubscribe();
|
|
3950
|
-
}
|
|
3951
|
-
const paginationOptions = {
|
|
3952
|
-
initialNumItems: options.initialNumItems,
|
|
3953
|
-
id: -1
|
|
3954
|
-
};
|
|
3955
|
-
const { paginatedQueryToken, unsubscribe } = this.paginatedClient.subscribe(
|
|
3956
|
-
getFunctionName(query),
|
|
3957
|
-
args,
|
|
3958
|
-
// Simple client doesn't use IDs, there's no expectation that these queries remain separate.
|
|
3959
|
-
paginationOptions
|
|
3960
|
-
);
|
|
3961
|
-
const queryInfo = {
|
|
3962
|
-
queryToken: paginatedQueryToken,
|
|
3963
|
-
callback,
|
|
3964
|
-
onError,
|
|
3965
|
-
unsubscribe,
|
|
3966
|
-
hasEverRun: false,
|
|
3967
|
-
query,
|
|
3968
|
-
args,
|
|
3969
|
-
paginationOptions
|
|
3970
|
-
};
|
|
3971
|
-
this.listeners.add(queryInfo);
|
|
3972
|
-
if (!!this.paginatedClient.localQueryResultByToken(paginatedQueryToken) && this.callNewListenersWithCurrentValuesTimer === void 0) {
|
|
3973
|
-
this.callNewListenersWithCurrentValuesTimer = setTimeout(
|
|
3974
|
-
() => this.callNewListenersWithCurrentValues(),
|
|
3975
|
-
0
|
|
3976
|
-
);
|
|
3977
|
-
}
|
|
3978
|
-
const unsubscribeProps = {
|
|
3979
|
-
unsubscribe: () => {
|
|
3980
|
-
if (this.closed) {
|
|
3981
|
-
return;
|
|
3982
|
-
}
|
|
3983
|
-
this.listeners.delete(queryInfo);
|
|
3984
|
-
unsubscribe();
|
|
3985
|
-
},
|
|
3986
|
-
getCurrentValue: () => {
|
|
3987
|
-
const result = this.paginatedClient.localQueryResult(
|
|
3988
|
-
getFunctionName(query),
|
|
3989
|
-
args,
|
|
3990
|
-
paginationOptions
|
|
3991
|
-
);
|
|
3992
|
-
return result;
|
|
3993
|
-
},
|
|
3994
|
-
getQueryLogs: () => []
|
|
3995
|
-
// Paginated queries don't aggregate their logs
|
|
3996
|
-
};
|
|
3997
|
-
const ret = unsubscribeProps.unsubscribe;
|
|
3998
|
-
Object.assign(ret, unsubscribeProps);
|
|
3999
|
-
return ret;
|
|
4000
|
-
}
|
|
4001
|
-
// Run all callbacks that have never been run before if they have a query
|
|
4002
|
-
// result available now.
|
|
4003
|
-
callNewListenersWithCurrentValues() {
|
|
4004
|
-
this.callNewListenersWithCurrentValuesTimer = void 0;
|
|
4005
|
-
this._transition({ queries: [], paginatedQueries: [] }, true);
|
|
4006
|
-
}
|
|
4007
|
-
queryResultReady(queryToken) {
|
|
4008
|
-
return this.client.hasLocalQueryResultByToken(queryToken);
|
|
4009
|
-
}
|
|
4010
|
-
createDisabledUnsubscribe() {
|
|
4011
|
-
const disabledUnsubscribe = () => {
|
|
4012
|
-
};
|
|
4013
|
-
const unsubscribeProps = {
|
|
4014
|
-
unsubscribe: disabledUnsubscribe,
|
|
4015
|
-
getCurrentValue: () => void 0,
|
|
4016
|
-
getQueryLogs: () => void 0
|
|
4017
|
-
};
|
|
4018
|
-
Object.assign(disabledUnsubscribe, unsubscribeProps);
|
|
4019
|
-
return disabledUnsubscribe;
|
|
4020
|
-
}
|
|
4021
|
-
async close() {
|
|
4022
|
-
if (this.disabled) return;
|
|
4023
|
-
this.listeners.clear();
|
|
4024
|
-
this._closed = true;
|
|
4025
|
-
if (this._paginatedClient) {
|
|
4026
|
-
this._paginatedClient = void 0;
|
|
4027
|
-
}
|
|
4028
|
-
return this.client.close();
|
|
4029
|
-
}
|
|
4030
|
-
/**
|
|
4031
|
-
* Get the current JWT auth token and decoded claims.
|
|
4032
|
-
*/
|
|
4033
|
-
getAuth() {
|
|
4034
|
-
if (this.disabled) return;
|
|
4035
|
-
return this.client.getCurrentAuthClaims();
|
|
4036
|
-
}
|
|
4037
|
-
/**
|
|
4038
|
-
* Set the authentication token to be used for subsequent queries and mutations.
|
|
4039
|
-
* `fetchToken` will be called automatically again if a token expires.
|
|
4040
|
-
* `fetchToken` should return `null` if the token cannot be retrieved, for example
|
|
4041
|
-
* when the user's rights were permanently revoked.
|
|
4042
|
-
* @param fetchToken - an async function returning the JWT (typically an OpenID Connect Identity Token)
|
|
4043
|
-
* @param onChange - a callback that will be called when the authentication status changes
|
|
4044
|
-
*/
|
|
4045
|
-
setAuth(fetchToken, onChange) {
|
|
4046
|
-
if (this.disabled) return;
|
|
4047
|
-
this.client.setAuth(
|
|
4048
|
-
fetchToken,
|
|
4049
|
-
onChange ?? (() => {
|
|
4050
|
-
})
|
|
4051
|
-
);
|
|
4052
|
-
}
|
|
4053
|
-
/**
|
|
4054
|
-
* @internal
|
|
4055
|
-
*/
|
|
4056
|
-
setAdminAuth(token, identity) {
|
|
4057
|
-
if (this.closed) {
|
|
4058
|
-
throw new Error("ConvexClient has already been closed.");
|
|
4059
|
-
}
|
|
4060
|
-
if (this.disabled) return;
|
|
4061
|
-
this.client.setAdminAuth(token, identity);
|
|
4062
|
-
}
|
|
4063
|
-
/**
|
|
4064
|
-
* @internal
|
|
4065
|
-
*/
|
|
4066
|
-
_transition({
|
|
4067
|
-
queries,
|
|
4068
|
-
paginatedQueries
|
|
4069
|
-
}, callNewListeners = false) {
|
|
4070
|
-
const updatedQueries = [
|
|
4071
|
-
...queries.map((q) => q.token),
|
|
4072
|
-
...paginatedQueries.map((q) => q.token)
|
|
4073
|
-
];
|
|
4074
|
-
for (const queryInfo of this.listeners) {
|
|
4075
|
-
const { callback, queryToken, onError, hasEverRun } = queryInfo;
|
|
4076
|
-
const isPaginatedQuery = serializedQueryTokenIsPaginated(queryToken);
|
|
4077
|
-
const hasResultReady = isPaginatedQuery ? !!this.paginatedClient.localQueryResultByToken(queryToken) : this.client.hasLocalQueryResultByToken(queryToken);
|
|
4078
|
-
if (updatedQueries.includes(queryToken) || callNewListeners && !hasEverRun && hasResultReady) {
|
|
4079
|
-
queryInfo.hasEverRun = true;
|
|
4080
|
-
let newValue;
|
|
4081
|
-
try {
|
|
4082
|
-
if (isPaginatedQuery) {
|
|
4083
|
-
newValue = this.paginatedClient.localQueryResultByToken(queryToken);
|
|
4084
|
-
} else {
|
|
4085
|
-
newValue = this.client.localQueryResultByToken(queryToken);
|
|
4086
|
-
}
|
|
4087
|
-
} catch (error) {
|
|
4088
|
-
if (!(error instanceof Error)) throw error;
|
|
4089
|
-
if (onError) {
|
|
4090
|
-
onError(
|
|
4091
|
-
error,
|
|
4092
|
-
"Second argument to onUpdate onError is reserved for later use"
|
|
4093
|
-
);
|
|
4094
|
-
} else {
|
|
4095
|
-
void Promise.reject(error);
|
|
4096
|
-
}
|
|
4097
|
-
continue;
|
|
4098
|
-
}
|
|
4099
|
-
callback(
|
|
4100
|
-
newValue,
|
|
4101
|
-
"Second argument to onUpdate callback is reserved for later use"
|
|
4102
|
-
);
|
|
4103
|
-
}
|
|
4104
|
-
}
|
|
4105
|
-
}
|
|
4106
|
-
/**
|
|
4107
|
-
* Execute a mutation function.
|
|
4108
|
-
*
|
|
4109
|
-
* @param mutation - A {@link server.FunctionReference} for the public mutation
|
|
4110
|
-
* to run.
|
|
4111
|
-
* @param args - An arguments object for the mutation.
|
|
4112
|
-
* @param options - A {@link MutationOptions} options object for the mutation.
|
|
4113
|
-
* @returns A promise of the mutation's result.
|
|
4114
|
-
*/
|
|
4115
|
-
async mutation(mutation, args, options) {
|
|
4116
|
-
if (this.disabled) throw new Error("ConvexClient is disabled");
|
|
4117
|
-
return await this.client.mutation(getFunctionName(mutation), args, options);
|
|
4118
|
-
}
|
|
4119
|
-
/**
|
|
4120
|
-
* Execute an action function.
|
|
4121
|
-
*
|
|
4122
|
-
* @param action - A {@link server.FunctionReference} for the public action
|
|
4123
|
-
* to run.
|
|
4124
|
-
* @param args - An arguments object for the action.
|
|
4125
|
-
* @returns A promise of the action's result.
|
|
4126
|
-
*/
|
|
4127
|
-
async action(action, args) {
|
|
4128
|
-
if (this.disabled) throw new Error("ConvexClient is disabled");
|
|
4129
|
-
return await this.client.action(getFunctionName(action), args);
|
|
4130
|
-
}
|
|
4131
|
-
/**
|
|
4132
|
-
* Fetch a query result once.
|
|
4133
|
-
*
|
|
4134
|
-
* @param query - A {@link server.FunctionReference} for the public query
|
|
4135
|
-
* to run.
|
|
4136
|
-
* @param args - An arguments object for the query.
|
|
4137
|
-
* @returns A promise of the query's result.
|
|
4138
|
-
*/
|
|
4139
|
-
async query(query, args) {
|
|
4140
|
-
if (this.disabled) throw new Error("ConvexClient is disabled");
|
|
4141
|
-
const value = this.client.localQueryResult(getFunctionName(query), args);
|
|
4142
|
-
if (value !== void 0) return Promise.resolve(value);
|
|
4143
|
-
return new Promise((resolve, reject) => {
|
|
4144
|
-
const { unsubscribe } = this.onUpdate(
|
|
4145
|
-
query,
|
|
4146
|
-
args,
|
|
4147
|
-
(value2) => {
|
|
4148
|
-
unsubscribe();
|
|
4149
|
-
resolve(value2);
|
|
4150
|
-
},
|
|
4151
|
-
(e) => {
|
|
4152
|
-
unsubscribe();
|
|
4153
|
-
reject(e);
|
|
4154
|
-
}
|
|
4155
|
-
);
|
|
4156
|
-
});
|
|
4157
|
-
}
|
|
4158
|
-
/**
|
|
4159
|
-
* Get the current {@link ConnectionState} between the client and the Convex
|
|
4160
|
-
* backend.
|
|
4161
|
-
*
|
|
4162
|
-
* @returns The {@link ConnectionState} with the Convex backend.
|
|
4163
|
-
*/
|
|
4164
|
-
connectionState() {
|
|
4165
|
-
if (this.disabled) throw new Error("ConvexClient is disabled");
|
|
4166
|
-
return this.client.connectionState();
|
|
4167
|
-
}
|
|
4168
|
-
/**
|
|
4169
|
-
* Subscribe to the {@link ConnectionState} between the client and the Convex
|
|
4170
|
-
* backend, calling a callback each time it changes.
|
|
4171
|
-
*
|
|
4172
|
-
* Subscribed callbacks will be called when any part of ConnectionState changes.
|
|
4173
|
-
* ConnectionState may grow in future versions (e.g. to provide a array of
|
|
4174
|
-
* inflight requests) in which case callbacks would be called more frequently.
|
|
4175
|
-
*
|
|
4176
|
-
* @returns An unsubscribe function to stop listening.
|
|
4177
|
-
*/
|
|
4178
|
-
subscribeToConnectionState(cb) {
|
|
4179
|
-
if (this.disabled) return () => {
|
|
4180
|
-
};
|
|
4181
|
-
return this.client.subscribeToConnectionState(cb);
|
|
4182
|
-
}
|
|
4183
|
-
};
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { ConvexClient } from "convex/browser";
|
|
4184
3
|
|
|
4185
4
|
// src/services/lobby.ts
|
|
4186
|
-
|
|
5
|
+
import debounce from "lodash.debounce";
|
|
6
|
+
|
|
7
|
+
// src/constants.ts
|
|
8
|
+
import {
|
|
9
|
+
LOBBY_VISIBILITY,
|
|
10
|
+
LEADERBOARD_SORT_ORDER,
|
|
11
|
+
LEADERBOARD_DISPLAY_TYPE,
|
|
12
|
+
UGC_TYPE,
|
|
13
|
+
UGC_VISIBILITY,
|
|
14
|
+
GAME_ENGINE,
|
|
15
|
+
LOBBY_MESSAGE_MAX_LENGTH
|
|
16
|
+
} from "@wvdsh/api";
|
|
17
|
+
var LobbyKickedReason = {
|
|
18
|
+
KICKED: "KICKED",
|
|
19
|
+
ERROR: "ERROR"
|
|
20
|
+
};
|
|
21
|
+
var LobbyUserChangeType = {
|
|
22
|
+
JOINED: "JOINED",
|
|
23
|
+
LEFT: "LEFT"
|
|
24
|
+
};
|
|
25
|
+
var P2PPacketDropReason = {
|
|
26
|
+
QUEUE_FULL: "QUEUE_FULL",
|
|
27
|
+
PAYLOAD_TOO_LARGE: "PAYLOAD_TOO_LARGE",
|
|
28
|
+
INVALID_PAYLOAD_SIZE: "INVALID_PAYLOAD_SIZE",
|
|
29
|
+
INVALID_CHANNEL: "INVALID_CHANNEL",
|
|
30
|
+
MALFORMED: "MALFORMED",
|
|
31
|
+
PEER_NOT_READY: "PEER_NOT_READY"
|
|
32
|
+
};
|
|
33
|
+
var AvatarSize = {
|
|
34
|
+
SMALL: 64,
|
|
35
|
+
// Lists, chat bubbles
|
|
36
|
+
MEDIUM: 128,
|
|
37
|
+
// Profile cards
|
|
38
|
+
LARGE: 256
|
|
39
|
+
// Large displays
|
|
40
|
+
};
|
|
4187
41
|
|
|
4188
42
|
// src/events.ts
|
|
4189
43
|
var WavedashEvents = {
|
|
@@ -4227,22 +81,8 @@ var WavedashEvents = {
|
|
|
4227
81
|
// P2P_CONNECTION_REQUESTED: 'P2PConnectionRequested', // for now we always connect all lobby members
|
|
4228
82
|
};
|
|
4229
83
|
|
|
4230
|
-
// src/types.ts
|
|
4231
|
-
var LobbyKickedReason = {
|
|
4232
|
-
KICKED: "KICKED",
|
|
4233
|
-
ERROR: "ERROR"
|
|
4234
|
-
};
|
|
4235
|
-
var LobbyUserChangeType = {
|
|
4236
|
-
JOINED: "JOINED",
|
|
4237
|
-
LEFT: "LEFT"
|
|
4238
|
-
};
|
|
4239
|
-
|
|
4240
84
|
// src/services/lobby.ts
|
|
4241
|
-
import {
|
|
4242
|
-
api,
|
|
4243
|
-
IFRAME_MESSAGE_TYPE,
|
|
4244
|
-
LOBBY_MESSAGE_MAX_LENGTH
|
|
4245
|
-
} from "@wvdsh/api";
|
|
85
|
+
import { api, IFRAME_MESSAGE_TYPE } from "@wvdsh/api";
|
|
4246
86
|
var LobbyManager = class {
|
|
4247
87
|
constructor(sdk) {
|
|
4248
88
|
// Track current lobby state
|
|
@@ -4265,7 +105,7 @@ var LobbyManager = class {
|
|
|
4265
105
|
this.seenInviteIds = /* @__PURE__ */ new Set();
|
|
4266
106
|
// Queue for serializing P2P connection updates to prevent race conditions
|
|
4267
107
|
this.p2pUpdateQueue = Promise.resolve();
|
|
4268
|
-
this.debouncedMetadataUpdate = (
|
|
108
|
+
this.debouncedMetadataUpdate = debounce(
|
|
4269
109
|
() => this.processPendingLobbyDataUpdates(),
|
|
4270
110
|
50
|
|
4271
111
|
);
|
|
@@ -6561,7 +2401,7 @@ var P2PManager = _P2PManager;
|
|
|
6561
2401
|
|
|
6562
2402
|
// src/services/stats.ts
|
|
6563
2403
|
import { api as api6 } from "@wvdsh/api";
|
|
6564
|
-
|
|
2404
|
+
import debounce2 from "lodash.debounce";
|
|
6565
2405
|
var STORE_DEBOUNCE_MS = 1e3;
|
|
6566
2406
|
var StatsManager = class {
|
|
6567
2407
|
constructor(sdk) {
|
|
@@ -6585,7 +2425,7 @@ var StatsManager = class {
|
|
|
6585
2425
|
// Debounced persist — used by storeNow in setters to batch rapid calls.
|
|
6586
2426
|
// Leading+trailing: first call fires immediately, subsequent calls within
|
|
6587
2427
|
// the window are batched into one trailing call.
|
|
6588
|
-
this.debouncedPersist = (
|
|
2428
|
+
this.debouncedPersist = debounce2(() => this.persist(), STORE_DEBOUNCE_MS, {
|
|
6589
2429
|
leading: true,
|
|
6590
2430
|
trailing: true
|
|
6591
2431
|
});
|
|
@@ -6967,7 +2807,7 @@ var FullscreenManager = class {
|
|
|
6967
2807
|
(data) => {
|
|
6968
2808
|
this.sdk.gameEventManager.notifyGame(
|
|
6969
2809
|
WavedashEvents.FULLSCREEN_CHANGED,
|
|
6970
|
-
data.isFullscreen
|
|
2810
|
+
{ isFullscreen: data.isFullscreen }
|
|
6971
2811
|
);
|
|
6972
2812
|
this.setState(data.isFullscreen);
|
|
6973
2813
|
}
|
|
@@ -7049,7 +2889,6 @@ import { IFRAME_MESSAGE_TYPE as IFRAME_MESSAGE_TYPE4 } from "@wvdsh/api";
|
|
|
7049
2889
|
var OverlayManager = class {
|
|
7050
2890
|
constructor(sdk) {
|
|
7051
2891
|
this.handleKeyDown = (event) => {
|
|
7052
|
-
if (event.defaultPrevented) return;
|
|
7053
2892
|
if (event.key === "Tab" && event.shiftKey) {
|
|
7054
2893
|
event.preventDefault();
|
|
7055
2894
|
this.toggleOverlay();
|
|
@@ -7099,10 +2938,6 @@ function getCdnImageUrl(r2Key, host, options) {
|
|
|
7099
2938
|
}
|
|
7100
2939
|
|
|
7101
2940
|
// src/services/friends.ts
|
|
7102
|
-
var AVATAR_SIZE_SMALL = 0;
|
|
7103
|
-
var AVATAR_SIZE_MEDIUM = 1;
|
|
7104
|
-
var AVATAR_SIZE_LARGE = 2;
|
|
7105
|
-
var AVATAR_DIMENSIONS = [64, 128, 256];
|
|
7106
2941
|
var FriendsManager = class {
|
|
7107
2942
|
constructor(sdk) {
|
|
7108
2943
|
this.userCache = /* @__PURE__ */ new Map();
|
|
@@ -7123,20 +2958,20 @@ var FriendsManager = class {
|
|
|
7123
2958
|
}
|
|
7124
2959
|
}
|
|
7125
2960
|
/**
|
|
7126
|
-
* Returns CDN URL with size transformation for a cached user's avatar
|
|
2961
|
+
* Returns CDN URL with size transformation for a cached user's avatar.
|
|
7127
2962
|
* @param userId - The user ID to get the avatar URL for
|
|
7128
|
-
* @param size -
|
|
2963
|
+
* @param size - Pixel size for width and height. Use a value from
|
|
2964
|
+
* `AvatarSize` (SMALL=64, MEDIUM=128, LARGE=256) or any custom pixel size.
|
|
7129
2965
|
* @returns CDN URL with size transformation, or null if user not cached or has no avatar
|
|
7130
2966
|
*/
|
|
7131
|
-
getUserAvatarUrl(userId, size =
|
|
2967
|
+
getUserAvatarUrl(userId, size = AvatarSize.MEDIUM) {
|
|
7132
2968
|
const user = this.userCache.get(userId);
|
|
7133
2969
|
if (!user?.avatarR2Key) {
|
|
7134
2970
|
return null;
|
|
7135
2971
|
}
|
|
7136
|
-
const dimension = AVATAR_DIMENSIONS[size] ?? AVATAR_DIMENSIONS[AVATAR_SIZE_MEDIUM];
|
|
7137
2972
|
return getCdnImageUrl(user.avatarR2Key, this.sdk.uploadsHost, {
|
|
7138
|
-
width:
|
|
7139
|
-
height:
|
|
2973
|
+
width: size,
|
|
2974
|
+
height: size,
|
|
7140
2975
|
fit: "cover",
|
|
7141
2976
|
quality: "high",
|
|
7142
2977
|
sharpen: 1
|
|
@@ -7295,16 +3130,7 @@ var IFrameMessenger = class {
|
|
|
7295
3130
|
};
|
|
7296
3131
|
|
|
7297
3132
|
// src/index.ts
|
|
7298
|
-
import {
|
|
7299
|
-
GAME_ENGINE,
|
|
7300
|
-
IFRAME_MESSAGE_TYPE as IFRAME_MESSAGE_TYPE5,
|
|
7301
|
-
LEADERBOARD_DISPLAY_TYPE,
|
|
7302
|
-
LEADERBOARD_SORT_ORDER,
|
|
7303
|
-
LOBBY_VISIBILITY,
|
|
7304
|
-
UGC_TYPE,
|
|
7305
|
-
UGC_VISIBILITY,
|
|
7306
|
-
UrlParams
|
|
7307
|
-
} from "@wvdsh/api";
|
|
3133
|
+
import { IFRAME_MESSAGE_TYPE as IFRAME_MESSAGE_TYPE5, UrlParams } from "@wvdsh/api";
|
|
7308
3134
|
|
|
7309
3135
|
// src/utils/validation.ts
|
|
7310
3136
|
var CONVEX_ID_REGEX = /^[0-9a-z]{31,37}$/;
|
|
@@ -7419,12 +3245,28 @@ var WavedashSDK = class extends EventTarget {
|
|
|
7419
3245
|
this._eventsReady = false;
|
|
7420
3246
|
this.sessionEndSent = false;
|
|
7421
3247
|
this.gameFinishedLoading = false;
|
|
3248
|
+
// Expose constants for easy access `Wavedash.LobbyVisibility.PUBLIC` etc.
|
|
7422
3249
|
this.Events = WavedashEvents;
|
|
3250
|
+
this.LobbyVisibility = LOBBY_VISIBILITY;
|
|
3251
|
+
this.LeaderboardSortOrder = LEADERBOARD_SORT_ORDER;
|
|
3252
|
+
this.LeaderboardDisplayType = LEADERBOARD_DISPLAY_TYPE;
|
|
3253
|
+
this.UGCType = UGC_TYPE;
|
|
3254
|
+
this.UGCVisibility = UGC_VISIBILITY;
|
|
3255
|
+
this.AvatarSize = AvatarSize;
|
|
3256
|
+
this.LobbyKickedReason = LobbyKickedReason;
|
|
3257
|
+
this.LobbyUserChangeType = LobbyUserChangeType;
|
|
3258
|
+
this.P2PPacketDropReason = P2PPacketDropReason;
|
|
7423
3259
|
this.config = null;
|
|
7424
3260
|
this.engineCallbackReceiver = "WavedashCallbackReceiver";
|
|
7425
3261
|
this.engineInstance = null;
|
|
7426
3262
|
this.gameplayJwt = null;
|
|
7427
3263
|
this.gameplayJwtPromise = null;
|
|
3264
|
+
// ==============
|
|
3265
|
+
// Event listening
|
|
3266
|
+
// ==============
|
|
3267
|
+
// Wrappers stored so `off(event, listener)` can find the wrapped EventListener
|
|
3268
|
+
// we registered on the EventTarget for a given user-supplied payload listener.
|
|
3269
|
+
this.listenerWrappers = /* @__PURE__ */ new Map();
|
|
7428
3270
|
this.convexClient = new ConvexClient(sdkConfig.convexCloudUrl, {
|
|
7429
3271
|
expectAuth: true
|
|
7430
3272
|
});
|
|
@@ -7505,6 +3347,47 @@ var WavedashSDK = class extends EventTarget {
|
|
|
7505
3347
|
this._eventsReady = true;
|
|
7506
3348
|
this.gameEventManager.flushEventQueue();
|
|
7507
3349
|
}
|
|
3350
|
+
/**
|
|
3351
|
+
* Subscribe to a Wavedash event with a payload-typed listener.
|
|
3352
|
+
* Returns an unsubscribe function.
|
|
3353
|
+
*
|
|
3354
|
+
* const unsubscribeLobbyJoined = Wavedash.on(Wavedash.Events.LOBBY_JOINED, (payload) => {
|
|
3355
|
+
* // payload: LobbyJoinedPayload
|
|
3356
|
+
* });
|
|
3357
|
+
* unsubscribeLobbyJoined(); // later
|
|
3358
|
+
*/
|
|
3359
|
+
on(event, listener) {
|
|
3360
|
+
const wrapped = (e) => {
|
|
3361
|
+
listener(e.detail);
|
|
3362
|
+
};
|
|
3363
|
+
let perEvent = this.listenerWrappers.get(event);
|
|
3364
|
+
if (!perEvent) {
|
|
3365
|
+
perEvent = /* @__PURE__ */ new Map();
|
|
3366
|
+
this.listenerWrappers.set(event, perEvent);
|
|
3367
|
+
}
|
|
3368
|
+
const prev = perEvent.get(listener);
|
|
3369
|
+
if (prev) this.removeEventListener(event, prev);
|
|
3370
|
+
perEvent.set(listener, wrapped);
|
|
3371
|
+
this.addEventListener(event, wrapped);
|
|
3372
|
+
return () => this.off(event, listener);
|
|
3373
|
+
}
|
|
3374
|
+
/**
|
|
3375
|
+
* Remove a listener previously registered with {@link on}.
|
|
3376
|
+
*/
|
|
3377
|
+
off(event, listener) {
|
|
3378
|
+
const perEvent = this.listenerWrappers.get(event);
|
|
3379
|
+
const wrapped = perEvent?.get(listener);
|
|
3380
|
+
if (!perEvent || !wrapped) return;
|
|
3381
|
+
this.removeEventListener(event, wrapped);
|
|
3382
|
+
perEvent.delete(listener);
|
|
3383
|
+
if (perEvent.size === 0) this.listenerWrappers.delete(event);
|
|
3384
|
+
}
|
|
3385
|
+
addEventListener(type, listener, options) {
|
|
3386
|
+
super.addEventListener(type, listener, options);
|
|
3387
|
+
}
|
|
3388
|
+
removeEventListener(type, listener, options) {
|
|
3389
|
+
super.removeEventListener(type, listener, options);
|
|
3390
|
+
}
|
|
7508
3391
|
// ==================
|
|
7509
3392
|
// Entrypoint Helpers
|
|
7510
3393
|
// ==================
|
|
@@ -7620,10 +3503,10 @@ var WavedashSDK = class extends EventTarget {
|
|
|
7620
3503
|
* Get avatar URL for a cached user with size transformation.
|
|
7621
3504
|
* Users are cached when seen via listFriends() or lobby membership.
|
|
7622
3505
|
* @param userId - The user ID to get the avatar URL for
|
|
7623
|
-
* @param size - Avatar size constant (
|
|
3506
|
+
* @param size - Avatar size constant (Wavedash.AvatarSize.SMALL=0, Wavedash.AvatarSize.MEDIUM=1, Wavedash.AvatarSize.LARGE=2)
|
|
7624
3507
|
* @returns CDN URL with size transformation, or null if user not cached or has no avatar
|
|
7625
3508
|
*/
|
|
7626
|
-
getUserAvatarUrl(userId, size =
|
|
3509
|
+
getUserAvatarUrl(userId, size = this.AvatarSize.MEDIUM) {
|
|
7627
3510
|
return this.apiCallSync(
|
|
7628
3511
|
this.friendsManager,
|
|
7629
3512
|
"getUserAvatarUrl",
|
|
@@ -8361,7 +4244,7 @@ var WavedashSDK = class extends EventTarget {
|
|
|
8361
4244
|
}
|
|
8362
4245
|
};
|
|
8363
4246
|
function setupWavedashSDK() {
|
|
8364
|
-
const existing = window.
|
|
4247
|
+
const existing = window.Wavedash;
|
|
8365
4248
|
if (existing) return existing;
|
|
8366
4249
|
const raw = new URLSearchParams(window.location.search).get(
|
|
8367
4250
|
UrlParams.SdkConfig
|
|
@@ -8381,17 +4264,10 @@ function setupWavedashSDK() {
|
|
|
8381
4264
|
);
|
|
8382
4265
|
}
|
|
8383
4266
|
const sdk = new WavedashSDK(sdkConfig);
|
|
8384
|
-
window.WavedashJS = sdk;
|
|
8385
4267
|
window.Wavedash = sdk;
|
|
4268
|
+
window.WavedashJS = sdk;
|
|
8386
4269
|
return sdk;
|
|
8387
4270
|
}
|
|
8388
4271
|
export {
|
|
8389
|
-
AVATAR_SIZE_LARGE,
|
|
8390
|
-
AVATAR_SIZE_MEDIUM,
|
|
8391
|
-
AVATAR_SIZE_SMALL,
|
|
8392
|
-
LobbyKickedReason,
|
|
8393
|
-
LobbyUserChangeType,
|
|
8394
|
-
WavedashEvents,
|
|
8395
|
-
WavedashSDK,
|
|
8396
4272
|
setupWavedashSDK
|
|
8397
4273
|
};
|