@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.
Files changed (31) hide show
  1. package/dist/adapters/angular/index.cjs +4 -4
  2. package/dist/adapters/angular/index.d.cts +2 -2
  3. package/dist/adapters/angular/index.d.ts +2 -2
  4. package/dist/adapters/angular/index.js +2 -2
  5. package/dist/billing/index.cjs +5 -5
  6. package/dist/billing/index.js +1 -1
  7. package/dist/{chunk-BJDU4UX4.js → chunk-6PAEAOGQ.js} +508 -247
  8. package/dist/chunk-6PAEAOGQ.js.map +1 -0
  9. package/dist/{chunk-XK5PW7IX.cjs → chunk-CGJTK2BE.cjs} +531 -270
  10. package/dist/chunk-CGJTK2BE.cjs.map +1 -0
  11. package/dist/{chunk-Y4OD5SDF.cjs → chunk-VDPZQ5F3.cjs} +41 -6
  12. package/dist/chunk-VDPZQ5F3.cjs.map +1 -0
  13. package/dist/{chunk-Q5XGHH7D.js → chunk-ZGGY4WK7.js} +42 -5
  14. package/dist/chunk-ZGGY4WK7.js.map +1 -0
  15. package/dist/{client-Bn-0nJ8y.d.ts → client-C0CA6PHq.d.ts} +1 -1
  16. package/dist/{client-Ca2wlmC4.d.cts → client-XvsWJ1Z1.d.cts} +1 -1
  17. package/dist/{index-D50r0Gl0.d.ts → index-Bld5-Yr1.d.ts} +1 -1
  18. package/dist/{index-Ct2Mh0zl.d.cts → index-DF59UYzN.d.cts} +1 -1
  19. package/dist/index.cjs +387 -387
  20. package/dist/index.d.cts +6 -6
  21. package/dist/index.d.ts +6 -6
  22. package/dist/index.js +2 -2
  23. package/dist/pagination/index.d.cts +2 -2
  24. package/dist/pagination/index.d.ts +2 -2
  25. package/dist/{sync-engine-D35aV8Zc.d.ts → sync-engine-CZ0U9XBy.d.ts} +14 -9
  26. package/dist/{sync-engine-21OlgS5_.d.cts → sync-engine-DXESBFX0.d.cts} +14 -9
  27. package/package.json +1 -1
  28. package/dist/chunk-BJDU4UX4.js.map +0 -1
  29. package/dist/chunk-Q5XGHH7D.js.map +0 -1
  30. package/dist/chunk-XK5PW7IX.cjs.map +0 -1
  31. package/dist/chunk-Y4OD5SDF.cjs.map +0 -1
@@ -1,6 +1,6 @@
1
1
  import { Request, Connection, PageInfo, defaultConnection } from './chunk-KEM6SUTS.js';
2
2
  import { createInferenceClientInternal } from './chunk-PDM2KR7T.js';
3
- import { ConnectionSupervisor, consumeSseStream, refreshTokenSingleFlight, createHttpTransport, BillingClient, print, Kind } from './chunk-Q5XGHH7D.js';
3
+ import { createHttpTransport, BillingClient, refreshTokenSingleFlight, print, Kind } from './chunk-ZGGY4WK7.js';
4
4
  import { GRAPHQL_ERROR_CODES, DvinaAuthenticationError, DvinaNetworkError, DvinaGraphQLError, DvinaError, createGraphQLError } from './chunk-7XBJ77RJ.js';
5
5
  import { ChatConnectionFragmentDoc, ChatFragmentDoc, FileFragmentDoc, ChatMessageFragmentDoc, AgentConnectionFragmentDoc, ArtifactConnectionFragmentDoc, DesktopDeviceFragmentDoc, InsightFragmentDoc, ChatMessageConnectionFragmentDoc, ProjectFragmentDoc, ContentBlockFragmentDoc, FeedbackFragmentDoc, DatabaseEngineFragmentDoc, TableConnectionFragmentDoc, ProjectDesktopBindingFragmentDoc, DocumentContentFragmentDoc, DocumentFormatFragmentDoc, FeedSendMessageActionFragmentDoc, FeedArtifactDataFragmentDoc, ReportMemberFragmentDoc, ReportConnectionFragmentDoc, IntegrationProviderFragmentDoc, FeedItemGeneratedFragmentDoc, CandidateFragmentDoc, IntegrationFragmentDoc, InsightConnectionFragmentDoc, DatabaseFragmentDoc, DocumentFragmentDoc, RelationFragmentDoc, AbortChatDocument, AddInsightToReportDocument, CancelOauthFlowDocument, CancelWorkspaceDeletionDocument, ConnectIntegrationDocument, ConsumePulseEventsDocument, ContinueImportedChatDocument, ContinueInterpretationDocument, CreateAgentDocument, CreateChatDocument, CreateDatabaseDocument, CreateDocumentDocument, CreateFeedbackDocument, CreateFolderDocument, CreateInsightDocument, CreateIntegrationDocument, CreateProjectDocument, CreateReportDocument, CreateTableDocument, CreateUserSkillFileDocument, CreateUserSkillFolderDocument, DeleteAgentDocument, DeleteAiProviderSettingDocument, DeleteArtifactDocument, DeleteChatDocument, DeleteDatabaseDocument, DeleteDocumentDocument, DeleteFolderDocument, DeleteInsightDocument, DeleteInsightsDocument, DeleteIntegrationDocument, DeleteProjectDocument, DeleteReportDocument, DeleteTableDocument, DeleteUserSkillFileDocument, DeleteUserSkillFolderDocument, DisconnectIntegrationDocument, DismissPulseEventDocument, ExecuteChatImportDocument, GenerateUploadUriDocument, PreviewChatImportDocument, ReanalyzeDocumentDocument, RefineAgentInstructionDocument, RefineSkillInstructionDocument, RefreshDatabaseSchemaDocument, RefreshInsightDocument, RegisterDesktopDeviceDocument, ReinterpretSourceDocument, ReinterpretSourcesOfuserDocument, RelocateInsightDocument, RemoveInsightFromReportDocument, ResetWorkspaceDocument, ResolvePulseEventDocument, ScheduleWorkspaceDeletionDocument, SendMessageDocument, SetDatabasePrimaryKeyDocument, SyncProjectDesktopBindingDocument, UpdateAgentDocument, UpdateArtifactNameDocument, UpdateChatDocument, UpdateDatabaseDocument, UpdateDocumentDocument, UpdateFolderDocument, UpdateInsightDocument, UpdateInsightInReportDocument, UpdateInsightThumbnailDocument, UpdateInterpDocument, UpdateLiveContextDocument, UpdateProjectDocument, UpdatePulseTriggerDocument, UpdateReportDocument, UpdateTableDocument, UpdateUserSkillFileDocument, UpdateUserSkillFolderDocument, UpsertAiProviderSettingDocument, AgentDocument, Agent_ChatsDocument, AgentsDocument, AiProviderSettingDocument, ArtifactDocument, Artifact_ChatDocument, Artifact_Chat_DesktopDeviceDocument, Artifact_Chat_InsightDocument, Artifact_Chat_ProjectDocument, Artifact_FileDocument, Artifact_MessageDocument, Artifact_Message_ChatDocument, Artifact_Message_ContentsDocument, Artifact_Message_FeedbackDocument, ArtifactsDocument, ChatDocument, Chat_AgentsDocument, Chat_ArtifactsDocument, Chat_DesktopDeviceDocument, Chat_DesktopDevice_DesktopBindingsDocument, Chat_InsightDocument, Chat_Insight_ReportMembersDocument, Chat_Insight_ThumbnailFileDocument, Chat_MessagesDocument, Chat_ProjectDocument, Chat_Project_DesktopBindingDocument, ChatMessageDocument, ChatMessage_ArtifactsDocument, ChatMessage_ChatDocument, ChatMessage_Chat_DesktopDeviceDocument, ChatMessage_Chat_InsightDocument, ChatMessage_Chat_ProjectDocument, ChatMessage_ContentsDocument, ChatMessage_FeedbackDocument, ChatMessagesDocument, ChatsDocument, DatabaseDocument, Database_EngineDocument, Database_Engine_CatalogDocument, Database_TablesDocument, DatabaseCatalogDocument, DatabaseCatalog_EngineDocument, DatabaseCatalogsDocument, DatabaseSchemaDocument, DatabasesDocument, DesktopDeviceDocument, DesktopDevice_ChatsDocument, DesktopDevice_DesktopBindingsDocument, DesktopDevicesDocument, DocumentDocument, Document_ContentsDocument, Document_FileDocument, Document_FormatDocument, Document_Format_CatalogDocument, Document_TablesDocument, DocumentCatalogDocument, DocumentCatalog_FormatDocument, DocumentCatalogsDocument, DocumentsDocument, ExportDocument, ExportWithInsightIdDocument, FeedItemDocument, FeedItem_ActionDocument, FeedItem_DataDocument, FeedItemsDocument, FileDocument, FileMetaDocument, FileUrlsDocument, FindFitTierDocument, FolderDocument, FoldersDocument, GetCapabilityDocument, GetDevAccessTokenDocument, GetLimitDocument, GetRemainingDocument, GetTokenUsageByModelDocument, GetTokenUsageHistoryDocument, GetTokenUsageStatusDocument, UsageWindowsStatusTypeFragmentDoc, GetTokenUsageStatus_WindowsDocument, GetTokenUsageStatus_Windows_DayDocument, GetTokenUsageStatus_Windows_FiveHourDocument, GetTokenUsageStatus_Windows_MonthDocument, GetTokenUsageStatus_Windows_WeekDocument, GetUsageDocument, InsightDocument, Insight_ChatDocument, Insight_Chat_DesktopDeviceDocument, Insight_Chat_ProjectDocument, Insight_ReportMembersDocument, Insight_ReportsDocument, Insight_ThumbnailFileDocument, InsightsDocument, IntegrationDocument, Integration_ProviderDocument, Integration_Provider_CatalogDocument, IntegrationCatalogDocument, IntegrationCatalog_ProviderDocument, IntegrationCatalogToolsDocument, IntegrationCatalogsDocument, IntegrationsDocument, InterpretationsDocument, LiveContextDocument, LiveContext_ItemsDocument, LiveContext_SourceDocument, LiveContext_Source_EvidencesDocument, LiveContextsDocument, LocalSandboxDeviceStatusesDocument, NotificationDocument, NotificationsDocument, NotificationsByReferenceDocument, PrivacyStatsDocument, ProjectDocument, Project_ChatsDocument, Project_DesktopBindingDocument, Project_DesktopBinding_DeviceDocument, ProjectsDocument, PulseAppSummaryDocument, PulseEventDocument, PulseEvent_IntegrationDocument, PulseEvent_Integration_ProviderDocument, PulseEventsDocument, PulseTriggerSettingsDocument, QueryDocument, QueryWithInsightIdDocument, QueryWithMessageIdDocument, ReportDocument, Report_InsightsDocument, Report_LayoutDocument, ReportsDocument, TableDocument, Table_DatabaseDocument, Table_Database_EngineDocument, Table_DocumentDocument, Table_Document_ContentsDocument, Table_Document_FileDocument, Table_Document_FormatDocument, Table_FromRelationsDocument, Table_ToRelationsDocument, TablesDocument, UserSkillFileDocument, UserSkillFilesDocument, UserSkillFolderDocument, UserSkillFoldersDocument, WorkspaceDeletionScheduleDocument, McpAuthUpdatesDocument, TokenUsageUpdatesDocument } from './chunk-ETPR6MV5.js';
