@dvina/sdk 4.0.215 → 4.0.220
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/adapters/angular/index.cjs +4 -4
- package/dist/adapters/angular/index.d.cts +2 -2
- package/dist/adapters/angular/index.d.ts +2 -2
- package/dist/adapters/angular/index.js +2 -2
- package/dist/billing/index.cjs +5 -5
- package/dist/billing/index.js +1 -1
- package/dist/{chunk-BJDU4UX4.js → chunk-6PAEAOGQ.js} +508 -247
- package/dist/chunk-6PAEAOGQ.js.map +1 -0
- package/dist/{chunk-XK5PW7IX.cjs → chunk-CGJTK2BE.cjs} +531 -270
- package/dist/chunk-CGJTK2BE.cjs.map +1 -0
- package/dist/{chunk-Y4OD5SDF.cjs → chunk-VDPZQ5F3.cjs} +41 -6
- package/dist/chunk-VDPZQ5F3.cjs.map +1 -0
- package/dist/{chunk-Q5XGHH7D.js → chunk-ZGGY4WK7.js} +42 -5
- package/dist/chunk-ZGGY4WK7.js.map +1 -0
- package/dist/{client-Bn-0nJ8y.d.ts → client-C0CA6PHq.d.ts} +1 -1
- package/dist/{client-Ca2wlmC4.d.cts → client-XvsWJ1Z1.d.cts} +1 -1
- package/dist/{index-D50r0Gl0.d.ts → index-Bld5-Yr1.d.ts} +1 -1
- package/dist/{index-Ct2Mh0zl.d.cts → index-DF59UYzN.d.cts} +1 -1
- package/dist/index.cjs +387 -387
- package/dist/index.d.cts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +2 -2
- package/dist/pagination/index.d.cts +2 -2
- package/dist/pagination/index.d.ts +2 -2
- package/dist/{sync-engine-D35aV8Zc.d.ts → sync-engine-CZ0U9XBy.d.ts} +14 -9
- package/dist/{sync-engine-21OlgS5_.d.cts → sync-engine-DXESBFX0.d.cts} +14 -9
- package/package.json +1 -1
- package/dist/chunk-BJDU4UX4.js.map +0 -1
- package/dist/chunk-Q5XGHH7D.js.map +0 -1
- package/dist/chunk-XK5PW7IX.cjs.map +0 -1
- package/dist/chunk-Y4OD5SDF.cjs.map +0 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var chunk342BFYZZ_cjs = require('./chunk-342BFYZZ.cjs');
|
|
4
4
|
var chunkUELAE75E_cjs = require('./chunk-UELAE75E.cjs');
|
|
5
|
-
var
|
|
5
|
+
var chunkVDPZQ5F3_cjs = require('./chunk-VDPZQ5F3.cjs');
|
|
6
6
|
var chunkKV5SP7RP_cjs = require('./chunk-KV5SP7RP.cjs');
|
|
7
7
|
var chunk32A6N4YK_cjs = require('./chunk-32A6N4YK.cjs');
|
|
8
8
|
var chunkDZUJEN5N_cjs = require('./chunk-DZUJEN5N.cjs');
|
|
@@ -6035,6 +6035,7 @@ var require_dexie = chunkDZUJEN5N_cjs.__commonJS({
|
|
|
6035
6035
|
// src/chat-stream.ts
|
|
6036
6036
|
var INITIAL_RECONNECT_DELAY_MS = 1e3;
|
|
6037
6037
|
var MAX_RECONNECT_DELAY_MS = 3e4;
|
|
6038
|
+
var RECONNECT_BACKOFF_MULTIPLIER = 2;
|
|
6038
6039
|
var MAX_CONSECUTIVE_AUTH_FAILURES = 3;
|
|
6039
6040
|
var AuthChatStreamError = class extends Error {
|
|
6040
6041
|
constructor(status) {
|
|
@@ -6048,63 +6049,24 @@ var ChatStreamConnection = class {
|
|
|
6048
6049
|
this.chatId = chatId;
|
|
6049
6050
|
this.options = options;
|
|
6050
6051
|
this.onEmpty = onEmpty;
|
|
6051
|
-
this.supervisor = new chunkY4OD5SDF_cjs.ConnectionSupervisor({
|
|
6052
|
-
authRetryDelayMs: INITIAL_RECONNECT_DELAY_MS,
|
|
6053
|
-
baseReconnectDelayMs: INITIAL_RECONNECT_DELAY_MS,
|
|
6054
|
-
getToken: options.getToken,
|
|
6055
|
-
id: chatId,
|
|
6056
|
-
isAuthError: (error) => error instanceof AuthChatStreamError,
|
|
6057
|
-
kind: "chat-sse",
|
|
6058
|
-
maxConsecutiveAuthFailures: MAX_CONSECUTIVE_AUTH_FAILURES,
|
|
6059
|
-
maxReconnectDelayMs: MAX_RECONNECT_DELAY_MS,
|
|
6060
|
-
onFatalError: () => {
|
|
6061
|
-
const authError = new chunkKV5SP7RP_cjs.DvinaAuthenticationError("Chat SSE stream authentication failed permanently");
|
|
6062
|
-
this.options.onError?.(authError);
|
|
6063
|
-
this.close(authError);
|
|
6064
|
-
},
|
|
6065
|
-
dial: async (context) => {
|
|
6066
|
-
const url = new URL(`${this.options.baseUrl}/${encodeURIComponent(this.chatId)}/stream`);
|
|
6067
|
-
if (this.lastEventId) {
|
|
6068
|
-
url.searchParams.set("lastEventId", this.lastEventId);
|
|
6069
|
-
}
|
|
6070
|
-
const response = await fetch(url.toString(), {
|
|
6071
|
-
method: "GET",
|
|
6072
|
-
headers: {
|
|
6073
|
-
Accept: "text/event-stream",
|
|
6074
|
-
Authorization: `Bearer ${context.token}`,
|
|
6075
|
-
"Cache-Control": "no-cache",
|
|
6076
|
-
...this.lastEventId ? { "Last-Event-ID": this.lastEventId } : {}
|
|
6077
|
-
},
|
|
6078
|
-
signal: context.signal
|
|
6079
|
-
});
|
|
6080
|
-
if (!response.ok) {
|
|
6081
|
-
if (response.status === 401 || response.status === 403) {
|
|
6082
|
-
throw new AuthChatStreamError(response.status);
|
|
6083
|
-
}
|
|
6084
|
-
throw new Error(`Chat stream connection failed: ${response.status} ${response.statusText}`);
|
|
6085
|
-
}
|
|
6086
|
-
if (!response.body) {
|
|
6087
|
-
throw new Error("Chat stream response has no body");
|
|
6088
|
-
}
|
|
6089
|
-
context.markConnected();
|
|
6090
|
-
await chunkY4OD5SDF_cjs.consumeSseStream(response.body, context.signal, {
|
|
6091
|
-
onChunk: () => context.markActivity(),
|
|
6092
|
-
onEventBlock: (block) => this.processEventBlock(block, context.requestTokenRefresh)
|
|
6093
|
-
});
|
|
6094
|
-
}
|
|
6095
|
-
});
|
|
6096
6052
|
}
|
|
6053
|
+
abortController;
|
|
6054
|
+
consecutiveAuthFailures = 0;
|
|
6097
6055
|
destroyed = false;
|
|
6098
6056
|
lastEventId;
|
|
6057
|
+
needsForceRefresh = false;
|
|
6058
|
+
reconnectDelay = INITIAL_RECONNECT_DELAY_MS;
|
|
6059
|
+
reconnectTimer;
|
|
6060
|
+
shouldReconnect = false;
|
|
6099
6061
|
subscribers = /* @__PURE__ */ new Set();
|
|
6100
|
-
supervisor;
|
|
6101
6062
|
addSubscriber(subscriber) {
|
|
6102
6063
|
if (this.destroyed) {
|
|
6103
6064
|
throw new Error(`Chat stream '${this.chatId}' is closed`);
|
|
6104
6065
|
}
|
|
6105
6066
|
this.subscribers.add(subscriber);
|
|
6106
|
-
if (this.
|
|
6107
|
-
|
|
6067
|
+
if (!this.shouldReconnect) {
|
|
6068
|
+
this.shouldReconnect = true;
|
|
6069
|
+
void this.doConnect();
|
|
6108
6070
|
}
|
|
6109
6071
|
}
|
|
6110
6072
|
removeSubscriber(subscriber) {
|
|
@@ -6114,17 +6076,30 @@ var ChatStreamConnection = class {
|
|
|
6114
6076
|
}
|
|
6115
6077
|
}
|
|
6116
6078
|
reconnect() {
|
|
6117
|
-
if (this.destroyed || this.subscribers.size === 0) {
|
|
6079
|
+
if (!this.shouldReconnect || this.destroyed || this.subscribers.size === 0) {
|
|
6118
6080
|
return;
|
|
6119
6081
|
}
|
|
6120
|
-
this.
|
|
6082
|
+
if (this.reconnectTimer) {
|
|
6083
|
+
clearTimeout(this.reconnectTimer);
|
|
6084
|
+
this.reconnectTimer = void 0;
|
|
6085
|
+
}
|
|
6086
|
+
if (this.abortController) {
|
|
6087
|
+
this.abortController.abort();
|
|
6088
|
+
this.abortController = void 0;
|
|
6089
|
+
}
|
|
6090
|
+
void this.doConnect();
|
|
6121
6091
|
}
|
|
6122
6092
|
close(error) {
|
|
6123
|
-
|
|
6124
|
-
return;
|
|
6125
|
-
}
|
|
6093
|
+
this.shouldReconnect = false;
|
|
6126
6094
|
this.destroyed = true;
|
|
6127
|
-
this.
|
|
6095
|
+
if (this.reconnectTimer) {
|
|
6096
|
+
clearTimeout(this.reconnectTimer);
|
|
6097
|
+
this.reconnectTimer = void 0;
|
|
6098
|
+
}
|
|
6099
|
+
if (this.abortController) {
|
|
6100
|
+
this.abortController.abort();
|
|
6101
|
+
this.abortController = void 0;
|
|
6102
|
+
}
|
|
6128
6103
|
for (const subscriber of Array.from(this.subscribers)) {
|
|
6129
6104
|
subscriber.finish(error);
|
|
6130
6105
|
}
|
|
@@ -6134,7 +6109,94 @@ var ChatStreamConnection = class {
|
|
|
6134
6109
|
get isDestroyed() {
|
|
6135
6110
|
return this.destroyed;
|
|
6136
6111
|
}
|
|
6137
|
-
|
|
6112
|
+
async doConnect() {
|
|
6113
|
+
if (!this.shouldReconnect || this.destroyed || this.subscribers.size === 0) {
|
|
6114
|
+
return;
|
|
6115
|
+
}
|
|
6116
|
+
this.abortController = new AbortController();
|
|
6117
|
+
try {
|
|
6118
|
+
const forceRefresh = this.needsForceRefresh;
|
|
6119
|
+
this.needsForceRefresh = false;
|
|
6120
|
+
const token = await this.options.getToken(forceRefresh ? { forceRefresh: true } : void 0);
|
|
6121
|
+
const url = new URL(`${this.options.baseUrl}/${encodeURIComponent(this.chatId)}/stream`);
|
|
6122
|
+
if (this.lastEventId) {
|
|
6123
|
+
url.searchParams.set("lastEventId", this.lastEventId);
|
|
6124
|
+
}
|
|
6125
|
+
const response = await fetch(url.toString(), {
|
|
6126
|
+
method: "GET",
|
|
6127
|
+
headers: {
|
|
6128
|
+
Accept: "text/event-stream",
|
|
6129
|
+
Authorization: `Bearer ${token}`,
|
|
6130
|
+
"Cache-Control": "no-cache",
|
|
6131
|
+
...this.lastEventId ? { "Last-Event-ID": this.lastEventId } : {}
|
|
6132
|
+
},
|
|
6133
|
+
signal: this.abortController.signal
|
|
6134
|
+
});
|
|
6135
|
+
if (!response.ok) {
|
|
6136
|
+
if (response.status === 401 || response.status === 403) {
|
|
6137
|
+
throw new AuthChatStreamError(response.status);
|
|
6138
|
+
}
|
|
6139
|
+
throw new Error(`Chat stream connection failed: ${response.status} ${response.statusText}`);
|
|
6140
|
+
}
|
|
6141
|
+
if (!response.body) {
|
|
6142
|
+
throw new Error("Chat stream response has no body");
|
|
6143
|
+
}
|
|
6144
|
+
this.consecutiveAuthFailures = 0;
|
|
6145
|
+
this.reconnectDelay = INITIAL_RECONNECT_DELAY_MS;
|
|
6146
|
+
await this.parseSseStream(response.body, this.abortController.signal);
|
|
6147
|
+
} catch (error) {
|
|
6148
|
+
if (error.name === "AbortError") {
|
|
6149
|
+
return;
|
|
6150
|
+
}
|
|
6151
|
+
if (!this.shouldReconnect || this.destroyed || this.subscribers.size === 0) {
|
|
6152
|
+
return;
|
|
6153
|
+
}
|
|
6154
|
+
const isAuthError2 = error instanceof AuthChatStreamError;
|
|
6155
|
+
if (isAuthError2) {
|
|
6156
|
+
this.consecutiveAuthFailures += 1;
|
|
6157
|
+
if (this.consecutiveAuthFailures >= MAX_CONSECUTIVE_AUTH_FAILURES) {
|
|
6158
|
+
const authError = new chunkKV5SP7RP_cjs.DvinaAuthenticationError("Chat SSE stream authentication failed permanently");
|
|
6159
|
+
this.options.onError?.(authError);
|
|
6160
|
+
this.close(authError);
|
|
6161
|
+
return;
|
|
6162
|
+
}
|
|
6163
|
+
this.needsForceRefresh = true;
|
|
6164
|
+
}
|
|
6165
|
+
const delay = isAuthError2 ? INITIAL_RECONNECT_DELAY_MS : this.reconnectDelay;
|
|
6166
|
+
this.scheduleReconnect(delay);
|
|
6167
|
+
if (!isAuthError2) {
|
|
6168
|
+
this.reconnectDelay = Math.min(
|
|
6169
|
+
this.reconnectDelay * RECONNECT_BACKOFF_MULTIPLIER,
|
|
6170
|
+
MAX_RECONNECT_DELAY_MS
|
|
6171
|
+
);
|
|
6172
|
+
}
|
|
6173
|
+
}
|
|
6174
|
+
}
|
|
6175
|
+
async parseSseStream(body, signal) {
|
|
6176
|
+
const reader = body.getReader();
|
|
6177
|
+
const decoder = new TextDecoder();
|
|
6178
|
+
let buffer = "";
|
|
6179
|
+
try {
|
|
6180
|
+
while (!signal.aborted && this.shouldReconnect && !this.destroyed) {
|
|
6181
|
+
const { done, value } = await reader.read();
|
|
6182
|
+
if (done) {
|
|
6183
|
+
break;
|
|
6184
|
+
}
|
|
6185
|
+
buffer += decoder.decode(value, { stream: true });
|
|
6186
|
+
const parts = buffer.split(/(?:\r\n|\r|\n){2}/);
|
|
6187
|
+
buffer = parts.pop() ?? "";
|
|
6188
|
+
for (const part of parts) {
|
|
6189
|
+
this.processEventBlock(part.trim());
|
|
6190
|
+
}
|
|
6191
|
+
}
|
|
6192
|
+
} finally {
|
|
6193
|
+
reader.releaseLock();
|
|
6194
|
+
}
|
|
6195
|
+
if (this.shouldReconnect && !this.destroyed && this.subscribers.size > 0) {
|
|
6196
|
+
this.scheduleReconnect(this.reconnectDelay);
|
|
6197
|
+
}
|
|
6198
|
+
}
|
|
6199
|
+
processEventBlock(block) {
|
|
6138
6200
|
if (!block || block.startsWith(":")) {
|
|
6139
6201
|
return;
|
|
6140
6202
|
}
|
|
@@ -6151,8 +6213,8 @@ var ChatStreamConnection = class {
|
|
|
6151
6213
|
}
|
|
6152
6214
|
}
|
|
6153
6215
|
if (eventType === "token-expired") {
|
|
6154
|
-
|
|
6155
|
-
|
|
6216
|
+
this.needsForceRefresh = true;
|
|
6217
|
+
return;
|
|
6156
6218
|
}
|
|
6157
6219
|
if (!eventId || dataLines.length === 0) {
|
|
6158
6220
|
return;
|
|
@@ -6169,64 +6231,40 @@ var ChatStreamConnection = class {
|
|
|
6169
6231
|
subscriber.push(value);
|
|
6170
6232
|
}
|
|
6171
6233
|
}
|
|
6234
|
+
scheduleReconnect(delay) {
|
|
6235
|
+
if (!this.shouldReconnect || this.destroyed || this.subscribers.size === 0) {
|
|
6236
|
+
return;
|
|
6237
|
+
}
|
|
6238
|
+
if (this.reconnectTimer) {
|
|
6239
|
+
clearTimeout(this.reconnectTimer);
|
|
6240
|
+
}
|
|
6241
|
+
this.reconnectTimer = setTimeout(() => {
|
|
6242
|
+
this.reconnectTimer = void 0;
|
|
6243
|
+
void this.doConnect();
|
|
6244
|
+
}, delay);
|
|
6245
|
+
}
|
|
6172
6246
|
};
|
|
6173
6247
|
var ActiveChatStreamConnection = class {
|
|
6174
6248
|
constructor(options, onEmpty) {
|
|
6175
6249
|
this.options = options;
|
|
6176
6250
|
this.onEmpty = onEmpty;
|
|
6177
|
-
this.supervisor = new chunkY4OD5SDF_cjs.ConnectionSupervisor({
|
|
6178
|
-
authRetryDelayMs: INITIAL_RECONNECT_DELAY_MS,
|
|
6179
|
-
baseReconnectDelayMs: INITIAL_RECONNECT_DELAY_MS,
|
|
6180
|
-
getToken: options.getToken,
|
|
6181
|
-
id: "active",
|
|
6182
|
-
isAuthError: (error) => error instanceof AuthChatStreamError,
|
|
6183
|
-
kind: "active-chat-sse",
|
|
6184
|
-
maxConsecutiveAuthFailures: MAX_CONSECUTIVE_AUTH_FAILURES,
|
|
6185
|
-
maxReconnectDelayMs: MAX_RECONNECT_DELAY_MS,
|
|
6186
|
-
onFatalError: () => {
|
|
6187
|
-
const authError = new chunkKV5SP7RP_cjs.DvinaAuthenticationError(
|
|
6188
|
-
"Active chat SSE stream authentication failed permanently"
|
|
6189
|
-
);
|
|
6190
|
-
this.options.onError?.(authError);
|
|
6191
|
-
this.close(authError);
|
|
6192
|
-
},
|
|
6193
|
-
dial: async (context) => {
|
|
6194
|
-
const response = await fetch(new URL(`${this.options.baseUrl}/active`).toString(), {
|
|
6195
|
-
method: "GET",
|
|
6196
|
-
headers: {
|
|
6197
|
-
Accept: "text/event-stream",
|
|
6198
|
-
Authorization: `Bearer ${context.token}`,
|
|
6199
|
-
"Cache-Control": "no-cache"
|
|
6200
|
-
},
|
|
6201
|
-
signal: context.signal
|
|
6202
|
-
});
|
|
6203
|
-
if (!response.ok) {
|
|
6204
|
-
if (response.status === 401 || response.status === 403) {
|
|
6205
|
-
throw new AuthChatStreamError(response.status);
|
|
6206
|
-
}
|
|
6207
|
-
throw new Error(`Active chat stream connection failed: ${response.status} ${response.statusText}`);
|
|
6208
|
-
}
|
|
6209
|
-
if (!response.body) {
|
|
6210
|
-
throw new Error("Active chat stream response has no body");
|
|
6211
|
-
}
|
|
6212
|
-
context.markConnected();
|
|
6213
|
-
await chunkY4OD5SDF_cjs.consumeSseStream(response.body, context.signal, {
|
|
6214
|
-
onChunk: () => context.markActivity(),
|
|
6215
|
-
onEventBlock: (block) => this.processEventBlock(block, context.requestTokenRefresh)
|
|
6216
|
-
});
|
|
6217
|
-
}
|
|
6218
|
-
});
|
|
6219
6251
|
}
|
|
6252
|
+
abortController;
|
|
6253
|
+
consecutiveAuthFailures = 0;
|
|
6220
6254
|
destroyed = false;
|
|
6255
|
+
needsForceRefresh = false;
|
|
6256
|
+
reconnectDelay = INITIAL_RECONNECT_DELAY_MS;
|
|
6257
|
+
reconnectTimer;
|
|
6258
|
+
shouldReconnect = false;
|
|
6221
6259
|
subscribers = /* @__PURE__ */ new Set();
|
|
6222
|
-
supervisor;
|
|
6223
6260
|
addSubscriber(subscriber) {
|
|
6224
6261
|
if (this.destroyed) {
|
|
6225
6262
|
throw new Error("Active chat stream is closed");
|
|
6226
6263
|
}
|
|
6227
6264
|
this.subscribers.add(subscriber);
|
|
6228
|
-
if (this.
|
|
6229
|
-
|
|
6265
|
+
if (!this.shouldReconnect) {
|
|
6266
|
+
this.shouldReconnect = true;
|
|
6267
|
+
void this.doConnect();
|
|
6230
6268
|
}
|
|
6231
6269
|
}
|
|
6232
6270
|
removeSubscriber(subscriber) {
|
|
@@ -6236,17 +6274,30 @@ var ActiveChatStreamConnection = class {
|
|
|
6236
6274
|
}
|
|
6237
6275
|
}
|
|
6238
6276
|
reconnect() {
|
|
6239
|
-
if (this.destroyed || this.subscribers.size === 0) {
|
|
6277
|
+
if (!this.shouldReconnect || this.destroyed || this.subscribers.size === 0) {
|
|
6240
6278
|
return;
|
|
6241
6279
|
}
|
|
6242
|
-
this.
|
|
6280
|
+
if (this.reconnectTimer) {
|
|
6281
|
+
clearTimeout(this.reconnectTimer);
|
|
6282
|
+
this.reconnectTimer = void 0;
|
|
6283
|
+
}
|
|
6284
|
+
if (this.abortController) {
|
|
6285
|
+
this.abortController.abort();
|
|
6286
|
+
this.abortController = void 0;
|
|
6287
|
+
}
|
|
6288
|
+
void this.doConnect();
|
|
6243
6289
|
}
|
|
6244
6290
|
close(error) {
|
|
6245
|
-
|
|
6246
|
-
return;
|
|
6247
|
-
}
|
|
6291
|
+
this.shouldReconnect = false;
|
|
6248
6292
|
this.destroyed = true;
|
|
6249
|
-
this.
|
|
6293
|
+
if (this.reconnectTimer) {
|
|
6294
|
+
clearTimeout(this.reconnectTimer);
|
|
6295
|
+
this.reconnectTimer = void 0;
|
|
6296
|
+
}
|
|
6297
|
+
if (this.abortController) {
|
|
6298
|
+
this.abortController.abort();
|
|
6299
|
+
this.abortController = void 0;
|
|
6300
|
+
}
|
|
6250
6301
|
for (const subscriber of Array.from(this.subscribers)) {
|
|
6251
6302
|
subscriber.finish(error);
|
|
6252
6303
|
}
|
|
@@ -6256,7 +6307,91 @@ var ActiveChatStreamConnection = class {
|
|
|
6256
6307
|
get isDestroyed() {
|
|
6257
6308
|
return this.destroyed;
|
|
6258
6309
|
}
|
|
6259
|
-
|
|
6310
|
+
async doConnect() {
|
|
6311
|
+
if (!this.shouldReconnect || this.destroyed || this.subscribers.size === 0) {
|
|
6312
|
+
return;
|
|
6313
|
+
}
|
|
6314
|
+
this.abortController = new AbortController();
|
|
6315
|
+
try {
|
|
6316
|
+
const forceRefresh = this.needsForceRefresh;
|
|
6317
|
+
this.needsForceRefresh = false;
|
|
6318
|
+
const token = await this.options.getToken(forceRefresh ? { forceRefresh: true } : void 0);
|
|
6319
|
+
const response = await fetch(new URL(`${this.options.baseUrl}/active`).toString(), {
|
|
6320
|
+
method: "GET",
|
|
6321
|
+
headers: {
|
|
6322
|
+
Accept: "text/event-stream",
|
|
6323
|
+
Authorization: `Bearer ${token}`,
|
|
6324
|
+
"Cache-Control": "no-cache"
|
|
6325
|
+
},
|
|
6326
|
+
signal: this.abortController.signal
|
|
6327
|
+
});
|
|
6328
|
+
if (!response.ok) {
|
|
6329
|
+
if (response.status === 401 || response.status === 403) {
|
|
6330
|
+
throw new AuthChatStreamError(response.status);
|
|
6331
|
+
}
|
|
6332
|
+
throw new Error(`Active chat stream connection failed: ${response.status} ${response.statusText}`);
|
|
6333
|
+
}
|
|
6334
|
+
if (!response.body) {
|
|
6335
|
+
throw new Error("Active chat stream response has no body");
|
|
6336
|
+
}
|
|
6337
|
+
this.consecutiveAuthFailures = 0;
|
|
6338
|
+
this.reconnectDelay = INITIAL_RECONNECT_DELAY_MS;
|
|
6339
|
+
await this.parseSseStream(response.body, this.abortController.signal);
|
|
6340
|
+
} catch (error) {
|
|
6341
|
+
if (error.name === "AbortError") {
|
|
6342
|
+
return;
|
|
6343
|
+
}
|
|
6344
|
+
if (!this.shouldReconnect || this.destroyed || this.subscribers.size === 0) {
|
|
6345
|
+
return;
|
|
6346
|
+
}
|
|
6347
|
+
const isAuthError2 = error instanceof AuthChatStreamError;
|
|
6348
|
+
if (isAuthError2) {
|
|
6349
|
+
this.consecutiveAuthFailures += 1;
|
|
6350
|
+
if (this.consecutiveAuthFailures >= MAX_CONSECUTIVE_AUTH_FAILURES) {
|
|
6351
|
+
const authError = new chunkKV5SP7RP_cjs.DvinaAuthenticationError(
|
|
6352
|
+
"Active chat SSE stream authentication failed permanently"
|
|
6353
|
+
);
|
|
6354
|
+
this.options.onError?.(authError);
|
|
6355
|
+
this.close(authError);
|
|
6356
|
+
return;
|
|
6357
|
+
}
|
|
6358
|
+
this.needsForceRefresh = true;
|
|
6359
|
+
}
|
|
6360
|
+
const delay = isAuthError2 ? INITIAL_RECONNECT_DELAY_MS : this.reconnectDelay;
|
|
6361
|
+
this.scheduleReconnect(delay);
|
|
6362
|
+
if (!isAuthError2) {
|
|
6363
|
+
this.reconnectDelay = Math.min(
|
|
6364
|
+
this.reconnectDelay * RECONNECT_BACKOFF_MULTIPLIER,
|
|
6365
|
+
MAX_RECONNECT_DELAY_MS
|
|
6366
|
+
);
|
|
6367
|
+
}
|
|
6368
|
+
}
|
|
6369
|
+
}
|
|
6370
|
+
async parseSseStream(body, signal) {
|
|
6371
|
+
const reader = body.getReader();
|
|
6372
|
+
const decoder = new TextDecoder();
|
|
6373
|
+
let buffer = "";
|
|
6374
|
+
try {
|
|
6375
|
+
while (!signal.aborted && this.shouldReconnect && !this.destroyed) {
|
|
6376
|
+
const { done, value } = await reader.read();
|
|
6377
|
+
if (done) {
|
|
6378
|
+
break;
|
|
6379
|
+
}
|
|
6380
|
+
buffer += decoder.decode(value, { stream: true });
|
|
6381
|
+
const parts = buffer.split(/(?:\r\n|\r|\n){2}/);
|
|
6382
|
+
buffer = parts.pop() ?? "";
|
|
6383
|
+
for (const part of parts) {
|
|
6384
|
+
this.processEventBlock(part.trim());
|
|
6385
|
+
}
|
|
6386
|
+
}
|
|
6387
|
+
} finally {
|
|
6388
|
+
reader.releaseLock();
|
|
6389
|
+
}
|
|
6390
|
+
if (this.shouldReconnect && !this.destroyed && this.subscribers.size > 0) {
|
|
6391
|
+
this.scheduleReconnect(this.reconnectDelay);
|
|
6392
|
+
}
|
|
6393
|
+
}
|
|
6394
|
+
processEventBlock(block) {
|
|
6260
6395
|
if (!block || block.startsWith(":")) {
|
|
6261
6396
|
return;
|
|
6262
6397
|
}
|
|
@@ -6270,8 +6405,8 @@ var ActiveChatStreamConnection = class {
|
|
|
6270
6405
|
}
|
|
6271
6406
|
}
|
|
6272
6407
|
if (eventType === "token-expired") {
|
|
6273
|
-
|
|
6274
|
-
|
|
6408
|
+
this.needsForceRefresh = true;
|
|
6409
|
+
return;
|
|
6275
6410
|
}
|
|
6276
6411
|
if (eventType !== "active" || dataLines.length === 0) {
|
|
6277
6412
|
return;
|
|
@@ -6290,6 +6425,18 @@ var ActiveChatStreamConnection = class {
|
|
|
6290
6425
|
subscriber.push(value);
|
|
6291
6426
|
}
|
|
6292
6427
|
}
|
|
6428
|
+
scheduleReconnect(delay) {
|
|
6429
|
+
if (!this.shouldReconnect || this.destroyed || this.subscribers.size === 0) {
|
|
6430
|
+
return;
|
|
6431
|
+
}
|
|
6432
|
+
if (this.reconnectTimer) {
|
|
6433
|
+
clearTimeout(this.reconnectTimer);
|
|
6434
|
+
}
|
|
6435
|
+
this.reconnectTimer = setTimeout(() => {
|
|
6436
|
+
this.reconnectTimer = void 0;
|
|
6437
|
+
void this.doConnect();
|
|
6438
|
+
}, delay);
|
|
6439
|
+
}
|
|
6293
6440
|
};
|
|
6294
6441
|
function createChatStreamClient(options) {
|
|
6295
6442
|
const connections = /* @__PURE__ */ new Map();
|
|
@@ -7227,7 +7374,7 @@ function createWsTransport(options) {
|
|
|
7227
7374
|
let nextToken;
|
|
7228
7375
|
let currentToken;
|
|
7229
7376
|
async function refreshToken() {
|
|
7230
|
-
const token = await
|
|
7377
|
+
const token = await chunkVDPZQ5F3_cjs.refreshTokenSingleFlight(options.getToken, currentToken);
|
|
7231
7378
|
if (!token) {
|
|
7232
7379
|
throw new chunkKV5SP7RP_cjs.DvinaAuthenticationError("Token refresh did not produce a new token", currentToken);
|
|
7233
7380
|
}
|
|
@@ -7279,7 +7426,7 @@ function createWsTransport(options) {
|
|
|
7279
7426
|
}
|
|
7280
7427
|
});
|
|
7281
7428
|
function subscribe(document2, variables) {
|
|
7282
|
-
const query =
|
|
7429
|
+
const query = chunkVDPZQ5F3_cjs.print(document2);
|
|
7283
7430
|
const subscribeOnce = () => ({
|
|
7284
7431
|
[Symbol.asyncIterator]() {
|
|
7285
7432
|
const queue = [];
|
|
@@ -7967,47 +8114,44 @@ var AuthSseError = class extends Error {
|
|
|
7967
8114
|
};
|
|
7968
8115
|
var INITIAL_RECONNECT_DELAY_MS2 = 1e3;
|
|
7969
8116
|
var MAX_RECONNECT_DELAY_MS2 = 3e4;
|
|
8117
|
+
var RECONNECT_BACKOFF_MULTIPLIER2 = 2;
|
|
7970
8118
|
var MAX_CONSECUTIVE_AUTH_FAILURES2 = 3;
|
|
7971
8119
|
var SUBSCRIPTION_REFRESH_INTERVAL_MS = 5 * 60 * 1e3;
|
|
7972
|
-
function mapSupervisorState(state) {
|
|
7973
|
-
if (state === "connected") {
|
|
7974
|
-
return "connected";
|
|
7975
|
-
}
|
|
7976
|
-
if (state === "connecting") {
|
|
7977
|
-
return "connecting";
|
|
7978
|
-
}
|
|
7979
|
-
return "disconnected";
|
|
7980
|
-
}
|
|
7981
8120
|
function createSseTransport(options) {
|
|
8121
|
+
let abortController;
|
|
7982
8122
|
let isConnected = false;
|
|
7983
|
-
let
|
|
8123
|
+
let reconnectDelay = INITIAL_RECONNECT_DELAY_MS2;
|
|
8124
|
+
let reconnectTimer;
|
|
7984
8125
|
let refreshTimer;
|
|
8126
|
+
let shouldReconnect = false;
|
|
8127
|
+
let currentLastSyncId;
|
|
8128
|
+
let needsForceRefresh = false;
|
|
8129
|
+
let consecutiveAuthFailures = 0;
|
|
7985
8130
|
let hasConnectedOnce = false;
|
|
7986
|
-
let lastLegacyState;
|
|
7987
8131
|
const activeSubscriptions = /* @__PURE__ */ new Map();
|
|
7988
|
-
|
|
7989
|
-
|
|
7990
|
-
|
|
8132
|
+
async function connect(lastSyncId) {
|
|
8133
|
+
disconnect();
|
|
8134
|
+
shouldReconnect = true;
|
|
8135
|
+
currentLastSyncId = lastSyncId;
|
|
8136
|
+
await doConnect();
|
|
8137
|
+
}
|
|
8138
|
+
function reconnect() {
|
|
8139
|
+
const lastSyncId = currentLastSyncId;
|
|
8140
|
+
disconnect();
|
|
8141
|
+
shouldReconnect = true;
|
|
8142
|
+
currentLastSyncId = lastSyncId;
|
|
8143
|
+
void doConnect();
|
|
8144
|
+
}
|
|
8145
|
+
async function doConnect() {
|
|
8146
|
+
if (!shouldReconnect) {
|
|
7991
8147
|
return;
|
|
7992
8148
|
}
|
|
7993
|
-
|
|
7994
|
-
|
|
7995
|
-
|
|
7996
|
-
|
|
7997
|
-
|
|
7998
|
-
|
|
7999
|
-
};
|
|
8000
|
-
const supervisor = new chunkY4OD5SDF_cjs.ConnectionSupervisor({
|
|
8001
|
-
authRetryDelayMs: INITIAL_RECONNECT_DELAY_MS2,
|
|
8002
|
-
baseReconnectDelayMs: INITIAL_RECONNECT_DELAY_MS2,
|
|
8003
|
-
getToken: options.getToken,
|
|
8004
|
-
id: "primary",
|
|
8005
|
-
isAuthError: (error) => error instanceof AuthSseError,
|
|
8006
|
-
kind: "sync-sse",
|
|
8007
|
-
maxConsecutiveAuthFailures: MAX_CONSECUTIVE_AUTH_FAILURES2,
|
|
8008
|
-
maxReconnectDelayMs: MAX_RECONNECT_DELAY_MS2,
|
|
8009
|
-
onStateChange: (snapshot) => emitLegacyState(snapshot.state),
|
|
8010
|
-
dial: async (context) => {
|
|
8149
|
+
abortController = new AbortController();
|
|
8150
|
+
options.onStateChange?.("connecting");
|
|
8151
|
+
try {
|
|
8152
|
+
const forceRefresh = needsForceRefresh;
|
|
8153
|
+
needsForceRefresh = false;
|
|
8154
|
+
const token = await options.getToken(forceRefresh ? { forceRefresh: true } : void 0);
|
|
8011
8155
|
const url = new URL(options.url);
|
|
8012
8156
|
if (currentLastSyncId && currentLastSyncId !== "0") {
|
|
8013
8157
|
url.searchParams.set("lastSyncId", currentLastSyncId);
|
|
@@ -8015,11 +8159,11 @@ function createSseTransport(options) {
|
|
|
8015
8159
|
const response = await fetch(url.toString(), {
|
|
8016
8160
|
method: "GET",
|
|
8017
8161
|
headers: {
|
|
8018
|
-
Authorization: `Bearer ${
|
|
8162
|
+
Authorization: `Bearer ${token}`,
|
|
8019
8163
|
Accept: "text/event-stream",
|
|
8020
8164
|
"Cache-Control": "no-cache"
|
|
8021
8165
|
},
|
|
8022
|
-
signal:
|
|
8166
|
+
signal: abortController.signal
|
|
8023
8167
|
});
|
|
8024
8168
|
if (!response.ok) {
|
|
8025
8169
|
if (response.status === 401 || response.status === 403) {
|
|
@@ -8030,36 +8174,143 @@ function createSseTransport(options) {
|
|
|
8030
8174
|
if (!response.body) {
|
|
8031
8175
|
throw new Error("SSE response has no body");
|
|
8032
8176
|
}
|
|
8177
|
+
isConnected = true;
|
|
8178
|
+
consecutiveAuthFailures = 0;
|
|
8179
|
+
reconnectDelay = INITIAL_RECONNECT_DELAY_MS2;
|
|
8180
|
+
options.onStateChange?.("connected");
|
|
8033
8181
|
const isReconnect = hasConnectedOnce;
|
|
8034
8182
|
hasConnectedOnce = true;
|
|
8035
|
-
|
|
8036
|
-
await syncActiveSubscriptions(context.token);
|
|
8183
|
+
await syncActiveSubscriptions(token);
|
|
8037
8184
|
startSubscriptionRefresh();
|
|
8038
8185
|
if (isReconnect && activeSubscriptions.size > 0) {
|
|
8039
8186
|
options.onReconnect?.();
|
|
8040
8187
|
}
|
|
8041
|
-
await
|
|
8042
|
-
|
|
8043
|
-
|
|
8044
|
-
|
|
8188
|
+
await parseSseStream(response.body, abortController.signal);
|
|
8189
|
+
} catch (error) {
|
|
8190
|
+
if (error.name === "AbortError") {
|
|
8191
|
+
return;
|
|
8192
|
+
}
|
|
8193
|
+
isConnected = false;
|
|
8194
|
+
stopSubscriptionRefresh();
|
|
8195
|
+
options.onStateChange?.("disconnected");
|
|
8196
|
+
if (!shouldReconnect) {
|
|
8197
|
+
return;
|
|
8198
|
+
}
|
|
8199
|
+
const isAuthError2 = error instanceof AuthSseError;
|
|
8200
|
+
if (isAuthError2) {
|
|
8201
|
+
consecutiveAuthFailures += 1;
|
|
8202
|
+
if (consecutiveAuthFailures >= MAX_CONSECUTIVE_AUTH_FAILURES2) {
|
|
8203
|
+
disconnect();
|
|
8204
|
+
return;
|
|
8205
|
+
}
|
|
8206
|
+
needsForceRefresh = true;
|
|
8207
|
+
}
|
|
8208
|
+
const delay = isAuthError2 ? INITIAL_RECONNECT_DELAY_MS2 : reconnectDelay;
|
|
8209
|
+
reconnectTimer = setTimeout(() => {
|
|
8210
|
+
void doConnect();
|
|
8211
|
+
}, delay);
|
|
8212
|
+
if (!isAuthError2) {
|
|
8213
|
+
reconnectDelay = Math.min(reconnectDelay * RECONNECT_BACKOFF_MULTIPLIER2, MAX_RECONNECT_DELAY_MS2);
|
|
8214
|
+
}
|
|
8045
8215
|
}
|
|
8046
|
-
});
|
|
8047
|
-
async function connect(lastSyncId) {
|
|
8048
|
-
currentLastSyncId = lastSyncId;
|
|
8049
|
-
disconnect();
|
|
8050
|
-
await supervisor.start();
|
|
8051
8216
|
}
|
|
8052
|
-
function
|
|
8053
|
-
|
|
8217
|
+
async function parseSseStream(body, signal) {
|
|
8218
|
+
const reader = body.getReader();
|
|
8219
|
+
const decoder = new TextDecoder();
|
|
8220
|
+
let buffer = "";
|
|
8221
|
+
try {
|
|
8222
|
+
while (!signal.aborted) {
|
|
8223
|
+
const { done, value } = await reader.read();
|
|
8224
|
+
if (done) {
|
|
8225
|
+
break;
|
|
8226
|
+
}
|
|
8227
|
+
buffer += decoder.decode(value, { stream: true });
|
|
8228
|
+
const parts = buffer.split(/(?:\r\n|\r|\n){2}/);
|
|
8229
|
+
buffer = parts.pop() ?? "";
|
|
8230
|
+
for (const part of parts) {
|
|
8231
|
+
processEventBlock(part.trim());
|
|
8232
|
+
}
|
|
8233
|
+
}
|
|
8234
|
+
} finally {
|
|
8235
|
+
reader.releaseLock();
|
|
8236
|
+
}
|
|
8237
|
+
if (!shouldReconnect) {
|
|
8238
|
+
return;
|
|
8239
|
+
}
|
|
8054
8240
|
isConnected = false;
|
|
8055
8241
|
stopSubscriptionRefresh();
|
|
8056
|
-
|
|
8057
|
-
|
|
8058
|
-
|
|
8242
|
+
options.onStateChange?.("disconnected");
|
|
8243
|
+
reconnectTimer = setTimeout(() => {
|
|
8244
|
+
void doConnect();
|
|
8245
|
+
}, reconnectDelay);
|
|
8246
|
+
}
|
|
8247
|
+
function processEventBlock(block) {
|
|
8248
|
+
if (!block || block.startsWith(":")) {
|
|
8249
|
+
return;
|
|
8250
|
+
}
|
|
8251
|
+
let eventId;
|
|
8252
|
+
let eventType;
|
|
8253
|
+
let eventData;
|
|
8254
|
+
for (const line of block.split(/\r\n|\r|\n/)) {
|
|
8255
|
+
if (line.startsWith("id: ")) {
|
|
8256
|
+
eventId = line.slice(4).trim();
|
|
8257
|
+
} else if (line.startsWith("event: ")) {
|
|
8258
|
+
eventType = line.slice(7).trim();
|
|
8259
|
+
} else if (line.startsWith("data: ")) {
|
|
8260
|
+
eventData = line.slice(6);
|
|
8261
|
+
}
|
|
8262
|
+
}
|
|
8263
|
+
if (eventType === "token-expired") {
|
|
8264
|
+
needsForceRefresh = true;
|
|
8265
|
+
return;
|
|
8266
|
+
}
|
|
8267
|
+
if (eventType === "full-resync") {
|
|
8268
|
+
options.onFullResync?.();
|
|
8269
|
+
return;
|
|
8270
|
+
}
|
|
8271
|
+
if ((eventType === "query-add" || eventType === "query-remove") && eventData) {
|
|
8272
|
+
try {
|
|
8273
|
+
const parsed = JSON.parse(eventData);
|
|
8274
|
+
options.onQueryEvent?.({
|
|
8275
|
+
type: eventType === "query-add" ? "add" : "remove",
|
|
8276
|
+
...parsed
|
|
8277
|
+
});
|
|
8278
|
+
} catch {
|
|
8279
|
+
}
|
|
8280
|
+
return;
|
|
8281
|
+
}
|
|
8282
|
+
if (!eventId) {
|
|
8283
|
+
return;
|
|
8284
|
+
}
|
|
8285
|
+
currentLastSyncId = eventId;
|
|
8286
|
+
if (eventType === "cursor") {
|
|
8287
|
+
options.onCursor?.(eventId);
|
|
8288
|
+
return;
|
|
8289
|
+
}
|
|
8290
|
+
if (eventType === "sync" && eventData) {
|
|
8291
|
+
try {
|
|
8292
|
+
const parsed = JSON.parse(eventData);
|
|
8293
|
+
options.onEvent({
|
|
8294
|
+
id: eventId,
|
|
8295
|
+
...parsed
|
|
8296
|
+
});
|
|
8297
|
+
} catch {
|
|
8298
|
+
}
|
|
8059
8299
|
}
|
|
8060
8300
|
}
|
|
8061
|
-
function
|
|
8062
|
-
|
|
8301
|
+
function disconnect() {
|
|
8302
|
+
shouldReconnect = false;
|
|
8303
|
+
isConnected = false;
|
|
8304
|
+
stopSubscriptionRefresh();
|
|
8305
|
+
if (reconnectTimer) {
|
|
8306
|
+
clearTimeout(reconnectTimer);
|
|
8307
|
+
reconnectTimer = void 0;
|
|
8308
|
+
}
|
|
8309
|
+
if (abortController) {
|
|
8310
|
+
abortController.abort();
|
|
8311
|
+
abortController = void 0;
|
|
8312
|
+
}
|
|
8313
|
+
options.onStateChange?.("disconnected");
|
|
8063
8314
|
}
|
|
8064
8315
|
function subscribe(descriptor) {
|
|
8065
8316
|
activeSubscriptions.set(descriptor.id, descriptor);
|
|
@@ -8120,61 +8371,7 @@ function createSseTransport(options) {
|
|
|
8120
8371
|
if (response.status !== 401 && response.status !== 403) {
|
|
8121
8372
|
return;
|
|
8122
8373
|
}
|
|
8123
|
-
resolvedToken = await
|
|
8124
|
-
}
|
|
8125
|
-
}
|
|
8126
|
-
function processEventBlock(block, requestTokenRefresh) {
|
|
8127
|
-
if (!block || block.startsWith(":")) {
|
|
8128
|
-
return;
|
|
8129
|
-
}
|
|
8130
|
-
let eventId;
|
|
8131
|
-
let eventType;
|
|
8132
|
-
let eventData;
|
|
8133
|
-
for (const line of block.split(/\r\n|\r|\n/)) {
|
|
8134
|
-
if (line.startsWith("id: ")) {
|
|
8135
|
-
eventId = line.slice(4).trim();
|
|
8136
|
-
} else if (line.startsWith("event: ")) {
|
|
8137
|
-
eventType = line.slice(7).trim();
|
|
8138
|
-
} else if (line.startsWith("data: ")) {
|
|
8139
|
-
eventData = line.slice(6);
|
|
8140
|
-
}
|
|
8141
|
-
}
|
|
8142
|
-
if (eventType === "token-expired") {
|
|
8143
|
-
requestTokenRefresh();
|
|
8144
|
-
throw new AuthSseError(401);
|
|
8145
|
-
}
|
|
8146
|
-
if (eventType === "full-resync") {
|
|
8147
|
-
options.onFullResync?.();
|
|
8148
|
-
return;
|
|
8149
|
-
}
|
|
8150
|
-
if ((eventType === "query-add" || eventType === "query-remove") && eventData) {
|
|
8151
|
-
try {
|
|
8152
|
-
const parsed = JSON.parse(eventData);
|
|
8153
|
-
options.onQueryEvent?.({
|
|
8154
|
-
type: eventType === "query-add" ? "add" : "remove",
|
|
8155
|
-
...parsed
|
|
8156
|
-
});
|
|
8157
|
-
} catch {
|
|
8158
|
-
}
|
|
8159
|
-
return;
|
|
8160
|
-
}
|
|
8161
|
-
if (!eventId) {
|
|
8162
|
-
return;
|
|
8163
|
-
}
|
|
8164
|
-
currentLastSyncId = eventId;
|
|
8165
|
-
if (eventType === "cursor") {
|
|
8166
|
-
options.onCursor?.(eventId);
|
|
8167
|
-
return;
|
|
8168
|
-
}
|
|
8169
|
-
if (eventType === "sync" && eventData) {
|
|
8170
|
-
try {
|
|
8171
|
-
const parsed = JSON.parse(eventData);
|
|
8172
|
-
options.onEvent({
|
|
8173
|
-
id: eventId,
|
|
8174
|
-
...parsed
|
|
8175
|
-
});
|
|
8176
|
-
} catch {
|
|
8177
|
-
}
|
|
8374
|
+
resolvedToken = await chunkVDPZQ5F3_cjs.refreshTokenSingleFlight(options.getToken, resolvedToken);
|
|
8178
8375
|
}
|
|
8179
8376
|
}
|
|
8180
8377
|
return {
|
|
@@ -8812,9 +9009,12 @@ var CacheManager = class {
|
|
|
8812
9009
|
*/
|
|
8813
9010
|
async invalidateQuery(operationName, variables) {
|
|
8814
9011
|
const key = buildQueryKey(operationName, variables);
|
|
9012
|
+
await this.invalidateQueryKey(key);
|
|
9013
|
+
}
|
|
9014
|
+
async invalidateQueryKey(queryKey) {
|
|
8815
9015
|
await this._db.transaction("rw", [this._db._queryResults, this._db._sync], async () => {
|
|
8816
|
-
await this._db._queryResults.delete(
|
|
8817
|
-
await this._db._sync.delete(getQueryFreshnessKey(
|
|
9016
|
+
await this._db._queryResults.delete(queryKey);
|
|
9017
|
+
await this._db._sync.delete(getQueryFreshnessKey(queryKey));
|
|
8818
9018
|
});
|
|
8819
9019
|
}
|
|
8820
9020
|
/**
|
|
@@ -9509,6 +9709,7 @@ async function resolveRelationByReference(db, params) {
|
|
|
9509
9709
|
}
|
|
9510
9710
|
|
|
9511
9711
|
// src/store/sync-engine.ts
|
|
9712
|
+
var REVALIDATION_RETRY_DELAY_MS = 1e3;
|
|
9512
9713
|
var SyncEngine = class {
|
|
9513
9714
|
_db;
|
|
9514
9715
|
_sse;
|
|
@@ -9525,6 +9726,8 @@ var SyncEngine = class {
|
|
|
9525
9726
|
_subscriptionToQuery = /* @__PURE__ */ new Map();
|
|
9526
9727
|
/** Last per-query revalidation timestamp to avoid refetch storms. */
|
|
9527
9728
|
_lastRevalidatedAt = /* @__PURE__ */ new Map();
|
|
9729
|
+
/** Retry timers for recovery refetches that failed and need another attempt. */
|
|
9730
|
+
_revalidationRetryTimers = /* @__PURE__ */ new Map();
|
|
9528
9731
|
/**
|
|
9529
9732
|
* Last mutation/sync touch timestamp by entity type.
|
|
9530
9733
|
* Used to detect stale cached query results on watch re-entry.
|
|
@@ -9562,27 +9765,24 @@ var SyncEngine = class {
|
|
|
9562
9765
|
/**
|
|
9563
9766
|
* Handle a full-resync signal from the server.
|
|
9564
9767
|
*
|
|
9565
|
-
* Clears all cached entities and query results,
|
|
9566
|
-
*
|
|
9567
|
-
*
|
|
9568
|
-
* after the reconnect callback re-registers them with the server.
|
|
9569
|
-
* Without SSE, revalidation happens immediately.
|
|
9768
|
+
* Clears all cached entities and query results, restarts delta sync, and
|
|
9769
|
+
* refetches active subscription-backed queries once so filtered connections
|
|
9770
|
+
* are rebuilt from source of truth instead of waiting for future delta events.
|
|
9570
9771
|
*/
|
|
9571
9772
|
async handleFullResync() {
|
|
9572
9773
|
this.stopSync();
|
|
9573
9774
|
await this.clearAll();
|
|
9574
9775
|
if (this._sse) {
|
|
9575
9776
|
void this.startSync();
|
|
9576
|
-
return;
|
|
9577
9777
|
}
|
|
9578
9778
|
await this._revalidateAllActiveSubscriptions();
|
|
9579
9779
|
}
|
|
9580
9780
|
/**
|
|
9581
|
-
*
|
|
9582
|
-
*
|
|
9781
|
+
* Ordinary transport reconnects should recover from the sync cursor and
|
|
9782
|
+
* server-side subscription state without eagerly refetching every active query.
|
|
9583
9783
|
*/
|
|
9584
9784
|
async handleTransportReconnect() {
|
|
9585
|
-
|
|
9785
|
+
return;
|
|
9586
9786
|
}
|
|
9587
9787
|
/**
|
|
9588
9788
|
* Process an incoming SSE sync event.
|
|
@@ -9645,8 +9845,15 @@ var SyncEngine = class {
|
|
|
9645
9845
|
void this._revalidateSubscriptionIfStale(subscriptionDescriptor.id);
|
|
9646
9846
|
const originalDispose = ref.dispose.bind(ref);
|
|
9647
9847
|
ref.dispose = () => {
|
|
9848
|
+
const hasOtherActiveSubscription = this._hasOtherActiveSubscriptionForQueryKey(
|
|
9849
|
+
queryKey,
|
|
9850
|
+
subscriptionDescriptor.id
|
|
9851
|
+
);
|
|
9648
9852
|
this._subscriptionToQueryKey.delete(subscriptionDescriptor.id);
|
|
9649
9853
|
this._subscriptionToQuery.delete(subscriptionDescriptor.id);
|
|
9854
|
+
if (!hasOtherActiveSubscription) {
|
|
9855
|
+
this._clearRevalidationRetry(queryKey);
|
|
9856
|
+
}
|
|
9650
9857
|
if (this._sse) {
|
|
9651
9858
|
this._sse.unsubscribe(subscriptionDescriptor.id);
|
|
9652
9859
|
}
|
|
@@ -9818,7 +10025,7 @@ var SyncEngine = class {
|
|
|
9818
10025
|
if (!cached) return;
|
|
9819
10026
|
const fetchedAt = await this._cache.getQueryFetchedAt(sub.queryKey, cached);
|
|
9820
10027
|
if ((fetchedAt ?? cached.fetchedAt) >= touchedAt) return;
|
|
9821
|
-
await this.
|
|
10028
|
+
await this._revalidateSubscriptionQuery(sub, { force: true });
|
|
9822
10029
|
}
|
|
9823
10030
|
async _revalidateAllActiveSubscriptions() {
|
|
9824
10031
|
await this._revalidateSubscriptions(Array.from(this._subscriptionToQuery.values()), { force: true });
|
|
@@ -9832,15 +10039,60 @@ var SyncEngine = class {
|
|
|
9832
10039
|
pendingByQueryKey.set(sub.queryKey, sub);
|
|
9833
10040
|
}
|
|
9834
10041
|
if (pendingByQueryKey.size === 0) return;
|
|
9835
|
-
for (const sub of pendingByQueryKey.values()) {
|
|
9836
|
-
this._lastRevalidatedAt.set(sub.queryKey, now);
|
|
9837
|
-
}
|
|
9838
10042
|
await Promise.all(
|
|
9839
|
-
Array.from(pendingByQueryKey.values()).map(
|
|
9840
|
-
(sub) => this.query(sub.document, sub.variables, sub.operationName).catch(() => void 0)
|
|
9841
|
-
)
|
|
10043
|
+
Array.from(pendingByQueryKey.values()).map((sub) => this._revalidateSubscriptionQuery(sub, options))
|
|
9842
10044
|
);
|
|
9843
10045
|
}
|
|
10046
|
+
async _revalidateSubscriptionQuery(subscription, options) {
|
|
10047
|
+
const startedAt = Date.now();
|
|
10048
|
+
this._lastRevalidatedAt.set(subscription.queryKey, startedAt);
|
|
10049
|
+
try {
|
|
10050
|
+
await this.query(subscription.document, subscription.variables, subscription.operationName);
|
|
10051
|
+
this._clearRevalidationRetry(subscription.queryKey);
|
|
10052
|
+
} catch {
|
|
10053
|
+
this._lastRevalidatedAt.delete(subscription.queryKey);
|
|
10054
|
+
await this._cache.invalidateQueryKey(subscription.queryKey).catch(() => void 0);
|
|
10055
|
+
if (options?.force || this._hasActiveSubscriptionForQueryKey(subscription.queryKey)) {
|
|
10056
|
+
this._scheduleRevalidationRetry(subscription.queryKey);
|
|
10057
|
+
}
|
|
10058
|
+
}
|
|
10059
|
+
}
|
|
10060
|
+
_scheduleRevalidationRetry(queryKey) {
|
|
10061
|
+
if (this._revalidationRetryTimers.has(queryKey)) {
|
|
10062
|
+
return;
|
|
10063
|
+
}
|
|
10064
|
+
const timer = setTimeout(() => {
|
|
10065
|
+
this._revalidationRetryTimers.delete(queryKey);
|
|
10066
|
+
const subscription = this._getActiveSubscriptionByQueryKey(queryKey);
|
|
10067
|
+
if (!subscription) {
|
|
10068
|
+
return;
|
|
10069
|
+
}
|
|
10070
|
+
void this._revalidateSubscriptionQuery(subscription, { force: true });
|
|
10071
|
+
}, REVALIDATION_RETRY_DELAY_MS);
|
|
10072
|
+
this._revalidationRetryTimers.set(queryKey, timer);
|
|
10073
|
+
}
|
|
10074
|
+
_clearRevalidationRetry(queryKey) {
|
|
10075
|
+
const timer = this._revalidationRetryTimers.get(queryKey);
|
|
10076
|
+
if (!timer) {
|
|
10077
|
+
return;
|
|
10078
|
+
}
|
|
10079
|
+
clearTimeout(timer);
|
|
10080
|
+
this._revalidationRetryTimers.delete(queryKey);
|
|
10081
|
+
}
|
|
10082
|
+
_getActiveSubscriptionByQueryKey(queryKey) {
|
|
10083
|
+
return Array.from(this._subscriptionToQuery.values()).find((sub) => sub.queryKey === queryKey);
|
|
10084
|
+
}
|
|
10085
|
+
_hasActiveSubscriptionForQueryKey(queryKey) {
|
|
10086
|
+
return this._getActiveSubscriptionByQueryKey(queryKey) !== void 0;
|
|
10087
|
+
}
|
|
10088
|
+
_hasOtherActiveSubscriptionForQueryKey(queryKey, subscriptionId) {
|
|
10089
|
+
for (const [activeSubscriptionId, subscription] of this._subscriptionToQuery.entries()) {
|
|
10090
|
+
if (activeSubscriptionId !== subscriptionId && subscription.queryKey === queryKey) {
|
|
10091
|
+
return true;
|
|
10092
|
+
}
|
|
10093
|
+
}
|
|
10094
|
+
return false;
|
|
10095
|
+
}
|
|
9844
10096
|
_getActiveSubscriptionsForEntityType(entityType) {
|
|
9845
10097
|
return Array.from(this._subscriptionToQuery.values()).filter((sub) => sub.entityType === entityType);
|
|
9846
10098
|
}
|
|
@@ -10118,10 +10370,6 @@ function createLazySyncEngine(httpTransport, sseUrl, syncPolicyUrl, getToken, ge
|
|
|
10118
10370
|
onFullResync: () => {
|
|
10119
10371
|
realEngine?.handleFullResync().catch(() => {
|
|
10120
10372
|
});
|
|
10121
|
-
},
|
|
10122
|
-
onReconnect: () => {
|
|
10123
|
-
realEngine?.handleTransportReconnect().catch(() => {
|
|
10124
|
-
});
|
|
10125
10373
|
}
|
|
10126
10374
|
});
|
|
10127
10375
|
sseTransport = transport;
|
|
@@ -10378,6 +10626,9 @@ var DEFAULT_BASE_URL = "api.dvina.ai";
|
|
|
10378
10626
|
var DB_INIT_TOKEN_POLL_INTERVAL_MS = 100;
|
|
10379
10627
|
var DB_INIT_TOKEN_TIMEOUT_MS = 15e3;
|
|
10380
10628
|
var LIFECYCLE_HINT_DEBOUNCE_MS = 250;
|
|
10629
|
+
function shouldRecoverConnections(hints) {
|
|
10630
|
+
return hints.has("network-restored") || hints.has("app-resumed");
|
|
10631
|
+
}
|
|
10381
10632
|
function resolveGetToken(options) {
|
|
10382
10633
|
if ("getToken" in options && options.getToken) {
|
|
10383
10634
|
return options.getToken;
|
|
@@ -10427,7 +10678,7 @@ function createDvinaClient(options) {
|
|
|
10427
10678
|
const getToken = resolveGetToken(options);
|
|
10428
10679
|
const getLanguage = resolveLanguage(options.language);
|
|
10429
10680
|
const getUserTimezone = resolveUserTimezone();
|
|
10430
|
-
const httpTransport =
|
|
10681
|
+
const httpTransport = chunkVDPZQ5F3_cjs.createHttpTransport({
|
|
10431
10682
|
url: httpUrl,
|
|
10432
10683
|
getToken,
|
|
10433
10684
|
getLanguage,
|
|
@@ -10486,19 +10737,29 @@ function createDvinaClient(options) {
|
|
|
10486
10737
|
const billingBase = hasProtocol ? billingOverride.replace(/\/+$/, "") : `${httpProtocol}://${billingOverride ?? baseUrl.replace(/^api\./, "billing.")}`;
|
|
10487
10738
|
const billingHttpUrl = `${billingBase}/graphql`;
|
|
10488
10739
|
const billingSseUrl = `${billingBase}/subscriptions/stream`;
|
|
10489
|
-
const billing = new
|
|
10740
|
+
const billing = new chunkVDPZQ5F3_cjs.BillingClient({ billingHttpUrl, billingSseUrl, getToken, onError: options.onError });
|
|
10490
10741
|
let lifecycleHintTimer;
|
|
10742
|
+
const pendingLifecycleHints = /* @__PURE__ */ new Set();
|
|
10743
|
+
const recoverConnections = () => {
|
|
10744
|
+
recoverableSyncEngine.reconnectActiveSync();
|
|
10745
|
+
chatStream.reconnectAll();
|
|
10746
|
+
wsTransport?.terminate();
|
|
10747
|
+
billing.reconnectAll();
|
|
10748
|
+
};
|
|
10491
10749
|
const lifecycle = {
|
|
10492
|
-
hint(
|
|
10750
|
+
hint(reason) {
|
|
10751
|
+
pendingLifecycleHints.add(reason);
|
|
10493
10752
|
if (lifecycleHintTimer) {
|
|
10494
10753
|
return;
|
|
10495
10754
|
}
|
|
10496
10755
|
lifecycleHintTimer = setTimeout(() => {
|
|
10497
10756
|
lifecycleHintTimer = void 0;
|
|
10498
|
-
|
|
10499
|
-
|
|
10500
|
-
|
|
10501
|
-
|
|
10757
|
+
const hints = new Set(pendingLifecycleHints);
|
|
10758
|
+
pendingLifecycleHints.clear();
|
|
10759
|
+
if (!shouldRecoverConnections(hints)) {
|
|
10760
|
+
return;
|
|
10761
|
+
}
|
|
10762
|
+
recoverConnections();
|
|
10502
10763
|
}, LIFECYCLE_HINT_DEBOUNCE_MS);
|
|
10503
10764
|
}
|
|
10504
10765
|
};
|
|
@@ -10819,7 +11080,7 @@ function buildSmartQuery(baseDocument, rootFieldName, includes, baseVariables, i
|
|
|
10819
11080
|
}
|
|
10820
11081
|
const doc = cloneDocument(baseDocument);
|
|
10821
11082
|
const mergedVariables = { ...baseVariables };
|
|
10822
|
-
const opDef = doc.definitions.find((d) => d.kind ===
|
|
11083
|
+
const opDef = doc.definitions.find((d) => d.kind === chunkVDPZQ5F3_cjs.Kind.OPERATION_DEFINITION);
|
|
10823
11084
|
if (!opDef) {
|
|
10824
11085
|
return { document: baseDocument, variables: baseVariables };
|
|
10825
11086
|
}
|
|
@@ -10829,7 +11090,7 @@ function buildSmartQuery(baseDocument, rootFieldName, includes, baseVariables, i
|
|
|
10829
11090
|
}
|
|
10830
11091
|
const existingFragments = /* @__PURE__ */ new Set();
|
|
10831
11092
|
for (const def of doc.definitions) {
|
|
10832
|
-
if (def.kind ===
|
|
11093
|
+
if (def.kind === chunkVDPZQ5F3_cjs.Kind.FRAGMENT_DEFINITION) {
|
|
10833
11094
|
existingFragments.add(def.name.value);
|
|
10834
11095
|
}
|
|
10835
11096
|
}
|
|
@@ -10853,10 +11114,10 @@ function buildSmartQuery(baseDocument, rootFieldName, includes, baseVariables, i
|
|
|
10853
11114
|
}
|
|
10854
11115
|
if (isConnection && connectionIncludeFields.length > 0) {
|
|
10855
11116
|
const nodesWrapper = {
|
|
10856
|
-
kind:
|
|
10857
|
-
name: { kind:
|
|
11117
|
+
kind: chunkVDPZQ5F3_cjs.Kind.FIELD,
|
|
11118
|
+
name: { kind: chunkVDPZQ5F3_cjs.Kind.NAME, value: "nodes" },
|
|
10858
11119
|
selectionSet: {
|
|
10859
|
-
kind:
|
|
11120
|
+
kind: chunkVDPZQ5F3_cjs.Kind.SELECTION_SET,
|
|
10860
11121
|
selections: connectionIncludeFields
|
|
10861
11122
|
}
|
|
10862
11123
|
};
|
|
@@ -10870,14 +11131,14 @@ function buildSmartQuery(baseDocument, rootFieldName, includes, baseVariables, i
|
|
|
10870
11131
|
function processIncludeDirective(include, prefix, opDef, mergedVariables, existingFragments, newDefinitions) {
|
|
10871
11132
|
const fieldArgs = buildPrefixedArguments(include.fieldArguments ?? [], prefix);
|
|
10872
11133
|
const fragmentDefs = include.fragmentDoc.definitions.filter(
|
|
10873
|
-
(d) => d.kind ===
|
|
11134
|
+
(d) => d.kind === chunkVDPZQ5F3_cjs.Kind.FRAGMENT_DEFINITION
|
|
10874
11135
|
);
|
|
10875
11136
|
const mainFragment = fragmentDefs[0];
|
|
10876
11137
|
if (!mainFragment) return void 0;
|
|
10877
11138
|
const selections = [
|
|
10878
11139
|
{
|
|
10879
|
-
kind:
|
|
10880
|
-
name: { kind:
|
|
11140
|
+
kind: chunkVDPZQ5F3_cjs.Kind.FRAGMENT_SPREAD,
|
|
11141
|
+
name: { kind: chunkVDPZQ5F3_cjs.Kind.NAME, value: mainFragment.name.value }
|
|
10881
11142
|
}
|
|
10882
11143
|
];
|
|
10883
11144
|
if (include.children && include.children.length > 0) {
|
|
@@ -10899,10 +11160,10 @@ function processIncludeDirective(include, prefix, opDef, mergedVariables, existi
|
|
|
10899
11160
|
if (childFields.length > 0) {
|
|
10900
11161
|
if (include.isConnection) {
|
|
10901
11162
|
const nodesWrapper = {
|
|
10902
|
-
kind:
|
|
10903
|
-
name: { kind:
|
|
11163
|
+
kind: chunkVDPZQ5F3_cjs.Kind.FIELD,
|
|
11164
|
+
name: { kind: chunkVDPZQ5F3_cjs.Kind.NAME, value: "nodes" },
|
|
10904
11165
|
selectionSet: {
|
|
10905
|
-
kind:
|
|
11166
|
+
kind: chunkVDPZQ5F3_cjs.Kind.SELECTION_SET,
|
|
10906
11167
|
selections: childFields
|
|
10907
11168
|
}
|
|
10908
11169
|
};
|
|
@@ -10913,11 +11174,11 @@ function processIncludeDirective(include, prefix, opDef, mergedVariables, existi
|
|
|
10913
11174
|
}
|
|
10914
11175
|
}
|
|
10915
11176
|
const includeField = {
|
|
10916
|
-
kind:
|
|
10917
|
-
name: { kind:
|
|
11177
|
+
kind: chunkVDPZQ5F3_cjs.Kind.FIELD,
|
|
11178
|
+
name: { kind: chunkVDPZQ5F3_cjs.Kind.NAME, value: include.fieldName },
|
|
10918
11179
|
arguments: fieldArgs.length > 0 ? fieldArgs : void 0,
|
|
10919
11180
|
selectionSet: {
|
|
10920
|
-
kind:
|
|
11181
|
+
kind: chunkVDPZQ5F3_cjs.Kind.SELECTION_SET,
|
|
10921
11182
|
selections
|
|
10922
11183
|
}
|
|
10923
11184
|
};
|
|
@@ -10944,7 +11205,7 @@ function processIncludeDirective(include, prefix, opDef, mergedVariables, existi
|
|
|
10944
11205
|
}
|
|
10945
11206
|
function findFieldInSelectionSet(selectionSet, fieldName) {
|
|
10946
11207
|
for (const selection of selectionSet.selections) {
|
|
10947
|
-
if (selection.kind ===
|
|
11208
|
+
if (selection.kind === chunkVDPZQ5F3_cjs.Kind.FIELD && selection.name.value === fieldName) {
|
|
10948
11209
|
return selection;
|
|
10949
11210
|
}
|
|
10950
11211
|
}
|
|
@@ -10958,7 +11219,7 @@ function buildPrefixedArguments(args, prefix) {
|
|
|
10958
11219
|
});
|
|
10959
11220
|
}
|
|
10960
11221
|
function prefixVariableReferences(node, prefix) {
|
|
10961
|
-
if (node["kind"] ===
|
|
11222
|
+
if (node["kind"] === chunkVDPZQ5F3_cjs.Kind.VARIABLE && typeof node["name"]?.["value"] === "string") {
|
|
10962
11223
|
node["name"]["value"] = `${prefix}${node["name"]["value"]}`;
|
|
10963
11224
|
return;
|
|
10964
11225
|
}
|
|
@@ -10983,7 +11244,7 @@ function buildPrefixedVariableDefinitions(varDefs, prefix) {
|
|
|
10983
11244
|
}
|
|
10984
11245
|
function extractIncludeInfo(nestedDocument, nestedFieldName, parentVarNames) {
|
|
10985
11246
|
const opDef = nestedDocument.definitions.find(
|
|
10986
|
-
(d) => d.kind ===
|
|
11247
|
+
(d) => d.kind === chunkVDPZQ5F3_cjs.Kind.OPERATION_DEFINITION
|
|
10987
11248
|
);
|
|
10988
11249
|
if (!opDef) {
|
|
10989
11250
|
return { variableDefinitions: [], fieldArguments: [] };
|
|
@@ -10995,7 +11256,7 @@ function extractIncludeInfo(nestedDocument, nestedFieldName, parentVarNames) {
|
|
|
10995
11256
|
let fieldArguments = [];
|
|
10996
11257
|
function findNestedField(selectionSet) {
|
|
10997
11258
|
for (const sel of selectionSet.selections) {
|
|
10998
|
-
if (sel.kind ===
|
|
11259
|
+
if (sel.kind === chunkVDPZQ5F3_cjs.Kind.FIELD) {
|
|
10999
11260
|
if (sel.name.value === nestedFieldName && sel.arguments) {
|
|
11000
11261
|
fieldArguments = sel.arguments;
|
|
11001
11262
|
return;
|
|
@@ -23060,5 +23321,5 @@ exports.getOrCreateDatabase = getOrCreateDatabase;
|
|
|
23060
23321
|
exports.reconstructConnectionNodes = reconstructConnectionNodes;
|
|
23061
23322
|
exports.reconstructEntity = reconstructEntity;
|
|
23062
23323
|
exports.uploadFile = uploadFile;
|
|
23063
|
-
//# sourceMappingURL=chunk-
|
|
23064
|
-
//# sourceMappingURL=chunk-
|
|
23324
|
+
//# sourceMappingURL=chunk-CGJTK2BE.cjs.map
|
|
23325
|
+
//# sourceMappingURL=chunk-CGJTK2BE.cjs.map
|