@pooflabs/core 0.0.32 → 0.0.33
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/operations.d.ts +73 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +197 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +196 -14
- package/dist/index.mjs.map +1 -1
- package/dist/utils/server-session-manager.d.ts +1 -0
- package/package.json +1 -1
|
@@ -31,6 +31,79 @@ export type RunQueryOptions = {
|
|
|
31
31
|
headers?: Record<string, string>;
|
|
32
32
|
};
|
|
33
33
|
};
|
|
34
|
+
/**
|
|
35
|
+
* Supported aggregate operations for count/aggregate queries.
|
|
36
|
+
*/
|
|
37
|
+
export type AggregateOperation = 'count' | 'uniqueCount' | 'sum' | 'avg' | 'min' | 'max';
|
|
38
|
+
/**
|
|
39
|
+
* Result of a count or aggregate query — always a single numeric value.
|
|
40
|
+
*/
|
|
41
|
+
export type AggregateResult = {
|
|
42
|
+
value: number;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Options for the count function.
|
|
46
|
+
*/
|
|
47
|
+
export type CountOptions = {
|
|
48
|
+
/** Natural language filter prompt (e.g., "posts created in the last 7 days") */
|
|
49
|
+
prompt?: string;
|
|
50
|
+
/** Internal overrides for headers */
|
|
51
|
+
_overrides?: {
|
|
52
|
+
headers?: Record<string, string>;
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Options for the aggregate function.
|
|
57
|
+
*/
|
|
58
|
+
export type AggregateOptions = {
|
|
59
|
+
/** Natural language filter prompt */
|
|
60
|
+
prompt?: string;
|
|
61
|
+
/** Field name to aggregate on (required for sum, avg, min, max) */
|
|
62
|
+
field?: string;
|
|
63
|
+
/** Internal overrides for headers */
|
|
64
|
+
_overrides?: {
|
|
65
|
+
headers?: Record<string, string>;
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Count items in a collection path. Returns a numeric result.
|
|
70
|
+
*
|
|
71
|
+
* This uses the AI query engine with a count-specific prompt prefix,
|
|
72
|
+
* so TaroBase will generate a $count aggregation pipeline and return
|
|
73
|
+
* just the count rather than full documents.
|
|
74
|
+
*
|
|
75
|
+
* IMPORTANT: This only works for collections where the read policy is "true".
|
|
76
|
+
* If the read policy requires per-document checks, the server will return
|
|
77
|
+
* an error because aggregate counts cannot be performed without pulling all
|
|
78
|
+
* documents for access control evaluation.
|
|
79
|
+
*
|
|
80
|
+
* @param path - Collection path (e.g., "posts", "users/abc/comments")
|
|
81
|
+
* @param opts - Optional filter prompt and overrides
|
|
82
|
+
* @returns AggregateResult with the count value
|
|
83
|
+
*/
|
|
84
|
+
export declare function count(path: string, opts?: CountOptions): Promise<AggregateResult>;
|
|
85
|
+
/**
|
|
86
|
+
* Run an aggregate operation on a collection path. Returns a numeric result.
|
|
87
|
+
*
|
|
88
|
+
* Supported operations:
|
|
89
|
+
* - count: Total number of documents
|
|
90
|
+
* - uniqueCount: Number of distinct values for a field
|
|
91
|
+
* - sum: Sum of a numeric field
|
|
92
|
+
* - avg: Average of a numeric field
|
|
93
|
+
* - min: Minimum value of a numeric field
|
|
94
|
+
* - max: Maximum value of a numeric field
|
|
95
|
+
*
|
|
96
|
+
* IMPORTANT: This only works for collections where the read policy is "true".
|
|
97
|
+
* If the read policy requires per-document checks, the server will return
|
|
98
|
+
* an error because aggregate operations cannot be performed without pulling
|
|
99
|
+
* all documents for access control evaluation.
|
|
100
|
+
*
|
|
101
|
+
* @param path - Collection path (e.g., "posts", "users/abc/comments")
|
|
102
|
+
* @param operation - The aggregate operation to perform
|
|
103
|
+
* @param opts - Options including optional filter prompt and field name
|
|
104
|
+
* @returns AggregateResult with the computed numeric value
|
|
105
|
+
*/
|
|
106
|
+
export declare function aggregate(path: string, operation: AggregateOperation, opts?: AggregateOptions): Promise<AggregateResult>;
|
|
34
107
|
export declare function get(path: string, opts?: GetOptions): Promise<any>;
|
|
35
108
|
export type RunExpressionOptions = {
|
|
36
109
|
returnType?: 'Bool' | 'String' | 'Int' | 'UInt';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { init } from './client/config';
|
|
2
2
|
export { getConfig, ClientConfig } from './client/config';
|
|
3
|
-
export { get, set, setMany, setFile, getFiles, runQuery, runQueryMany, runExpression, runExpressionMany, signMessage, signTransaction, signAndSubmitTransaction, SetOptions, GetOptions, RunExpressionOptions, RunExpressionResult } from './client/operations';
|
|
3
|
+
export { get, set, setMany, setFile, getFiles, runQuery, runQueryMany, runExpression, runExpressionMany, signMessage, signTransaction, signAndSubmitTransaction, count, aggregate, SetOptions, GetOptions, CountOptions, AggregateOptions, AggregateOperation, AggregateResult, RunExpressionOptions, RunExpressionResult } from './client/operations';
|
|
4
4
|
export { subscribe, closeAllSubscriptions, clearCache, getCachedData, reconnectWithNewAuth } from './client/subscription';
|
|
5
5
|
export * from './types';
|
|
6
6
|
export { getIdToken } from './utils/utils';
|
package/dist/index.js
CHANGED
|
@@ -139,10 +139,14 @@ class WebSessionManager {
|
|
|
139
139
|
const newObj = JSON.parse(newSession);
|
|
140
140
|
return { address: newObj.address, session: newObj };
|
|
141
141
|
}
|
|
142
|
+
// Refresh failed — clear stale session to prevent retry loops
|
|
143
|
+
this.clearSession();
|
|
142
144
|
return null;
|
|
143
145
|
}
|
|
144
146
|
}
|
|
145
147
|
catch (err) {
|
|
148
|
+
// Token decode or refresh failed — clear stale session to prevent retry loops
|
|
149
|
+
this.clearSession();
|
|
146
150
|
return null;
|
|
147
151
|
}
|
|
148
152
|
return { address: sessionObj.address, session: sessionObj };
|
|
@@ -3066,15 +3070,30 @@ class ServerSessionManager {
|
|
|
3066
3070
|
constructor() {
|
|
3067
3071
|
/* Private cache (lives for the life of the process) */
|
|
3068
3072
|
this.session = null;
|
|
3073
|
+
/* Coalesce concurrent getSession() calls into a single in-flight request */
|
|
3074
|
+
this.pendingSession = null;
|
|
3069
3075
|
}
|
|
3070
3076
|
/* ---------------------------------------------- *
|
|
3071
3077
|
* GET (lazy-fetch)
|
|
3072
3078
|
* ---------------------------------------------- */
|
|
3073
3079
|
async getSession() {
|
|
3074
|
-
if (this.session
|
|
3075
|
-
this.session
|
|
3080
|
+
if (this.session !== null) {
|
|
3081
|
+
return this.session;
|
|
3082
|
+
}
|
|
3083
|
+
// If a session creation is already in-flight, reuse that promise
|
|
3084
|
+
// instead of firing a second concurrent request.
|
|
3085
|
+
if (this.pendingSession !== null) {
|
|
3086
|
+
return this.pendingSession;
|
|
3076
3087
|
}
|
|
3077
|
-
|
|
3088
|
+
this.pendingSession = createSession()
|
|
3089
|
+
.then((session) => {
|
|
3090
|
+
this.session = session;
|
|
3091
|
+
return session;
|
|
3092
|
+
})
|
|
3093
|
+
.finally(() => {
|
|
3094
|
+
this.pendingSession = null;
|
|
3095
|
+
});
|
|
3096
|
+
return this.pendingSession;
|
|
3078
3097
|
}
|
|
3079
3098
|
/* ---------------------------------------------- *
|
|
3080
3099
|
* STORE (overwrites the cached value)
|
|
@@ -3087,6 +3106,7 @@ class ServerSessionManager {
|
|
|
3087
3106
|
* ---------------------------------------------- */
|
|
3088
3107
|
clearSession() {
|
|
3089
3108
|
this.session = null;
|
|
3109
|
+
this.pendingSession = null;
|
|
3090
3110
|
}
|
|
3091
3111
|
/* ---------------------------------------------- *
|
|
3092
3112
|
* QUICK helpers
|
|
@@ -3389,6 +3409,150 @@ function hashForKey$1(value) {
|
|
|
3389
3409
|
}
|
|
3390
3410
|
return h.toString(36);
|
|
3391
3411
|
}
|
|
3412
|
+
/**
|
|
3413
|
+
* Validates that a field name is a safe identifier (alphanumeric, underscores, dots for nested paths).
|
|
3414
|
+
* Prevents prompt injection via crafted field names.
|
|
3415
|
+
*/
|
|
3416
|
+
function validateFieldName(field) {
|
|
3417
|
+
if (!/^[a-zA-Z0-9_.]+$/.test(field)) {
|
|
3418
|
+
throw new Error(`Invalid field name "${field}". Field names must only contain letters, numbers, underscores, and dots.`);
|
|
3419
|
+
}
|
|
3420
|
+
}
|
|
3421
|
+
/**
|
|
3422
|
+
* Parses a raw aggregation result (e.g. [{ count: 42 }] or [{ _id: null, total: 100 }])
|
|
3423
|
+
* into a single numeric value.
|
|
3424
|
+
*/
|
|
3425
|
+
function parseAggregateValue(result) {
|
|
3426
|
+
if (typeof result === 'number')
|
|
3427
|
+
return result;
|
|
3428
|
+
if (Array.isArray(result)) {
|
|
3429
|
+
if (result.length === 0)
|
|
3430
|
+
return 0;
|
|
3431
|
+
// Multiple elements — not a collapsed aggregate result
|
|
3432
|
+
if (result.length > 1) {
|
|
3433
|
+
throw new Error(`Unexpected aggregate result: got array with ${result.length} elements. The AI may have returned full documents instead of an aggregation.`);
|
|
3434
|
+
}
|
|
3435
|
+
const first = result[0];
|
|
3436
|
+
if (typeof first === 'number')
|
|
3437
|
+
return first;
|
|
3438
|
+
if (first && typeof first === 'object') {
|
|
3439
|
+
// $count stage returns { count: N }
|
|
3440
|
+
if (typeof first.count === 'number')
|
|
3441
|
+
return first.count;
|
|
3442
|
+
// $group stage returns { _id: null, result: N } — expect _id + one numeric field
|
|
3443
|
+
const numericEntries = Object.entries(first).filter(([key, val]) => key !== '_id' && typeof val === 'number');
|
|
3444
|
+
if (numericEntries.length === 1)
|
|
3445
|
+
return numericEntries[0][1];
|
|
3446
|
+
}
|
|
3447
|
+
// Avoid leaking document contents into error messages
|
|
3448
|
+
const shape = first && typeof first === 'object' ? `{${Object.keys(first).join(', ')}}` : String(first);
|
|
3449
|
+
throw new Error(`Unexpected aggregate result shape: ${shape}. Expected {count: N} or {_id: null, <field>: N}.`);
|
|
3450
|
+
}
|
|
3451
|
+
if (result && typeof result === 'object' && typeof result.count === 'number') {
|
|
3452
|
+
return result.count;
|
|
3453
|
+
}
|
|
3454
|
+
throw new Error(`Unexpected aggregate result type: ${typeof result}. Expected a number, array, or object with a count field.`);
|
|
3455
|
+
}
|
|
3456
|
+
/**
|
|
3457
|
+
* Count items in a collection path. Returns a numeric result.
|
|
3458
|
+
*
|
|
3459
|
+
* This uses the AI query engine with a count-specific prompt prefix,
|
|
3460
|
+
* so TaroBase will generate a $count aggregation pipeline and return
|
|
3461
|
+
* just the count rather than full documents.
|
|
3462
|
+
*
|
|
3463
|
+
* IMPORTANT: This only works for collections where the read policy is "true".
|
|
3464
|
+
* If the read policy requires per-document checks, the server will return
|
|
3465
|
+
* an error because aggregate counts cannot be performed without pulling all
|
|
3466
|
+
* documents for access control evaluation.
|
|
3467
|
+
*
|
|
3468
|
+
* @param path - Collection path (e.g., "posts", "users/abc/comments")
|
|
3469
|
+
* @param opts - Optional filter prompt and overrides
|
|
3470
|
+
* @returns AggregateResult with the count value
|
|
3471
|
+
*/
|
|
3472
|
+
async function count(path, opts = {}) {
|
|
3473
|
+
const prefix = 'Return ONLY the total count of matching documents. Use the $count stage to produce a field named "count". Do NOT return the documents themselves.';
|
|
3474
|
+
const fullPrompt = opts.prompt
|
|
3475
|
+
? `${prefix} Filter: ${opts.prompt}`
|
|
3476
|
+
: prefix;
|
|
3477
|
+
const result = await get(path, { prompt: fullPrompt, bypassCache: true, _overrides: opts._overrides });
|
|
3478
|
+
return { value: parseAggregateValue(result) };
|
|
3479
|
+
}
|
|
3480
|
+
/**
|
|
3481
|
+
* Run an aggregate operation on a collection path. Returns a numeric result.
|
|
3482
|
+
*
|
|
3483
|
+
* Supported operations:
|
|
3484
|
+
* - count: Total number of documents
|
|
3485
|
+
* - uniqueCount: Number of distinct values for a field
|
|
3486
|
+
* - sum: Sum of a numeric field
|
|
3487
|
+
* - avg: Average of a numeric field
|
|
3488
|
+
* - min: Minimum value of a numeric field
|
|
3489
|
+
* - max: Maximum value of a numeric field
|
|
3490
|
+
*
|
|
3491
|
+
* IMPORTANT: This only works for collections where the read policy is "true".
|
|
3492
|
+
* If the read policy requires per-document checks, the server will return
|
|
3493
|
+
* an error because aggregate operations cannot be performed without pulling
|
|
3494
|
+
* all documents for access control evaluation.
|
|
3495
|
+
*
|
|
3496
|
+
* @param path - Collection path (e.g., "posts", "users/abc/comments")
|
|
3497
|
+
* @param operation - The aggregate operation to perform
|
|
3498
|
+
* @param opts - Options including optional filter prompt and field name
|
|
3499
|
+
* @returns AggregateResult with the computed numeric value
|
|
3500
|
+
*/
|
|
3501
|
+
async function aggregate(path, operation, opts = {}) {
|
|
3502
|
+
let prefix;
|
|
3503
|
+
switch (operation) {
|
|
3504
|
+
case 'count':
|
|
3505
|
+
prefix = 'Return ONLY the total count of matching documents. Use the $count stage to produce a field named "count". Do NOT return the documents themselves.';
|
|
3506
|
+
break;
|
|
3507
|
+
case 'uniqueCount':
|
|
3508
|
+
if (!opts.field)
|
|
3509
|
+
throw new Error('aggregate "uniqueCount" requires a field option');
|
|
3510
|
+
validateFieldName(opts.field);
|
|
3511
|
+
prefix = `Return ONLY the count of unique/distinct values of the "${opts.field}" field. Use $group with _id set to "$${opts.field}" then $count to produce a field named "count". Do NOT return the documents themselves.`;
|
|
3512
|
+
break;
|
|
3513
|
+
case 'sum':
|
|
3514
|
+
if (!opts.field)
|
|
3515
|
+
throw new Error('aggregate "sum" requires a field option');
|
|
3516
|
+
validateFieldName(opts.field);
|
|
3517
|
+
prefix = `Return ONLY the sum of the "${opts.field}" field across all matching documents. Use $group with _id: null and result: { $sum: "$${opts.field}" }. Do NOT return the documents themselves.`;
|
|
3518
|
+
break;
|
|
3519
|
+
case 'avg':
|
|
3520
|
+
if (!opts.field)
|
|
3521
|
+
throw new Error('aggregate "avg" requires a field option');
|
|
3522
|
+
validateFieldName(opts.field);
|
|
3523
|
+
prefix = `Return ONLY the average of the "${opts.field}" field across all matching documents. Use $group with _id: null and result: { $avg: "$${opts.field}" }. Do NOT return the documents themselves.`;
|
|
3524
|
+
break;
|
|
3525
|
+
case 'min':
|
|
3526
|
+
if (!opts.field)
|
|
3527
|
+
throw new Error('aggregate "min" requires a field option');
|
|
3528
|
+
validateFieldName(opts.field);
|
|
3529
|
+
prefix = `Return ONLY the minimum value of the "${opts.field}" field across all matching documents. Use $group with _id: null and result: { $min: "$${opts.field}" }. Do NOT return the documents themselves.`;
|
|
3530
|
+
break;
|
|
3531
|
+
case 'max':
|
|
3532
|
+
if (!opts.field)
|
|
3533
|
+
throw new Error('aggregate "max" requires a field option');
|
|
3534
|
+
validateFieldName(opts.field);
|
|
3535
|
+
prefix = `Return ONLY the maximum value of the "${opts.field}" field across all matching documents. Use $group with _id: null and result: { $max: "$${opts.field}" }. Do NOT return the documents themselves.`;
|
|
3536
|
+
break;
|
|
3537
|
+
default:
|
|
3538
|
+
throw new Error(`Unsupported aggregate operation: ${operation}`);
|
|
3539
|
+
}
|
|
3540
|
+
const fullPrompt = opts.prompt
|
|
3541
|
+
? `${prefix} Filter: ${opts.prompt}`
|
|
3542
|
+
: prefix;
|
|
3543
|
+
const result = await get(path, { prompt: fullPrompt, bypassCache: true, _overrides: opts._overrides });
|
|
3544
|
+
// For uniqueCount, the AI may return $group results without the final $count
|
|
3545
|
+
// stage, producing [{_id: "val1"}, {_id: "val2"}, ...]. Verify elements look
|
|
3546
|
+
// like $group output (only _id key) before using array length as the count.
|
|
3547
|
+
if (operation === 'uniqueCount' && Array.isArray(result) && result.length > 1) {
|
|
3548
|
+
const looksLikeGroupOutput = result.every((el) => el && typeof el === 'object' && Object.keys(el).length === 1 && '_id' in el);
|
|
3549
|
+
if (looksLikeGroupOutput) {
|
|
3550
|
+
return { value: result.length };
|
|
3551
|
+
}
|
|
3552
|
+
throw new Error(`Unexpected uniqueCount result: got ${result.length} elements that don't match $group output shape.`);
|
|
3553
|
+
}
|
|
3554
|
+
return { value: parseAggregateValue(result) };
|
|
3555
|
+
}
|
|
3392
3556
|
async function get(path, opts = {}) {
|
|
3393
3557
|
try {
|
|
3394
3558
|
let normalizedPath = path.startsWith("/") ? path.slice(1) : path;
|
|
@@ -3855,7 +4019,7 @@ const BASE_MIN_RECONNECT_DELAY_MS = 1000;
|
|
|
3855
4019
|
const MIN_RECONNECT_DELAY_JITTER_MS = 1000;
|
|
3856
4020
|
const MAX_RECONNECT_DELAY_MS = 300000;
|
|
3857
4021
|
const RECONNECT_DELAY_GROW_FACTOR = 1.8;
|
|
3858
|
-
const MIN_BROWSER_RECONNECT_INTERVAL_MS =
|
|
4022
|
+
const MIN_BROWSER_RECONNECT_INTERVAL_MS = 5000;
|
|
3859
4023
|
const WS_CONFIG = {
|
|
3860
4024
|
// Keep retrying indefinitely so long outages recover without page refresh.
|
|
3861
4025
|
maxRetries: Infinity,
|
|
@@ -4020,6 +4184,8 @@ async function getOrCreateConnection(appId, isServer) {
|
|
|
4020
4184
|
isConnected: false,
|
|
4021
4185
|
appId,
|
|
4022
4186
|
tokenRefreshTimer: null,
|
|
4187
|
+
lastMessageAt: Date.now(),
|
|
4188
|
+
keepaliveTimer: null,
|
|
4023
4189
|
};
|
|
4024
4190
|
connections.set(appId, connection);
|
|
4025
4191
|
// URL provider for reconnection with fresh tokens
|
|
@@ -4056,6 +4222,7 @@ async function getOrCreateConnection(appId, isServer) {
|
|
|
4056
4222
|
ws.addEventListener('open', () => {
|
|
4057
4223
|
connection.isConnecting = false;
|
|
4058
4224
|
connection.isConnected = true;
|
|
4225
|
+
connection.lastMessageAt = Date.now();
|
|
4059
4226
|
// Schedule token refresh before expiry
|
|
4060
4227
|
(async () => {
|
|
4061
4228
|
const token = await getIdToken(isServer);
|
|
@@ -4063,11 +4230,28 @@ async function getOrCreateConnection(appId, isServer) {
|
|
|
4063
4230
|
})();
|
|
4064
4231
|
// Re-subscribe to all existing subscriptions after reconnect
|
|
4065
4232
|
for (const sub of connection.subscriptions.values()) {
|
|
4233
|
+
sub.lastData = undefined;
|
|
4066
4234
|
sendSubscribe(connection, sub);
|
|
4067
4235
|
}
|
|
4236
|
+
// Start keepalive detection — if no messages for 90s, force reconnect
|
|
4237
|
+
if (connection.keepaliveTimer) {
|
|
4238
|
+
clearInterval(connection.keepaliveTimer);
|
|
4239
|
+
}
|
|
4240
|
+
connection.keepaliveTimer = setInterval(() => {
|
|
4241
|
+
var _a;
|
|
4242
|
+
if (Date.now() - connection.lastMessageAt > 90000) {
|
|
4243
|
+
console.warn('[WS v2] No messages received for 90s, forcing reconnect');
|
|
4244
|
+
if (connection.keepaliveTimer) {
|
|
4245
|
+
clearInterval(connection.keepaliveTimer);
|
|
4246
|
+
connection.keepaliveTimer = null;
|
|
4247
|
+
}
|
|
4248
|
+
(_a = connection.ws) === null || _a === void 0 ? void 0 : _a.reconnect();
|
|
4249
|
+
}
|
|
4250
|
+
}, 30000);
|
|
4068
4251
|
});
|
|
4069
4252
|
// Handle incoming messages
|
|
4070
4253
|
ws.addEventListener('message', (event) => {
|
|
4254
|
+
connection.lastMessageAt = Date.now();
|
|
4071
4255
|
try {
|
|
4072
4256
|
const message = JSON.parse(event.data);
|
|
4073
4257
|
handleServerMessage(connection, message);
|
|
@@ -4079,20 +4263,22 @@ async function getOrCreateConnection(appId, isServer) {
|
|
|
4079
4263
|
// Handle errors
|
|
4080
4264
|
ws.addEventListener('error', (event) => {
|
|
4081
4265
|
console.error('[WS v2] WebSocket error:', event);
|
|
4082
|
-
|
|
4083
|
-
for (const [id, pending] of connection.pendingSubscriptions) {
|
|
4266
|
+
for (const [, pending] of connection.pendingSubscriptions) {
|
|
4084
4267
|
pending.reject(new Error('WebSocket error'));
|
|
4085
|
-
connection.pendingSubscriptions.delete(id);
|
|
4086
4268
|
}
|
|
4269
|
+
connection.pendingSubscriptions.clear();
|
|
4087
4270
|
});
|
|
4088
4271
|
// Handle close
|
|
4089
4272
|
ws.addEventListener('close', () => {
|
|
4090
4273
|
connection.isConnected = false;
|
|
4091
|
-
// Clear token refresh timer
|
|
4092
4274
|
if (connection.tokenRefreshTimer) {
|
|
4093
4275
|
clearTimeout(connection.tokenRefreshTimer);
|
|
4094
4276
|
connection.tokenRefreshTimer = null;
|
|
4095
4277
|
}
|
|
4278
|
+
if (connection.keepaliveTimer) {
|
|
4279
|
+
clearInterval(connection.keepaliveTimer);
|
|
4280
|
+
connection.keepaliveTimer = null;
|
|
4281
|
+
}
|
|
4096
4282
|
});
|
|
4097
4283
|
return connection;
|
|
4098
4284
|
}
|
|
@@ -4292,9 +4478,7 @@ async function subscribeV2(path, subscriptionOptions) {
|
|
|
4292
4478
|
await subscriptionPromise;
|
|
4293
4479
|
}
|
|
4294
4480
|
catch (error) {
|
|
4295
|
-
|
|
4296
|
-
connection.subscriptions.delete(subscriptionId);
|
|
4297
|
-
throw error;
|
|
4481
|
+
console.warn('[WS v2] Subscription confirmation failed, keeping for reconnect recovery:', error);
|
|
4298
4482
|
}
|
|
4299
4483
|
}
|
|
4300
4484
|
// Return unsubscribe function
|
|
@@ -4410,8 +4594,6 @@ async function reconnectWithNewAuthV2() {
|
|
|
4410
4594
|
if (!connection.ws) {
|
|
4411
4595
|
continue;
|
|
4412
4596
|
}
|
|
4413
|
-
// Reject any pending subscriptions - they'll need to be retried after reconnect
|
|
4414
|
-
// This prevents hanging promises during auth transitions
|
|
4415
4597
|
for (const [, pending] of connection.pendingSubscriptions) {
|
|
4416
4598
|
pending.reject(new Error('Connection reconnecting due to auth change'));
|
|
4417
4599
|
}
|
|
@@ -4505,10 +4687,12 @@ async function reconnectWithNewAuth() {
|
|
|
4505
4687
|
|
|
4506
4688
|
exports.ServerSessionManager = ServerSessionManager;
|
|
4507
4689
|
exports.WebSessionManager = WebSessionManager;
|
|
4690
|
+
exports.aggregate = aggregate;
|
|
4508
4691
|
exports.buildSetDocumentsTransaction = buildSetDocumentsTransaction;
|
|
4509
4692
|
exports.clearCache = clearCache;
|
|
4510
4693
|
exports.closeAllSubscriptions = closeAllSubscriptions;
|
|
4511
4694
|
exports.convertRemainingAccounts = convertRemainingAccounts;
|
|
4695
|
+
exports.count = count;
|
|
4512
4696
|
exports.createSessionWithPrivy = createSessionWithPrivy;
|
|
4513
4697
|
exports.createSessionWithSignature = createSessionWithSignature;
|
|
4514
4698
|
exports.genAuthNonce = genAuthNonce;
|