6
6
  import { __commonJS, __toESM } from './chunk-5WRI5ZAA.js';
@@ -6033,6 +6033,7 @@ var require_dexie = __commonJS({
6033
6033
  // src/chat-stream.ts
6034
6034
  var INITIAL_RECONNECT_DELAY_MS = 1e3;
6035
6035
  var MAX_RECONNECT_DELAY_MS = 3e4;
6036
+ var RECONNECT_BACKOFF_MULTIPLIER = 2;
6036
6037
  var MAX_CONSECUTIVE_AUTH_FAILURES = 3;
6037
6038
  var AuthChatStreamError = class extends Error {
6038
6039
  constructor(status) {
@@ -6046,63 +6047,24 @@ var ChatStreamConnection = class {
6046
6047
  this.chatId = chatId;
6047
6048
  this.options = options;
6048
6049
  this.onEmpty = onEmpty;
6049
- this.supervisor = new ConnectionSupervisor({
6050
- authRetryDelayMs: INITIAL_RECONNECT_DELAY_MS,
6051
- baseReconnectDelayMs: INITIAL_RECONNECT_DELAY_MS,
6052
- getToken: options.getToken,
6053
- id: chatId,
6054
- isAuthError: (error) => error instanceof AuthChatStreamError,
6055
- kind: "chat-sse",
6056
- maxConsecutiveAuthFailures: MAX_CONSECUTIVE_AUTH_FAILURES,
6057
- maxReconnectDelayMs: MAX_RECONNECT_DELAY_MS,
6058
- onFatalError: () => {
6059
- const authError = new DvinaAuthenticationError("Chat SSE stream authentication failed permanently");
6060
- this.options.onError?.(authError);
6061
- this.close(authError);
6062
- },
6063
- dial: async (context) => {
6064
- const url = new URL(`${this.options.baseUrl}/${encodeURIComponent(this.chatId)}/stream`);
6065
- if (this.lastEventId) {
6066
- url.searchParams.set("lastEventId", this.lastEventId);
6067
- }
6068
- const response = await fetch(url.toString(), {
6069
- method: "GET",
6070
- headers: {
6071
- Accept: "text/event-stream",
6072
- Authorization: `Bearer ${context.token}`,
6073
- "Cache-Control": "no-cache",
6074
- ...this.lastEventId ? { "Last-Event-ID": this.lastEventId } : {}
6075
- },
6076
- signal: context.signal
6077
- });
6078
- if (!response.ok) {
6079
- if (response.status === 401 || response.status === 403) {
6080
- throw new AuthChatStreamError(response.status);
6081
- }
6082
- throw new Error(`Chat stream connection failed: ${response.status} ${response.statusText}`);
6083
- }
6084
- if (!response.body) {
6085
- throw new Error("Chat stream response has no body");
6086
- }
6087
- context.markConnected();
6088
- await consumeSseStream(response.body, context.signal, {
6089
- onChunk: () => context.markActivity(),
6090
- onEventBlock: (block) => this.processEventBlock(block, context.requestTokenRefresh)
6091
- });
6092
- }
6093
- });
6094
6050
  }
6051
+ abortController;
6052
+ consecutiveAuthFailures = 0;
6095
6053
  destroyed = false;
6096
6054
  lastEventId;
6055
+ needsForceRefresh = false;
6056
+ reconnectDelay = INITIAL_RECONNECT_DELAY_MS;
6057
+ reconnectTimer;
6058
+ shouldReconnect = false;
6097
6059
  subscribers = /* @__PURE__ */ new Set();
6098
- supervisor;
6099
6060
  addSubscriber(subscriber) {
6100
6061
  if (this.destroyed) {
6101
6062
  throw new Error(`Chat stream '${this.chatId}' is closed`);
6102
6063
  }
6103
6064
  this.subscribers.add(subscriber);
6104
- if (this.subscribers.size === 1) {
6105
- void this.supervisor.start();
6065
+ if (!this.shouldReconnect) {
6066
+ this.shouldReconnect = true;
6067
+ void this.doConnect();
6106
6068
  }
6107
6069
  }
6108
6070
  removeSubscriber(subscriber) {
@@ -6112,17 +6074,30 @@ var ChatStreamConnection = class {
6112
6074
  }
6113
6075
  }
6114
6076
  reconnect() {
6115
- if (this.destroyed || this.subscribers.size === 0) {
6077
+ if (!this.shouldReconnect || this.destroyed || this.subscribers.size === 0) {
6116
6078
  return;
6117
6079
  }
6118
- this.supervisor.reconnect();
6080
+ if (this.reconnectTimer) {
6081
+ clearTimeout(this.reconnectTimer);
6082
+ this.reconnectTimer = void 0;
6083
+ }
6084
+ if (this.abortController) {
6085
+ this.abortController.abort();
6086
+ this.abortController = void 0;
6087
+ }
6088
+ void this.doConnect();
6119
6089
  }
6120
6090
  close(error) {
6121
- if (this.destroyed) {
6122
- return;
6123
- }
6091
+ this.shouldReconnect = false;
6124
6092
  this.destroyed = true;
6125
- this.supervisor.close();
6093
+ if (this.reconnectTimer) {
6094
+ clearTimeout(this.reconnectTimer);
6095
+ this.reconnectTimer = void 0;
6096
+ }
6097
+ if (this.abortController) {
6098
+ this.abortController.abort();
6099
+ this.abortController = void 0;
6100
+ }
6126
6101
  for (const subscriber of Array.from(this.subscribers)) {
6127
6102
  subscriber.finish(error);
6128
6103
  }
@@ -6132,7 +6107,94 @@ var ChatStreamConnection = class {
6132
6107
  get isDestroyed() {
6133
6108
  return this.destroyed;
6134
6109
  }
6135
- processEventBlock(block, requestTokenRefresh) {
6110
+ async doConnect() {
6111
+ if (!this.shouldReconnect || this.destroyed || this.subscribers.size === 0) {
6112
+ return;
6113
+ }
6114
+ this.abortController = new AbortController();
6115
+ try {
6116
+ const forceRefresh = this.needsForceRefresh;
6117
+ this.needsForceRefresh = false;
6118
+ const token = await this.options.getToken(forceRefresh ? { forceRefresh: true } : void 0);
6119
+ const url = new URL(`${this.options.baseUrl}/${encodeURIComponent(this.chatId)}/stream`);
6120
+ if (this.lastEventId) {
6121
+ url.searchParams.set("lastEventId", this.lastEventId);
6122
+ }
6123
+ const response = await fetch(url.toString(), {
6124
+ method: "GET",
6125
+ headers: {
6126
+ Accept: "text/event-stream",
6127
+ Authorization: `Bearer ${token}`,
6128
+ "Cache-Control": "no-cache",
6129
+ ...this.lastEventId ? { "Last-Event-ID": this.lastEventId } : {}
6130
+ },
6131
+ signal: this.abortController.signal
6132
+ });
6133
+ if (!response.ok) {
6134
+ if (response.status === 401 || response.status === 403) {
6135
+ throw new AuthChatStreamError(response.status);
6136
+ }
6137
+ throw new Error(`Chat stream connection failed: ${response.status} ${response.statusText}`);
6138
+ }
6139
+ if (!response.body) {
6140
+ throw new Error("Chat stream response has no body");
6141
+ }
6142
+ this.consecutiveAuthFailures = 0;
6143
+ this.reconnectDelay = INITIAL_RECONNECT_DELAY_MS;
6144
+ await this.parseSseStream(response.body, this.abortController.signal);
6145
+ } catch (error) {
6146
+ if (error.name === "AbortError") {
6147
+ return;
6148
+ }
6149
+ if (!this.shouldReconnect || this.destroyed || this.subscribers.size === 0) {
6150
+ return;
6151
+ }
6152
+ const isAuthError2 = error instanceof AuthChatStreamError;
6153
+ if (isAuthError2) {
6154
+ this.consecutiveAuthFailures += 1;
6155
+ if (this.consecutiveAuthFailures >= MAX_CONSECUTIVE_AUTH_FAILURES) {
6156
+ const authError = new DvinaAuthenticationError("Chat SSE stream authentication failed permanently");
6157
+ this.options.onError?.(authError);
6158
+ this.close(authError);
6159
+ return;
6160
+ }
6161
+ this.needsForceRefresh = true;
6162
+ }
6163
+ const delay = isAuthError2 ? INITIAL_RECONNECT_DELAY_MS : this.reconnectDelay;
6164
+ this.scheduleReconnect(delay);
6165
+ if (!isAuthError2) {
6166
+ this.reconnectDelay = Math.min(
6167
+ this.reconnectDelay * RECONNECT_BACKOFF_MULTIPLIER,
6168
+ MAX_RECONNECT_DELAY_MS
6169
+ );
6170
+ }
6171
+ }
6172
+ }
6173
+ async parseSseStream(body, signal) {
6174
+ const reader = body.getReader();
6175
+ const decoder = new TextDecoder();
6176
+ let buffer = "";
6177
+ try {
6178
+ while (!signal.aborted && this.shouldReconnect && !this.destroyed) {
6179
+ const { done, value } = await reader.read();
6180
+ if (done) {
6181
+ break;
6182
+ }
6183
+ buffer += decoder.decode(value, { stream: true });
6184
+ const parts = buffer.split(/(?:\r\n|\r|\n){2}/);
6185
+ buffer = parts.pop() ?? "";
6186
+ for (const part of parts) {
6187
+ this.processEventBlock(part.trim());
6188
+ }
6189
+ }
6190
+ } finally {
6191
+ reader.releaseLock();
6192
+ }
6193
+ if (this.shouldReconnect && !this.destroyed && this.subscribers.size > 0) {
6194
+ this.scheduleReconnect(this.reconnectDelay);
6195
+ }
6196
+ }
6197
+ processEventBlock(block) {
6136
6198
  if (!block || block.startsWith(":")) {
6137
6199
  return;
6138
6200
  }
@@ -6149,8 +6211,8 @@ var ChatStreamConnection = class {
6149
6211
  }
6150
6212
  }
6151
6213
  if (eventType === "token-expired") {
6152
- requestTokenRefresh();
6153
- throw new AuthChatStreamError(401);
6214
+ this.needsForceRefresh = true;
6215
+ return;
6154
6216
  }
6155
6217
  if (!eventId || dataLines.length === 0) {
6156
6218
  return;
@@ -6167,64 +6229,40 @@ var ChatStreamConnection = class {
6167
6229
  subscriber.push(value);
6168
6230
  }
6169
6231
  }
6232
+ scheduleReconnect(delay) {
6233
+ if (!this.shouldReconnect || this.destroyed || this.subscribers.size === 0) {
6234
+ return;
6235
+ }
6236
+ if (this.reconnectTimer) {
6237
+ clearTimeout(this.reconnectTimer);
6238
+ }
6239
+ this.reconnectTimer = setTimeout(() => {
6240
+ this.reconnectTimer = void 0;
6241
+ void this.doConnect();
6242
+ }, delay);
6243
+ }
6170
6244
  };
6171
6245
  var ActiveChatStreamConnection = class {
6172
6246
  constructor(options, onEmpty) {
6173
6247
  this.options = options;
6174
6248
  this.onEmpty = onEmpty;
6175
- this.supervisor = new ConnectionSupervisor({
6176
- authRetryDelayMs: INITIAL_RECONNECT_DELAY_MS,
6177
- baseReconnectDelayMs: INITIAL_RECONNECT_DELAY_MS,
6178
- getToken: options.getToken,
6179
- id: "active",
6180
- isAuthError: (error) => error instanceof AuthChatStreamError,
6181
- kind: "active-chat-sse",
6182
- maxConsecutiveAuthFailures: MAX_CONSECUTIVE_AUTH_FAILURES,
6183
- maxReconnectDelayMs: MAX_RECONNECT_DELAY_MS,
6184
- onFatalError: () => {
6185
- const authError = new DvinaAuthenticationError(
6186
- "Active chat SSE stream authentication failed permanently"
6187
- );
6188
- this.options.onError?.(authError);
6189
- this.close(authError);
6190
- },
6191
- dial: async (context) => {
6192
- const response = await fetch(new URL(`${this.options.baseUrl}/active`).toString(), {
6193
- method: "GET",
6194
- headers: {
6195
- Accept: "text/event-stream",
6196
- Authorization: `Bearer ${context.token}`,
6197
- "Cache-Control": "no-cache"
6198
- },
6199
- signal: context.signal
6200
- });
6201
- if (!response.ok) {
6202
- if (response.status === 401 || response.status === 403) {
6203
- throw new AuthChatStreamError(response.status);
6204
- }
6205
- throw new Error(`Active chat stream connection failed: ${response.status} ${response.statusText}`);
6206
- }
6207
- if (!response.body) {
6208
- throw new Error("Active chat stream response has no body");
6209
- }
6210
- context.markConnected();
6211
- await consumeSseStream(response.body, context.signal, {
6212
- onChunk: () => context.markActivity(),
6213
- onEventBlock: (block) => this.processEventBlock(block, context.requestTokenRefresh)
6214
- });
6215
- }
6216
- });
6217
6249
  }
6250
+ abortController;
6251
+ consecutiveAuthFailures = 0;
6218
6252
  destroyed = false;
6253
+ needsForceRefresh = false;
6254
+ reconnectDelay = INITIAL_RECONNECT_DELAY_MS;
6255
+ reconnectTimer;
6256
+ shouldReconnect = false;
6219
6257
  subscribers = /* @__PURE__ */ new Set();
6220
- supervisor;
6221
6258
  addSubscriber(subscriber) {
6222
6259
  if (this.destroyed) {
6223
6260
  throw new Error("Active chat stream is closed");
6224
6261
  }
6225
6262
  this.subscribers.add(subscriber);
6226
- if (this.subscribers.size === 1) {
6227
- void this.supervisor.start();
6263
+ if (!this.shouldReconnect) {
6264
+ this.shouldReconnect = true;
6265
+ void this.doConnect();
6228
6266
  }
6229
6267
  }
6230
6268
  removeSubscriber(subscriber) {
@@ -6234,17 +6272,30 @@ var ActiveChatStreamConnection = class {
6234
6272
  }
6235
6273
  }
6236
6274
  reconnect() {
6237
- if (this.destroyed || this.subscribers.size === 0) {
6275
+ if (!this.shouldReconnect || this.destroyed || this.subscribers.size === 0) {
6238
6276
  return;
6239
6277
  }
6240
- this.supervisor.reconnect();
6278
+ if (this.reconnectTimer) {
6279
+ clearTimeout(this.reconnectTimer);
6280
+ this.reconnectTimer = void 0;
6281
+ }
6282
+ if (this.abortController) {
6283
+ this.abortController.abort();
6284
+ this.abortController = void 0;
6285
+ }
6286
+ void this.doConnect();
6241
6287
  }
6242
6288
  close(error) {
6243
- if (this.destroyed) {
6244
- return;
6245
- }
6289
+ this.shouldReconnect = false;
6246
6290
  this.destroyed = true;
6247
- this.supervisor.close();
6291
+ if (this.reconnectTimer) {
6292
+ clearTimeout(this.reconnectTimer);
6293
+ this.reconnectTimer = void 0;
6294
+ }
6295
+ if (this.abortController) {
6296
+ this.abortController.abort();
6297
+ this.abortController = void 0;
6298
+ }
6248
6299
  for (const subscriber of Array.from(this.subscribers)) {
6249
6300
  subscriber.finish(error);
6250
6301
  }
@@ -6254,7 +6305,91 @@ var ActiveChatStreamConnection = class {
6254
6305
  get isDestroyed() {
6255
6306
  return this.destroyed;
6256
6307
  }
6257
- processEventBlock(block, requestTokenRefresh) {
6308
+ async doConnect() {
6309
+ if (!this.shouldReconnect || this.destroyed || this.subscribers.size === 0) {
6310
+ return;
6311
+ }
6312
+ this.abortController = new AbortController();
6313
+ try {
6314
+ const forceRefresh = this.needsForceRefresh;
6315
+ this.needsForceRefresh = false;
6316
+ const token = await this.options.getToken(forceRefresh ? { forceRefresh: true } : void 0);
6317
+ const response = await fetch(new URL(`${this.options.baseUrl}/active`).toString(), {
6318
+ method: "GET",
6319
+ headers: {
6320
+ Accept: "text/event-stream",
6321
+ Authorization: `Bearer ${token}`,
6322
+ "Cache-Control": "no-cache"
6323
+ },
6324
+ signal: this.abortController.signal
6325
+ });
6326
+ if (!response.ok) {
6327
+ if (response.status === 401 || response.status === 403) {
6328
+ throw new AuthChatStreamError(response.status);
6329
+ }
6330
+ throw new Error(`Active chat stream connection failed: ${response.status} ${response.statusText}`);
6331
+ }
6332
+ if (!response.body) {
6333
+ throw new Error("Active chat stream response has no body");
6334
+ }
6335
+ this.consecutiveAuthFailures = 0;
6336
+ this.reconnectDelay = INITIAL_RECONNECT_DELAY_MS;
6337
+ await this.parseSseStream(response.body, this.abortController.signal);
6338
+ } catch (error) {
6339
+ if (error.name === "AbortError") {
6340
+ return;
6341
+ }
6342
+ if (!this.shouldReconnect || this.destroyed || this.subscribers.size === 0) {
6343
+ return;
6344
+ }
6345
+ const isAuthError2 = error instanceof AuthChatStreamError;
6346
+ if (isAuthError2) {
6347
+ this.consecutiveAuthFailures += 1;
6348
+ if (this.consecutiveAuthFailures >= MAX_CONSECUTIVE_AUTH_FAILURES) {
6349
+ const authError = new DvinaAuthenticationError(
6350
+ "Active chat SSE stream authentication failed permanently"
6351
+ );
6352
+ this.options.onError?.(authError);
6353
+ this.close(authError);
6354
+ return;
6355
+ }
6356
+ this.needsForceRefresh = true;
6357
+ }
6358
+ const delay = isAuthError2 ? INITIAL_RECONNECT_DELAY_MS : this.reconnectDelay;
6359
+ this.scheduleReconnect(delay);
6360
+ if (!isAuthError2) {
6361
+ this.reconnectDelay = Math.min(
6362
+ this.reconnectDelay * RECONNECT_BACKOFF_MULTIPLIER,
6363
+ MAX_RECONNECT_DELAY_MS
6364
+ );
6365
+ }
6366
+ }
6367
+ }
6368
+ async parseSseStream(body, signal) {
6369
+ const reader = body.getReader();
6370
+ const decoder = new TextDecoder();
6371
+ let buffer = "";
6372
+ try {
6373
+ while (!signal.aborted && this.shouldReconnect && !this.destroyed) {
6374
+ const { done, value } = await reader.read();
6375
+ if (done) {
6376
+ break;
6377
+ }
6378
+ buffer += decoder.decode(value, { stream: true });
6379
+ const parts = buffer.split(/(?:\r\n|\r|\n){2}/);
6380
+ buffer = parts.pop() ?? "";
6381
+ for (const part of parts) {
6382
+ this.processEventBlock(part.trim());
6383
+ }
6384
+ }
6385
+ } finally {
6386
+ reader.releaseLock();
6387
+ }
6388
+ if (this.shouldReconnect && !this.destroyed && this.subscribers.size > 0) {
6389
+ this.scheduleReconnect(this.reconnectDelay);
6390
+ }
6391
+ }
6392
+ processEventBlock(block) {
6258
6393
  if (!block || block.startsWith(":")) {
6259
6394
  return;
6260
6395
  }
@@ -6268,8 +6403,8 @@ var ActiveChatStreamConnection = class {
6268
6403
  }
6269
6404
  }
6270
6405
  if (eventType === "token-expired") {
6271
- requestTokenRefresh();
6272
- throw new AuthChatStreamError(401);
6406
+ this.needsForceRefresh = true;
6407
+ return;
6273
6408
  }
6274
6409
  if (eventType !== "active" || dataLines.length === 0) {
6275
6410
  return;
@@ -6288,6 +6423,18 @@ var ActiveChatStreamConnection = class {
6288
6423
  subscriber.push(value);
6289
6424
  }
6290
6425
  }
6426
+ scheduleReconnect(delay) {
6427
+ if (!this.shouldReconnect || this.destroyed || this.subscribers.size === 0) {
6428
+ return;
6429
+ }
6430
+ if (this.reconnectTimer) {
6431
+ clearTimeout(this.reconnectTimer);
6432
+ }
6433
+ this.reconnectTimer = setTimeout(() => {
6434
+ this.reconnectTimer = void 0;
6435
+ void this.doConnect();
6436
+ }, delay);
6437
+ }
6291
6438
  };
6292
6439
  function createChatStreamClient(options) {
6293
6440
  const connections = /* @__PURE__ */ new Map();
@@ -7965,47 +8112,44 @@ var AuthSseError = class extends Error {
7965
8112
  };
7966
8113
  var INITIAL_RECONNECT_DELAY_MS2 = 1e3;
7967
8114
  var MAX_RECONNECT_DELAY_MS2 = 3e4;
8115
+ var RECONNECT_BACKOFF_MULTIPLIER2 = 2;
7968
8116
  var MAX_CONSECUTIVE_AUTH_FAILURES2 = 3;
7969
8117
  var SUBSCRIPTION_REFRESH_INTERVAL_MS = 5 * 60 * 1e3;
7970
- function mapSupervisorState(state) {
7971
- if (state === "connected") {
7972
- return "connected";
7973
- }
7974
- if (state === "connecting") {
7975
- return "connecting";
7976
- }
7977
- return "disconnected";
7978
- }
7979
8118
  function createSseTransport(options) {
8119
+ let abortController;
7980
8120
  let isConnected = false;
7981
- let currentLastSyncId;
8121
+ let reconnectDelay = INITIAL_RECONNECT_DELAY_MS2;
8122
+ let reconnectTimer;
7982
8123
  let refreshTimer;
8124
+ let shouldReconnect = false;
8125
+ let currentLastSyncId;
8126
+ let needsForceRefresh = false;
8127
+ let consecutiveAuthFailures = 0;
7983
8128
  let hasConnectedOnce = false;
7984
- let lastLegacyState;
7985
8129
  const activeSubscriptions = /* @__PURE__ */ new Map();
7986
- const emitLegacyState = (state) => {
7987
- const mapped = mapSupervisorState(state);
7988
- if (mapped === lastLegacyState) {
8130
+ async function connect(lastSyncId) {
8131
+ disconnect();
8132
+ shouldReconnect = true;
8133
+ currentLastSyncId = lastSyncId;
8134
+ await doConnect();
8135
+ }
8136
+ function reconnect() {
8137
+ const lastSyncId = currentLastSyncId;
8138
+ disconnect();
8139
+ shouldReconnect = true;
8140
+ currentLastSyncId = lastSyncId;
8141
+ void doConnect();
8142
+ }
8143
+ async function doConnect() {
8144
+ if (!shouldReconnect) {
7989
8145
  return;
7990
8146
  }
7991
- lastLegacyState = mapped;
7992
- isConnected = mapped === "connected";
7993
- if (!isConnected) {
7994
- stopSubscriptionRefresh();
7995
- }
7996
- options.onStateChange?.(mapped);
7997
- };
7998
- const supervisor = new ConnectionSupervisor({
7999
- authRetryDelayMs: INITIAL_RECONNECT_DELAY_MS2,
8000
- baseReconnectDelayMs: INITIAL_RECONNECT_DELAY_MS2,
8001
- getToken: options.getToken,
8002
- id: "primary",
8003
- isAuthError: (error) => error instanceof AuthSseError,
8004
- kind: "sync-sse",
8005
- maxConsecutiveAuthFailures: MAX_CONSECUTIVE_AUTH_FAILURES2,
8006
- maxReconnectDelayMs: MAX_RECONNECT_DELAY_MS2,
8007
- onStateChange: (snapshot) => emitLegacyState(snapshot.state),
8008
- dial: async (context) => {
8147
+ abortController = new AbortController();
8148
+ options.onStateChange?.("connecting");
8149
+ try {
8150
+ const forceRefresh = needsForceRefresh;
8151
+ needsForceRefresh = false;
8152
+ const token = await options.getToken(forceRefresh ? { forceRefresh: true } : void 0);
8009
8153
  const url = new URL(options.url);
8010
8154
  if (currentLastSyncId && currentLastSyncId !== "0") {
8011
8155
  url.searchParams.set("lastSyncId", currentLastSyncId);
@@ -8013,11 +8157,11 @@ function createSseTransport(options) {
8013
8157
  const response = await fetch(url.toString(), {
8014
8158
  method: "GET",
8015
8159
  headers: {
8016
- Authorization: `Bearer ${context.token}`,
8160
+ Authorization: `Bearer ${token}`,
8017
8161
  Accept: "text/event-stream",
8018
8162
  "Cache-Control": "no-cache"
8019
8163
  },
8020
- signal: context.signal
8164
+ signal: abortController.signal
8021
8165
  });
8022
8166
  if (!response.ok) {
8023
8167
  if (response.status === 401 || response.status === 403) {
@@ -8028,36 +8172,143 @@ function createSseTransport(options) {
8028
8172
  if (!response.body) {
8029
8173
  throw new Error("SSE response has no body");
8030
8174
  }
8175
+ isConnected = true;
8176
+ consecutiveAuthFailures = 0;
8177
+ reconnectDelay = INITIAL_RECONNECT_DELAY_MS2;
8178
+ options.onStateChange?.("connected");
8031
8179
  const isReconnect = hasConnectedOnce;
8032
8180
  hasConnectedOnce = true;
8033
- context.markConnected();
8034
- await syncActiveSubscriptions(context.token);
8181
+ await syncActiveSubscriptions(token);
8035
8182
  startSubscriptionRefresh();
8036
8183
  if (isReconnect && activeSubscriptions.size > 0) {
8037
8184
  options.onReconnect?.();
8038
8185
  }
8039
- await consumeSseStream(response.body, context.signal, {
8040
- onChunk: () => context.markActivity(),
8041
- onEventBlock: (block) => processEventBlock(block, context.requestTokenRefresh)
8042
- });
8186
+ await parseSseStream(response.body, abortController.signal);
8187
+ } catch (error) {
8188
+ if (error.name === "AbortError") {
8189
+ return;
8190
+ }
8191
+ isConnected = false;
8192
+ stopSubscriptionRefresh();
8193
+ options.onStateChange?.("disconnected");
8194
+ if (!shouldReconnect) {
8195
+ return;
8196
+ }
8197
+ const isAuthError2 = error instanceof AuthSseError;
8198
+ if (isAuthError2) {
8199
+ consecutiveAuthFailures += 1;
8200
+ if (consecutiveAuthFailures >= MAX_CONSECUTIVE_AUTH_FAILURES2) {
8201
+ disconnect();
8202
+ return;
8203
+ }
8204
+ needsForceRefresh = true;
8205
+ }
8206
+ const delay = isAuthError2 ? INITIAL_RECONNECT_DELAY_MS2 : reconnectDelay;
8207
+ reconnectTimer = setTimeout(() => {
8208
+ void doConnect();
8209
+ }, delay);
8210
+ if (!isAuthError2) {
8211
+ reconnectDelay = Math.min(reconnectDelay * RECONNECT_BACKOFF_MULTIPLIER2, MAX_RECONNECT_DELAY_MS2);
8212
+ }
8043
8213
  }
8044
- });
8045
- async function connect(lastSyncId) {
8046
- currentLastSyncId = lastSyncId;
8047
- disconnect();
8048
- await supervisor.start();
8049
8214
  }
8050
- function disconnect() {
8051
- supervisor.stop();
8215
+ async function parseSseStream(body, signal) {
8216
+ const reader = body.getReader();
8217
+ const decoder = new TextDecoder();
8218
+ let buffer = "";
8219
+ try {
8220
+ while (!signal.aborted) {
8221
+ const { done, value } = await reader.read();
8222
+ if (done) {
8223
+ break;
8224
+ }
8225
+ buffer += decoder.decode(value, { stream: true });
8226
+ const parts = buffer.split(/(?:\r\n|\r|\n){2}/);
8227
+ buffer = parts.pop() ?? "";
8228
+ for (const part of parts) {
8229
+ processEventBlock(part.trim());
8230
+ }
8231
+ }
8232
+ } finally {
8233
+ reader.releaseLock();
8234
+ }
8235
+ if (!shouldReconnect) {
8236
+ return;
8237
+ }
8052
8238
  isConnected = false;
8053
8239
  stopSubscriptionRefresh();
8054
- if (lastLegacyState !== "disconnected") {
8055
- lastLegacyState = "disconnected";
8056
- options.onStateChange?.("disconnected");
8240
+ options.onStateChange?.("disconnected");
8241
+ reconnectTimer = setTimeout(() => {
8242
+ void doConnect();
8243
+ }, reconnectDelay);
8244
+ }
8245
+ function processEventBlock(block) {
8246
+ if (!block || block.startsWith(":")) {
8247
+ return;
8248
+ }
8249
+ let eventId;
8250
+ let eventType;
8251
+ let eventData;
8252
+ for (const line of block.split(/\r\n|\r|\n/)) {
8253
+ if (line.startsWith("id: ")) {
8254
+ eventId = line.slice(4).trim();
8255
+ } else if (line.startsWith("event: ")) {
8256
+ eventType = line.slice(7).trim();
8257
+ } else if (line.startsWith("data: ")) {
8258
+ eventData = line.slice(6);
8259
+ }
8260
+ }
8261
+ if (eventType === "token-expired") {
8262
+ needsForceRefresh = true;
8263
+ return;
8264
+ }
8265
+ if (eventType === "full-resync") {
8266
+ options.onFullResync?.();
8267
+ return;
8268
+ }
8269
+ if ((eventType === "query-add" || eventType === "query-remove") && eventData) {
8270
+ try {
8271
+ const parsed = JSON.parse(eventData);
8272
+ options.onQueryEvent?.({
8273
+ type: eventType === "query-add" ? "add" : "remove",
8274
+ ...parsed
8275
+ });
8276
+ } catch {
8277
+ }
8278
+ return;
8279
+ }
8280
+ if (!eventId) {
8281
+ return;
8282
+ }
8283
+ currentLastSyncId = eventId;
8284
+ if (eventType === "cursor") {
8285
+ options.onCursor?.(eventId);
8286
+ return;
8287
+ }
8288
+ if (eventType === "sync" && eventData) {
8289
+ try {
8290
+ const parsed = JSON.parse(eventData);
8291
+ options.onEvent({
8292
+ id: eventId,
8293
+ ...parsed
8294
+ });
8295
+ } catch {
8296
+ }
8057
8297
  }
8058
8298
  }
8059
- function reconnect() {
8060
- supervisor.reconnect();
8299
+ function disconnect() {
8300
+ shouldReconnect = false;
8301
+ isConnected = false;
8302
+ stopSubscriptionRefresh();
8303
+ if (reconnectTimer) {
8304
+ clearTimeout(reconnectTimer);
8305
+ reconnectTimer = void 0;
8306
+ }
8307
+ if (abortController) {
8308
+ abortController.abort();
8309
+ abortController = void 0;
8310
+ }
8311
+ options.onStateChange?.("disconnected");
8061
8312
  }
8062
8313
  function subscribe(descriptor) {
8063
8314
  activeSubscriptions.set(descriptor.id, descriptor);
@@ -8121,60 +8372,6 @@ function createSseTransport(options) {
8121
8372
  resolvedToken = await refreshTokenSingleFlight(options.getToken, resolvedToken);
8122
8373
  }
8123
8374
  }
8124
- function processEventBlock(block, requestTokenRefresh) {
8125
- if (!block || block.startsWith(":")) {
8126
- return;
8127
- }
8128
- let eventId;
8129
- let eventType;
8130
- let eventData;
8131
- for (const line of block.split(/\r\n|\r|\n/)) {
8132
- if (line.startsWith("id: ")) {
8133
- eventId = line.slice(4).trim();
8134
- } else if (line.startsWith("event: ")) {
8135
- eventType = line.slice(7).trim();
8136
- } else if (line.startsWith("data: ")) {
8137
- eventData = line.slice(6);
8138
- }
8139
- }
8140
- if (eventType === "token-expired") {
8141
- requestTokenRefresh();
8142
- throw new AuthSseError(401);
8143
- }
8144
- if (eventType === "full-resync") {
8145
- options.onFullResync?.();
8146
- return;
8147
- }
8148
- if ((eventType === "query-add" || eventType === "query-remove") && eventData) {
8149
- try {
8150
- const parsed = JSON.parse(eventData);
8151
- options.onQueryEvent?.({
8152
- type: eventType === "query-add" ? "add" : "remove",
8153
- ...parsed
8154
- });
8155
- } catch {
8156
- }
8157
- return;
8158
- }
8159
- if (!eventId) {
8160
- return;
8161
- }
8162
- currentLastSyncId = eventId;
8163
- if (eventType === "cursor") {
8164
- options.onCursor?.(eventId);
8165
- return;
8166
- }
8167
- if (eventType === "sync" && eventData) {
8168
- try {
8169
- const parsed = JSON.parse(eventData);
8170
- options.onEvent({
8171
- id: eventId,
8172
- ...parsed
8173
- });
8174
- } catch {
8175
- }
8176
- }
8177
- }
8178
8375
  return {
8179
8376
  connect,
8180
8377
  disconnect,
@@ -8810,9 +9007,12 @@ var CacheManager = class {
8810
9007
  */
8811
9008
  async invalidateQuery(operationName, variables) {
8812
9009
  const key = buildQueryKey(operationName, variables);
9010
+ await this.invalidateQueryKey(key);
9011
+ }
9012
+ async invalidateQueryKey(queryKey) {
8813
9013
  await this._db.transaction("rw", [this._db._queryResults, this._db._sync], async () => {
8814
- await this._db._queryResults.delete(key);
8815
- await this._db._sync.delete(getQueryFreshnessKey(key));
9014
+ await this._db._queryResults.delete(queryKey);
9015
+ await this._db._sync.delete(getQueryFreshnessKey(queryKey));
8816
9016
  });
8817
9017
  }
8818
9018
  /**
@@ -9507,6 +9707,7 @@ async function resolveRelationByReference(db, params) {
9507
9707
  }
9508
9708
 
9509
9709
  // src/store/sync-engine.ts
9710
+ var REVALIDATION_RETRY_DELAY_MS = 1e3;
9510
9711
  var SyncEngine = class {
9511
9712
  _db;
9512
9713
  _sse;
@@ -9523,6 +9724,8 @@ var SyncEngine = class {
9523
9724
  _subscriptionToQuery = /* @__PURE__ */ new Map();
9524
9725
  /** Last per-query revalidation timestamp to avoid refetch storms. */
9525
9726
  _lastRevalidatedAt = /* @__PURE__ */ new Map();
9727
+ /** Retry timers for recovery refetches that failed and need another attempt. */
9728
+ _revalidationRetryTimers = /* @__PURE__ */ new Map();
9526
9729
  /**
9527
9730
  * Last mutation/sync touch timestamp by entity type.
9528
9731
  * Used to detect stale cached query results on watch re-entry.
@@ -9560,27 +9763,24 @@ var SyncEngine = class {
9560
9763
  /**
9561
9764
  * Handle a full-resync signal from the server.
9562
9765
  *
9563
- * Clears all cached entities and query results, resets the sync cursor,
9564
- * then restarts the SSE connection so the client gets a fresh cursor.
9565
- * When SSE is available, active subscription-backed watchers are revalidated
9566
- * after the reconnect callback re-registers them with the server.
9567
- * Without SSE, revalidation happens immediately.
9766
+ * Clears all cached entities and query results, restarts delta sync, and
9767
+ * refetches active subscription-backed queries once so filtered connections
9768
+ * are rebuilt from source of truth instead of waiting for future delta events.
9568
9769
  */
9569
9770
  async handleFullResync() {
9570
9771
  this.stopSync();
9571
9772
  await this.clearAll();
9572
9773
  if (this._sse) {
9573
9774
  void this.startSync();
9574
- return;
9575
9775
  }
9576
9776
  await this._revalidateAllActiveSubscriptions();
9577
9777
  }
9578
9778
  /**
9579
- * Revalidate active subscription-backed queries after the SSE transport
9580
- * reconnects and re-registers them with the server.
9779
+ * Ordinary transport reconnects should recover from the sync cursor and
9780
+ * server-side subscription state without eagerly refetching every active query.
9581
9781
  */
9582
9782
  async handleTransportReconnect() {
9583
- await this._revalidateAllActiveSubscriptions();
9783
+ return;
9584
9784
  }
9585
9785
  /**
9586
9786
  * Process an incoming SSE sync event.
@@ -9643,8 +9843,15 @@ var SyncEngine = class {
9643
9843
  void this._revalidateSubscriptionIfStale(subscriptionDescriptor.id);
9644
9844
  const originalDispose = ref.dispose.bind(ref);
9645
9845
  ref.dispose = () => {
9846
+ const hasOtherActiveSubscription = this._hasOtherActiveSubscriptionForQueryKey(
9847
+ queryKey,
9848
+ subscriptionDescriptor.id
9849
+ );
9646
9850
  this._subscriptionToQueryKey.delete(subscriptionDescriptor.id);
9647
9851
  this._subscriptionToQuery.delete(subscriptionDescriptor.id);
9852
+ if (!hasOtherActiveSubscription) {
9853
+ this._clearRevalidationRetry(queryKey);
9854
+ }
9648
9855
  if (this._sse) {
9649
9856
  this._sse.unsubscribe(subscriptionDescriptor.id);
9650
9857
  }
@@ -9816,7 +10023,7 @@ var SyncEngine = class {
9816
10023
  if (!cached) return;
9817
10024
  const fetchedAt = await this._cache.getQueryFetchedAt(sub.queryKey, cached);
9818
10025
  if ((fetchedAt ?? cached.fetchedAt) >= touchedAt) return;
9819
- await this.query(sub.document, sub.variables, sub.operationName).catch(() => void 0);
10026
+ await this._revalidateSubscriptionQuery(sub, { force: true });
9820
10027
  }
9821
10028
  async _revalidateAllActiveSubscriptions() {
9822
10029
  await this._revalidateSubscriptions(Array.from(this._subscriptionToQuery.values()), { force: true });
@@ -9830,15 +10037,60 @@ var SyncEngine = class {
9830
10037
  pendingByQueryKey.set(sub.queryKey, sub);
9831
10038
  }
9832
10039
  if (pendingByQueryKey.size === 0) return;
9833
- for (const sub of pendingByQueryKey.values()) {
9834
- this._lastRevalidatedAt.set(sub.queryKey, now);
9835
- }
9836
10040
  await Promise.all(
9837
- Array.from(pendingByQueryKey.values()).map(
9838
- (sub) => this.query(sub.document, sub.variables, sub.operationName).catch(() => void 0)
9839
- )
10041
+ Array.from(pendingByQueryKey.values()).map((sub) => this._revalidateSubscriptionQuery(sub, options))
9840
10042
  );
9841
10043
  }
10044
+ async _revalidateSubscriptionQuery(subscription, options) {
10045
+ const startedAt = Date.now();
10046
+ this._lastRevalidatedAt.set(subscription.queryKey, startedAt);
10047
+ try {
10048
+ await this.query(subscription.document, subscription.variables, subscription.operationName);
10049
+ this._clearRevalidationRetry(subscription.queryKey);
10050
+ } catch {
10051
+ this._lastRevalidatedAt.delete(subscription.queryKey);
10052
+ await this._cache.invalidateQueryKey(subscription.queryKey).catch(() => void 0);
10053
+ if (options?.force || this._hasActiveSubscriptionForQueryKey(subscription.queryKey)) {
10054
+ this._scheduleRevalidationRetry(subscription.queryKey);
10055
+ }
10056
+ }
10057
+ }
10058
+ _scheduleRevalidationRetry(queryKey) {
10059
+ if (this._revalidationRetryTimers.has(queryKey)) {
10060
+ return;
10061
+ }
10062
+ const timer = setTimeout(() => {
10063
+ this._revalidationRetryTimers.delete(queryKey);
10064
+ const subscription = this._getActiveSubscriptionByQueryKey(queryKey);
10065
+ if (!subscription) {
10066
+ return;
10067
+ }
10068
+ void this._revalidateSubscriptionQuery(subscription, { force: true });
10069
+ }, REVALIDATION_RETRY_DELAY_MS);
10070
+ this._revalidationRetryTimers.set(queryKey, timer);
10071
+ }
10072
+ _clearRevalidationRetry(queryKey) {
10073
+ const timer = this._revalidationRetryTimers.get(queryKey);
10074
+ if (!timer) {
10075
+ return;
10076
+ }
10077
+ clearTimeout(timer);
10078
+ this._revalidationRetryTimers.delete(queryKey);
10079
+ }
10080
+ _getActiveSubscriptionByQueryKey(queryKey) {
10081
+ return Array.from(this._subscriptionToQuery.values()).find((sub) => sub.queryKey === queryKey);
10082
+ }
10083
+ _hasActiveSubscriptionForQueryKey(queryKey) {
10084
+ return this._getActiveSubscriptionByQueryKey(queryKey) !== void 0;
10085
+ }
10086
+ _hasOtherActiveSubscriptionForQueryKey(queryKey, subscriptionId) {
10087
+ for (const [activeSubscriptionId, subscription] of this._subscriptionToQuery.entries()) {
10088
+ if (activeSubscriptionId !== subscriptionId && subscription.queryKey === queryKey) {
10089
+ return true;
10090
+ }
10091
+ }
10092
+ return false;
10093
+ }
9842
10094
  _getActiveSubscriptionsForEntityType(entityType) {
9843
10095
  return Array.from(this._subscriptionToQuery.values()).filter((sub) => sub.entityType === entityType);
9844
10096
  }
@@ -10116,10 +10368,6 @@ function createLazySyncEngine(httpTransport, sseUrl, syncPolicyUrl, getToken, ge
10116
10368
  onFullResync: () => {
10117
10369
  realEngine?.handleFullResync().catch(() => {
10118
10370
  });
10119
- },
10120
- onReconnect: () => {
10121
- realEngine?.handleTransportReconnect().catch(() => {
10122
- });
10123
10371
  }
10124
10372
  });
10125
10373
  sseTransport = transport;
@@ -10376,6 +10624,9 @@ var DEFAULT_BASE_URL = "api.dvina.ai";
10376
10624
  var DB_INIT_TOKEN_POLL_INTERVAL_MS = 100;
10377
10625
  var DB_INIT_TOKEN_TIMEOUT_MS = 15e3;
10378
10626
  var LIFECYCLE_HINT_DEBOUNCE_MS = 250;
10627
+ function shouldRecoverConnections(hints) {
10628
+ return hints.has("network-restored") || hints.has("app-resumed");
10629
+ }
10379
10630
  function resolveGetToken(options) {
10380
10631
  if ("getToken" in options && options.getToken) {
10381
10632
  return options.getToken;
@@ -10486,17 +10737,27 @@ function createDvinaClient(options) {
10486
10737
  const billingSseUrl = `${billingBase}/subscriptions/stream`;
10487
10738
  const billing = new BillingClient({ billingHttpUrl, billingSseUrl, getToken, onError: options.onError });
10488
10739
  let lifecycleHintTimer;
10740
+ const pendingLifecycleHints = /* @__PURE__ */ new Set();
10741
+ const recoverConnections = () => {
10742
+ recoverableSyncEngine.reconnectActiveSync();
10743
+ chatStream.reconnectAll();
10744
+ wsTransport?.terminate();
10745
+ billing.reconnectAll();
10746
+ };
10489
10747
  const lifecycle = {
10490
- hint(_reason) {
10748
+ hint(reason) {
10749
+ pendingLifecycleHints.add(reason);
10491
10750
  if (lifecycleHintTimer) {
10492
10751
  return;
10493
10752
  }
10494
10753
  lifecycleHintTimer = setTimeout(() => {
10495
10754
  lifecycleHintTimer = void 0;
10496
- recoverableSyncEngine.reconnectActiveSync();
10497
- chatStream.reconnectAll();
10498
- wsTransport?.terminate();
10499
- billing.reconnectAll();
10755
+ const hints = new Set(pendingLifecycleHints);
10756
+ pendingLifecycleHints.clear();
10757
+ if (!shouldRecoverConnections(hints)) {
10758
+ return;
10759
+ }
10760
+ recoverConnections();
10500
10761
  }, LIFECYCLE_HINT_DEBOUNCE_MS);
10501
10762
  }
10502
10763
  };
@@ -22674,5 +22935,5 @@ var DvinaSdk = class extends Request {
22674
22935
  };
22675
22936
 
22676
22937
  export { AbortChatMutation, Action, AddInsightToReportMutation, Agent, AgentConnection, AgentQuery, AgentSubBuilder, Agent_ChatsQuery, AgentsQuery, AiProviderSettingQuery, Artifact, ArtifactConnection, ArtifactQuery, ArtifactSubBuilder, Artifact_ChatQuery, Artifact_Chat_DesktopDeviceQuery, Artifact_Chat_InsightQuery, Artifact_Chat_ProjectQuery, Artifact_FileQuery, Artifact_MessageQuery, Artifact_Message_ChatQuery, Artifact_Message_ContentsQuery, Artifact_Message_FeedbackQuery, ArtifactsQuery, AudioEventOutput, CancelOauthFlowMutation, CancelWorkspaceDeletionMutation, Candidate, CandidateEvidence, Chat, ChatConnection, ChatImportExecuteOutput, ChatImportPreviewOutput, ChatMessage, ChatMessageConnection, ChatMessageQuery, ChatMessageSubBuilder, ChatMessage_ArtifactsQuery, ChatMessage_ChatQuery, ChatMessage_Chat_DesktopDeviceQuery, ChatMessage_Chat_InsightQuery, ChatMessage_Chat_ProjectQuery, ChatMessage_ContentsQuery, ChatMessage_FeedbackQuery, ChatMessagesQuery, ChatQuery, ChatSubBuilder, ChatTitleEventOutput, Chat_AgentsQuery, Chat_ArtifactsQuery, Chat_DesktopDeviceQuery, Chat_DesktopDevice_DesktopBindingsQuery, Chat_InsightQuery, Chat_Insight_ReportMembersQuery, Chat_Insight_ThumbnailFileQuery, Chat_MessagesQuery, Chat_ProjectQuery, Chat_Project_DesktopBindingQuery, ChatsQuery, ConnectIntegrationMutation, ConsumePulseEventsMutation, ContentBlock, ContentMask, ContinueImportedChatMutation, ContinueInterpretationMutation, CreateAgentMutation, CreateChatMutation, CreateDatabaseMutation, CreateDocumentMutation, CreateFeedbackMutation, CreateFolderMutation, CreateInsightMutation, CreateIntegrationMutation, CreateIntegrationOutput, CreateProjectMutation, CreateReportMutation, CreateTableMutation, CreateUserSkillFileMutation, CreateUserSkillFolderMutation, CubeModel, DB_ENTITY_SCHEMA, Database, DatabaseCatalog, DatabaseCatalogConnection, DatabaseCatalogQuery, DatabaseCatalogSubBuilder, DatabaseCatalog_EngineQuery, DatabaseCatalogsQuery, DatabaseConnection, DatabaseEngine, DatabaseQuery, DatabaseSchemaQuery, DatabaseSubBuilder, Database_EngineQuery, Database_Engine_CatalogQuery, Database_TablesQuery, DatabasesQuery, DeepAnalysisUsage, DeferredDvinaQueryRef, DeleteAgentMutation, DeleteAiProviderSettingMutation, DeleteArtifactMutation, DeleteChatMutation, DeleteDatabaseMutation, DeleteDocumentMutation, DeleteFolderMutation, DeleteInsightMutation, DeleteInsightsMutation, DeleteIntegrationMutation, DeleteProjectMutation, DeleteReportMutation, DeleteTableMutation, DeleteUserSkillFileMutation, DeleteUserSkillFolderMutation, DesktopDevice, DesktopDeviceConnection, DesktopDeviceQuery, DesktopDeviceSubBuilder, DesktopDevice_ChatsQuery, DesktopDevice_DesktopBindingsQuery, DesktopDevicesQuery, DevAccessTokenOutput, DexieLiveQueryRef, DisconnectIntegrationMutation, DismissPulseEventMutation, Document, DocumentCatalog, DocumentCatalogConnection, DocumentCatalogQuery, DocumentCatalogSubBuilder, DocumentCatalog_FormatQuery, DocumentCatalogsQuery, DocumentConnection, DocumentContent, DocumentFormat, DocumentQuery, DocumentSubBuilder, Document_ContentsQuery, Document_FileQuery, Document_FormatQuery, Document_Format_CatalogQuery, Document_TablesQuery, DocumentsQuery, DvinaDatabase, DvinaModel, DvinaSdk, Evidence, ExecuteChatImportMutation, ExportQuery, ExportWithInsightIdQuery, FailedSyncEventIngestion, FeedArtifactData, FeedConnection, FeedDatabaseData, FeedDocumentData, FeedInsightData, FeedIntegrationData, FeedItem, FeedItemGenerated, FeedItemQuery, FeedItemSubBuilder, FeedItem_ActionQuery, FeedItem_DataQuery, FeedItemsQuery, FeedLiveContextData, FeedProjectData, FeedPulseData, FeedSendMessageAction, Feedback, File, FileMetaQuery, FileModel, FileQuery, FileUrlsQuery, FinalContentEventOutput, FindFitTierQuery, Folder, FolderConnection, FolderQuery, FoldersQuery, GenerateUploadUriMutation, GetCapabilityQuery, GetDevAccessTokenQuery, GetLimitQuery, GetRemainingQuery, GetTokenUsageByModelQuery, GetTokenUsageHistoryQuery, GetTokenUsageStatusQuery, GetTokenUsageStatus_WindowsQuery, GetTokenUsageStatus_Windows_DayQuery, GetTokenUsageStatus_Windows_FiveHourQuery, GetTokenUsageStatus_Windows_MonthQuery, GetTokenUsageStatus_Windows_WeekQuery, GetUsageQuery, ImportedChatSummaryOutput, InferenceRequestAudit, Insight, InsightConnection, InsightQuery, InsightSubBuilder, Insight_ChatQuery, Insight_Chat_DesktopDeviceQuery, Insight_Chat_ProjectQuery, Insight_ReportMembersQuery, Insight_ReportsQuery, Insight_ThumbnailFileQuery, InsightsQuery, Integration, IntegrationCatalog, IntegrationCatalogConnection, IntegrationCatalogQuery, IntegrationCatalogSubBuilder, IntegrationCatalogToolsQuery, IntegrationCatalog_ProviderQuery, IntegrationCatalogsQuery, IntegrationConnection, IntegrationProvider, IntegrationQuery, IntegrationSubBuilder, Integration_ProviderQuery, Integration_Provider_CatalogQuery, IntegrationsQuery, Interpretation, InterpretationConnection, InterpretationsQuery, Invocation, LiveContext, LiveContextConnection, LiveContextQuery, LiveContextSubBuilder, LiveContext_ItemsQuery, LiveContext_SourceQuery, LiveContext_Source_EvidencesQuery, LiveContextsQuery, LocalSandboxDeviceStatusModel, LocalSandboxDeviceStatusesQuery, MUTATION_CACHE_RULES, MappedDvinaQueryRef, McpAuthUpdateModel, McpAuthUpdatesSubscription, McpClientInformation, McpCodeVerifier, McpServer, McpTokens, McpTool, MessageEndEventOutput, MessageStartEventOutput, ModelTokenUsage, Notification, NotificationConnection, NotificationQuery, NotificationsByReferenceQuery, NotificationsQuery, PRIMARY_KEY_CONFIG, PreviewChatImportMutation, PrivacyStats, PrivacyStatsQuery, ProgressSummaryEventOutput, Project, ProjectConnection, ProjectDesktopBinding, ProjectQuery, ProjectSubBuilder, Project_ChatsQuery, Project_DesktopBindingQuery, Project_DesktopBinding_DeviceQuery, ProjectsQuery, PulseAppSummaryModel, PulseAppSummaryQuery, PulseEvent, PulseEventConnection, PulseEventQuery, PulseEventSubBuilder, PulseEvent_IntegrationQuery, PulseEvent_Integration_ProviderQuery, PulseEventsQuery, PulseTriggerSettingModel, PulseTriggerSettingsQuery, QueryQuery, QueryWithInsightIdQuery, QueryWithMessageIdQuery, ReanalyzeDocumentMutation, ReasoningEventOutput, RefineAgentInstructionMutation, RefineSkillInstructionMutation, RefreshDatabaseSchemaMutation, RefreshInsightMutation, RegisterDesktopDeviceMutation, ReinterpretSourceMutation, ReinterpretSourcesOfuserMutation, Relation, RelocateInsightMutation, RemoveInsightFromReportMutation, Report, ReportConnection, ReportMember, ReportQuery, ReportSubBuilder, Report_InsightsQuery, Report_LayoutQuery, ReportsQuery, ResetWorkspaceMutation, ResolvePulseEventMutation, ResolvedFileUrl, ScheduleWorkspaceDeletionMutation, SendMessageMutation, SetDatabasePrimaryKeyMutation, StreamEventSchemaAnchor, StreamMessageContentOutput, StreamMessageOutput, SyncEngine, SyncEvent, SyncEventCursor, SyncProjectDesktopBindingMutation, TABLE_TO_TYPENAME, TYPENAME_TO_TABLE, Table, TableConnection, TableQuery, TableSubBuilder, Table_DatabaseQuery, Table_Database_EngineQuery, Table_DocumentQuery, Table_Document_ContentsQuery, Table_Document_FileQuery, Table_Document_FormatQuery, Table_FromRelationsQuery, Table_ToRelationsQuery, TablesQuery, TextBlockEventOutput, TextDeltaEventOutput, TokenUsage, TokenUsageUpdatesSubscription, ToolInputDeltaEventOutput, ToolResultArtifactOutput, ToolResultEventOutput, ToolStartEventOutput, UpdateAgentMutation, UpdateArtifactNameMutation, UpdateChatMutation, UpdateDatabaseMutation, UpdateDocumentMutation, UpdateFolderMutation, UpdateInsightInReportMutation, UpdateInsightMutation, UpdateInsightThumbnailMutation, UpdateInterpMutation, UpdateLiveContextMutation, UpdateProjectMutation, UpdatePulseTriggerMutation, UpdateReportMutation, UpdateTableMutation, UpdateUserSkillFileMutation, UpdateUserSkillFolderMutation, UpsertAiProviderSettingMutation, UsageMetaOutput, UsageStatus, UsageWindowsStatusType, UserAiProviderSetting, UserSkillFile, UserSkillFileModel, UserSkillFileQuery, UserSkillFilesQuery, UserSkillFolder, UserSkillFolderModel, UserSkillFolderQuery, UserSkillFoldersQuery, WidgetBlockCompleteEventOutput, WidgetBlockErrorEventOutput, WidgetBlockStartEventOutput, WidgetHtmlDeltaEventOutput, WindowDetailType, WorkspaceDeleteSchedule, WorkspaceDeletionScheduleQuery, closeDatabase, createChatStreamClient, createDvinaClient, createLazySyncEngine, createSseTransport, createWsTransport, deleteDatabase, getOrCreateDatabase, reconstructConnectionNodes, reconstructEntity, uploadFile };
22677
- //# sourceMappingURL=chunk-BJDU4UX4.js.map
22678
- //# sourceMappingURL=chunk-BJDU4UX4.js.map
22938
+ //# sourceMappingURL=chunk-6PAEAOGQ.js.map
22939
+ //# sourceMappingURL=chunk-6PAEAOGQ.js.map