@abloatai/ablo 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (278) hide show
  1. package/CHANGELOG.md +208 -0
  2. package/LICENSE +201 -0
  3. package/NOTICE +12 -0
  4. package/README.md +230 -0
  5. package/dist/BaseSyncedStore.d.ts +709 -0
  6. package/dist/BaseSyncedStore.js +1843 -0
  7. package/dist/Database.d.ts +344 -0
  8. package/dist/Database.js +1259 -0
  9. package/dist/LazyReferenceCollection.d.ts +181 -0
  10. package/dist/LazyReferenceCollection.js +460 -0
  11. package/dist/Model.d.ts +339 -0
  12. package/dist/Model.js +715 -0
  13. package/dist/ModelRegistry.d.ts +200 -0
  14. package/dist/ModelRegistry.js +535 -0
  15. package/dist/NetworkMonitor.d.ts +27 -0
  16. package/dist/NetworkMonitor.js +73 -0
  17. package/dist/ObjectPool.d.ts +202 -0
  18. package/dist/ObjectPool.js +1106 -0
  19. package/dist/SyncClient.d.ts +489 -0
  20. package/dist/SyncClient.js +1555 -0
  21. package/dist/SyncEngineContext.d.ts +46 -0
  22. package/dist/SyncEngineContext.js +74 -0
  23. package/dist/adapters/alwaysOnline.d.ts +16 -0
  24. package/dist/adapters/alwaysOnline.js +19 -0
  25. package/dist/adapters/inMemoryStorage.d.ts +30 -0
  26. package/dist/adapters/inMemoryStorage.js +94 -0
  27. package/dist/agent/Agent.d.ts +358 -0
  28. package/dist/agent/Agent.js +500 -0
  29. package/dist/agent/index.d.ts +115 -0
  30. package/dist/agent/index.js +128 -0
  31. package/dist/agent/session.d.ts +90 -0
  32. package/dist/agent/session.js +156 -0
  33. package/dist/agent/types.d.ts +73 -0
  34. package/dist/agent/types.js +10 -0
  35. package/dist/ai-sdk/coordination-context.d.ts +51 -0
  36. package/dist/ai-sdk/coordination-context.js +107 -0
  37. package/dist/ai-sdk/index.d.ts +68 -0
  38. package/dist/ai-sdk/index.js +68 -0
  39. package/dist/ai-sdk/intent-broadcast.d.ts +77 -0
  40. package/dist/ai-sdk/intent-broadcast.js +72 -0
  41. package/dist/ai-sdk/wrap.d.ts +67 -0
  42. package/dist/ai-sdk/wrap.js +45 -0
  43. package/dist/api/index.d.ts +10 -0
  44. package/dist/api/index.js +9 -0
  45. package/dist/auth/index.d.ts +137 -0
  46. package/dist/auth/index.js +246 -0
  47. package/dist/client/Ablo.d.ts +835 -0
  48. package/dist/client/Ablo.js +1440 -0
  49. package/dist/client/ApiClient.d.ts +200 -0
  50. package/dist/client/ApiClient.js +659 -0
  51. package/dist/client/auth.d.ts +79 -0
  52. package/dist/client/auth.js +81 -0
  53. package/dist/client/createInternalComponents.d.ts +44 -0
  54. package/dist/client/createInternalComponents.js +88 -0
  55. package/dist/client/createModelProxy.d.ts +152 -0
  56. package/dist/client/createModelProxy.js +199 -0
  57. package/dist/client/identity.d.ts +63 -0
  58. package/dist/client/identity.js +156 -0
  59. package/dist/client/index.d.ts +36 -0
  60. package/dist/client/index.js +33 -0
  61. package/dist/client/persistence.d.ts +7 -0
  62. package/dist/client/persistence.js +11 -0
  63. package/dist/client/validateAbloOptions.d.ts +42 -0
  64. package/dist/client/validateAbloOptions.js +43 -0
  65. package/dist/config/index.d.ts +10 -0
  66. package/dist/config/index.js +12 -0
  67. package/dist/context.d.ts +27 -0
  68. package/dist/context.js +58 -0
  69. package/dist/core/DatabaseManager.d.ts +108 -0
  70. package/dist/core/DatabaseManager.js +361 -0
  71. package/dist/core/QueryProcessor.d.ts +77 -0
  72. package/dist/core/QueryProcessor.js +262 -0
  73. package/dist/core/QueryView.d.ts +64 -0
  74. package/dist/core/QueryView.js +219 -0
  75. package/dist/core/StoreManager.d.ts +131 -0
  76. package/dist/core/StoreManager.js +334 -0
  77. package/dist/core/ViewRegistry.d.ts +20 -0
  78. package/dist/core/ViewRegistry.js +55 -0
  79. package/dist/core/index.d.ts +34 -0
  80. package/dist/core/index.js +59 -0
  81. package/dist/core/openIDBWithTimeout.d.ts +27 -0
  82. package/dist/core/openIDBWithTimeout.js +63 -0
  83. package/dist/core/query-utils.d.ts +37 -0
  84. package/dist/core/query-utils.js +60 -0
  85. package/dist/errors.d.ts +235 -0
  86. package/dist/errors.js +243 -0
  87. package/dist/index.d.ts +41 -0
  88. package/dist/index.js +82 -0
  89. package/dist/interfaces/headless.d.ts +95 -0
  90. package/dist/interfaces/headless.js +41 -0
  91. package/dist/interfaces/index.d.ts +321 -0
  92. package/dist/interfaces/index.js +8 -0
  93. package/dist/mutators/RecordingTransaction.d.ts +36 -0
  94. package/dist/mutators/RecordingTransaction.js +216 -0
  95. package/dist/mutators/Transaction.d.ts +48 -0
  96. package/dist/mutators/Transaction.js +64 -0
  97. package/dist/mutators/UndoManager.d.ts +114 -0
  98. package/dist/mutators/UndoManager.js +143 -0
  99. package/dist/mutators/defineMutators.d.ts +55 -0
  100. package/dist/mutators/defineMutators.js +28 -0
  101. package/dist/policy/index.d.ts +19 -0
  102. package/dist/policy/index.js +18 -0
  103. package/dist/policy/types.d.ts +74 -0
  104. package/dist/policy/types.js +17 -0
  105. package/dist/principal.d.ts +44 -0
  106. package/dist/principal.js +49 -0
  107. package/dist/query/client.d.ts +43 -0
  108. package/dist/query/client.js +84 -0
  109. package/dist/query/index.d.ts +6 -0
  110. package/dist/query/index.js +5 -0
  111. package/dist/query/types.d.ts +143 -0
  112. package/dist/query/types.js +36 -0
  113. package/dist/react/AbloProvider.d.ts +205 -0
  114. package/dist/react/AbloProvider.js +398 -0
  115. package/dist/react/ClientSideSuspense.d.ts +36 -0
  116. package/dist/react/ClientSideSuspense.js +17 -0
  117. package/dist/react/DefaultFallback.d.ts +24 -0
  118. package/dist/react/DefaultFallback.js +43 -0
  119. package/dist/react/SyncGroupProvider.d.ts +19 -0
  120. package/dist/react/SyncGroupProvider.js +44 -0
  121. package/dist/react/context.d.ts +161 -0
  122. package/dist/react/context.js +35 -0
  123. package/dist/react/index.d.ts +64 -0
  124. package/dist/react/index.js +73 -0
  125. package/dist/react/internalContext.d.ts +35 -0
  126. package/dist/react/internalContext.js +3 -0
  127. package/dist/react/useAblo.d.ts +72 -0
  128. package/dist/react/useAblo.js +63 -0
  129. package/dist/react/useCurrentUserId.d.ts +21 -0
  130. package/dist/react/useCurrentUserId.js +33 -0
  131. package/dist/react/useErrorListener.d.ts +20 -0
  132. package/dist/react/useErrorListener.js +39 -0
  133. package/dist/react/useIntent.d.ts +29 -0
  134. package/dist/react/useIntent.js +42 -0
  135. package/dist/react/useMutate.d.ts +83 -0
  136. package/dist/react/useMutate.js +122 -0
  137. package/dist/react/useMutationFailureListener.d.ts +26 -0
  138. package/dist/react/useMutationFailureListener.js +38 -0
  139. package/dist/react/useMutators.d.ts +56 -0
  140. package/dist/react/useMutators.js +66 -0
  141. package/dist/react/usePresence.d.ts +32 -0
  142. package/dist/react/usePresence.js +41 -0
  143. package/dist/react/useQuery.d.ts +123 -0
  144. package/dist/react/useQuery.js +145 -0
  145. package/dist/react/useReactive.d.ts +35 -0
  146. package/dist/react/useReactive.js +111 -0
  147. package/dist/react/useReader.d.ts +69 -0
  148. package/dist/react/useReader.js +73 -0
  149. package/dist/react/useSyncStatus.d.ts +61 -0
  150. package/dist/react/useSyncStatus.js +76 -0
  151. package/dist/react/useUndoScope.d.ts +36 -0
  152. package/dist/react/useUndoScope.js +73 -0
  153. package/dist/realtime/index.d.ts +10 -0
  154. package/dist/realtime/index.js +9 -0
  155. package/dist/schema/field.d.ts +134 -0
  156. package/dist/schema/field.js +264 -0
  157. package/dist/schema/index.d.ts +29 -0
  158. package/dist/schema/index.js +38 -0
  159. package/dist/schema/model.d.ts +326 -0
  160. package/dist/schema/model.js +89 -0
  161. package/dist/schema/queries.d.ts +203 -0
  162. package/dist/schema/queries.js +145 -0
  163. package/dist/schema/relation.d.ts +172 -0
  164. package/dist/schema/relation.js +104 -0
  165. package/dist/schema/schema.d.ts +259 -0
  166. package/dist/schema/schema.js +188 -0
  167. package/dist/schema/sugar.d.ts +129 -0
  168. package/dist/schema/sugar.js +94 -0
  169. package/dist/source/index.d.ts +423 -0
  170. package/dist/source/index.js +320 -0
  171. package/dist/source/pushQueue.d.ts +112 -0
  172. package/dist/source/pushQueue.js +249 -0
  173. package/dist/stores/ObjectStore.d.ts +103 -0
  174. package/dist/stores/ObjectStore.js +371 -0
  175. package/dist/stores/ObjectStoreContract.d.ts +39 -0
  176. package/dist/stores/ObjectStoreContract.js +1 -0
  177. package/dist/stores/SyncActionStore.d.ts +101 -0
  178. package/dist/stores/SyncActionStore.js +481 -0
  179. package/dist/sync/BootstrapHelper.d.ts +127 -0
  180. package/dist/sync/BootstrapHelper.js +434 -0
  181. package/dist/sync/ConnectionManager.d.ts +136 -0
  182. package/dist/sync/ConnectionManager.js +465 -0
  183. package/dist/sync/HydrationCoordinator.d.ts +137 -0
  184. package/dist/sync/HydrationCoordinator.js +468 -0
  185. package/dist/sync/NetworkProbe.d.ts +43 -0
  186. package/dist/sync/NetworkProbe.js +113 -0
  187. package/dist/sync/OfflineFlush.d.ts +9 -0
  188. package/dist/sync/OfflineFlush.js +22 -0
  189. package/dist/sync/OfflineTransactionStore.d.ts +37 -0
  190. package/dist/sync/OfflineTransactionStore.js +263 -0
  191. package/dist/sync/SyncWebSocket.d.ts +663 -0
  192. package/dist/sync/SyncWebSocket.js +1336 -0
  193. package/dist/sync/createIntentStream.d.ts +33 -0
  194. package/dist/sync/createIntentStream.js +243 -0
  195. package/dist/sync/createPresenceStream.d.ts +46 -0
  196. package/dist/sync/createPresenceStream.js +192 -0
  197. package/dist/sync/createSnapshot.d.ts +33 -0
  198. package/dist/sync/createSnapshot.js +124 -0
  199. package/dist/sync/participants.d.ts +114 -0
  200. package/dist/sync/participants.js +336 -0
  201. package/dist/sync/schemas.d.ts +79 -0
  202. package/dist/sync/schemas.js +78 -0
  203. package/dist/testing/fixtures/bootstrap.d.ts +45 -0
  204. package/dist/testing/fixtures/bootstrap.js +53 -0
  205. package/dist/testing/fixtures/deltas.d.ts +86 -0
  206. package/dist/testing/fixtures/deltas.js +139 -0
  207. package/dist/testing/fixtures/models.d.ts +82 -0
  208. package/dist/testing/fixtures/models.js +270 -0
  209. package/dist/testing/helpers/react-wrapper.d.ts +66 -0
  210. package/dist/testing/helpers/react-wrapper.js +64 -0
  211. package/dist/testing/helpers/sync-engine-harness.d.ts +55 -0
  212. package/dist/testing/helpers/sync-engine-harness.js +70 -0
  213. package/dist/testing/helpers/wait.d.ts +25 -0
  214. package/dist/testing/helpers/wait.js +44 -0
  215. package/dist/testing/index.d.ts +21 -0
  216. package/dist/testing/index.js +32 -0
  217. package/dist/testing/mocks/MockMutationExecutor.d.ts +65 -0
  218. package/dist/testing/mocks/MockMutationExecutor.js +139 -0
  219. package/dist/testing/mocks/MockNetworkMonitor.d.ts +20 -0
  220. package/dist/testing/mocks/MockNetworkMonitor.js +46 -0
  221. package/dist/testing/mocks/MockSyncContext.d.ts +64 -0
  222. package/dist/testing/mocks/MockSyncContext.js +100 -0
  223. package/dist/testing/mocks/MockSyncStore.d.ts +88 -0
  224. package/dist/testing/mocks/MockSyncStore.js +171 -0
  225. package/dist/testing/mocks/MockWebSocket.d.ts +66 -0
  226. package/dist/testing/mocks/MockWebSocket.js +117 -0
  227. package/dist/transactions/OptimisticEchoTracker.d.ts +82 -0
  228. package/dist/transactions/OptimisticEchoTracker.js +104 -0
  229. package/dist/transactions/TransactionQueue.d.ts +499 -0
  230. package/dist/transactions/TransactionQueue.js +1895 -0
  231. package/dist/transactions/index.d.ts +16 -0
  232. package/dist/transactions/index.js +7 -0
  233. package/dist/transactions/mutation-error-handler.d.ts +5 -0
  234. package/dist/transactions/mutation-error-handler.js +39 -0
  235. package/dist/types/global.d.ts +107 -0
  236. package/dist/types/global.js +38 -0
  237. package/dist/types/index.d.ts +241 -0
  238. package/dist/types/index.js +70 -0
  239. package/dist/types/streams.d.ts +495 -0
  240. package/dist/types/streams.js +11 -0
  241. package/dist/utils/asyncIterator.d.ts +41 -0
  242. package/dist/utils/asyncIterator.js +142 -0
  243. package/dist/utils/duration.d.ts +28 -0
  244. package/dist/utils/duration.js +47 -0
  245. package/dist/utils/mobx-setup.d.ts +42 -0
  246. package/dist/utils/mobx-setup.js +381 -0
  247. package/docs/api-keys.md +24 -0
  248. package/docs/api.md +230 -0
  249. package/docs/audit.md +81 -0
  250. package/docs/capabilities.md +163 -0
  251. package/docs/client-behavior.md +202 -0
  252. package/docs/data-sources.md +214 -0
  253. package/docs/examples/agent-human.md +84 -0
  254. package/docs/examples/ai-sdk-tool.md +92 -0
  255. package/docs/examples/existing-python-backend.md +249 -0
  256. package/docs/examples/nextjs.md +88 -0
  257. package/docs/examples/server-agent.md +86 -0
  258. package/docs/guarantees.md +148 -0
  259. package/docs/index.md +97 -0
  260. package/docs/integration-guide.md +493 -0
  261. package/docs/interaction-model.md +140 -0
  262. package/docs/mcp/claude-code.md +43 -0
  263. package/docs/mcp/cursor.md +53 -0
  264. package/docs/mcp/windsurf.md +46 -0
  265. package/docs/mcp.md +59 -0
  266. package/docs/quickstart.md +152 -0
  267. package/docs/react.md +115 -0
  268. package/docs/roadmap.md +45 -0
  269. package/examples/README.md +54 -0
  270. package/examples/data-source/README.md +102 -0
  271. package/examples/data-source/ablo-driver.ts +89 -0
  272. package/examples/data-source/customer-server.ts +208 -0
  273. package/examples/data-source/run.ts +101 -0
  274. package/examples/data-source/schema.ts +25 -0
  275. package/examples/quickstart.ts +54 -0
  276. package/examples/tsconfig.json +16 -0
  277. package/llms.txt +143 -0
  278. package/package.json +147 -0
@@ -0,0 +1,344 @@
1
+ /**
2
+ * Database - Simplified persistence layer
3
+ * Fixed bootstrap triggering and data flow
4
+ */
5
+ import { type DatabaseInfo, type WorkspaceMetadata } from './core/DatabaseManager.js';
6
+ import { ModelRegistry } from './ModelRegistry.js';
7
+ import { LoadStrategy } from './types/index.js';
8
+ import type { BootstrapHelper, BootstrapData } from './sync/BootstrapHelper.js';
9
+ import { InMemoryObjectStore } from './adapters/inMemoryStorage.js';
10
+ /** Generic record type for model data */
11
+ type ModelData = Record<string, unknown>;
12
+ /** Persisted mutation in a transaction */
13
+ interface PersistedMutation {
14
+ type: 'create' | 'update' | 'delete' | 'archive';
15
+ modelData: ModelData;
16
+ modelName: string;
17
+ timestamp: string;
18
+ writeOptions?: {
19
+ readAt?: number | null;
20
+ onStale?: 'reject' | 'force' | 'flag' | 'merge' | null;
21
+ };
22
+ }
23
+ /** Persisted transaction for offline/retry support.
24
+ *
25
+ * Index signature is part of the contract: this interface targets
26
+ * the generic record-shaped storage layer (`InMemoryObjectStore.put`
27
+ * + the IDB ObjectStore equivalent), both of which take
28
+ * `Record<string, unknown>`. Every declared field below already
29
+ * satisfies `unknown`; the index signature just makes the
30
+ * interface assignable to the storage parameter without a cast. */
31
+ interface PersistedTransaction {
32
+ id: string;
33
+ type?: string;
34
+ timestamp?: number;
35
+ createdAt?: number;
36
+ mutations?: PersistedMutation[];
37
+ awaitingDelta?: {
38
+ syncIdNeeded: number;
39
+ modelName: string;
40
+ modelId: string;
41
+ operationType: string;
42
+ };
43
+ [key: string]: unknown;
44
+ }
45
+ /**
46
+ * Bootstrap strategies (aligned with Linear's architecture):
47
+ *
48
+ * 'full' - Full bootstrap from server
49
+ * - Fetch complete snapshot from server
50
+ * - Clear IndexedDB
51
+ * - Load snapshot data
52
+ * - Use snapshot's lastSyncId
53
+ *
54
+ * 'local' - Local-only bootstrap (skip server fetch)
55
+ * - Use existing IndexedDB data
56
+ * - Hydrate ObjectPool from IndexedDB
57
+ * - Connect WebSocket with stored lastSyncId
58
+ * - Receive deltas from lastSyncId+1 onwards
59
+ */
60
+ export type BootstrapType = 'full' | 'partial' | 'local';
61
+ export interface BootstrapRequirements {
62
+ type: BootstrapType;
63
+ modelsToLoad: string[];
64
+ lastSyncId: number;
65
+ syncGroups: string[];
66
+ }
67
+ export interface BootstrapResult {
68
+ modelsLoaded: number;
69
+ modelsStored: number;
70
+ /** The raw bootstrap response — callers can apply models directly to ObjectPool */
71
+ bootstrapData: BootstrapData;
72
+ /**
73
+ * Results of applying partial-bootstrap deltas to IDB. Present only when
74
+ * `bootstrapData.type === 'partial'` and deltas were processed. Callers
75
+ * forward these to `syncClient.applyDeltaBatchToPool` so the in-memory
76
+ * pool reflects inserts/updates/deletes that arrived while the client
77
+ * was disconnected — without this, DELETE deltas persist to IDB but
78
+ * ghost entities linger in the pool until a full reload.
79
+ */
80
+ deltaResults?: Array<{
81
+ action: 'add' | 'update' | 'remove' | 'archive' | 'verify';
82
+ modelName: string;
83
+ modelId: string;
84
+ data?: ModelData | null;
85
+ }>;
86
+ }
87
+ export declare class Database {
88
+ private databaseManager;
89
+ private storeManager;
90
+ private modelRegistry;
91
+ private bootstrapHelper;
92
+ /** The pre-configured query helper for lazy-loading data from the sync server. */
93
+ get helper(): BootstrapHelper;
94
+ private currentDbInfo;
95
+ private workspaceDb;
96
+ /**
97
+ * Flag to track if database is closing/closed.
98
+ * Used for graceful degradation when operations are attempted during shutdown.
99
+ */
100
+ private isClosing;
101
+ /**
102
+ * When set, forces the next requiredBootstrap() call to return 'full' even if offline.
103
+ * Used when a sync group change delta is received — we must re-bootstrap to purge
104
+ * revoked data, even if the device is currently offline (it will bootstrap when online).
105
+ */
106
+ private _forceFullBootstrap;
107
+ /** Essential fields that must be preserved during partial UPDATE merges.
108
+ * Sourced from SyncEngineConfig.essentialFields — consumers define their own. */
109
+ private get essentialFields();
110
+ /**
111
+ * When true, all IndexedDB operations are replaced with in-memory Maps.
112
+ * Enables the SDK to run headlessly in Node.js / agent workers / tests
113
+ * without requiring a browser environment.
114
+ *
115
+ * Set via createSyncEngine({ storage: inMemoryStorage() }) or directly:
116
+ * new Database(registry, bootstrap, { inMemory: true })
117
+ */
118
+ private readonly inMemory;
119
+ /** In-memory stores used when inMemory=true. Keyed by model name. */
120
+ private inMemoryStores;
121
+ /** In-memory workspace metadata when inMemory=true. */
122
+ private inMemoryMetadata;
123
+ constructor(modelRegistry: ModelRegistry, bootstrapHelper: BootstrapHelper, options?: {
124
+ inMemory?: boolean;
125
+ });
126
+ /**
127
+ * Get store for a model, or `undefined` if no store exists.
128
+ *
129
+ * Routes to `inMemoryStores` in inMemory mode and `storeManager`
130
+ * otherwise. Both implementations satisfy `ObjectStoreContract`, so
131
+ * callers don't branch on which one they got back.
132
+ *
133
+ * Pass `context` to emit an observability breadcrumb when the store
134
+ * is missing — useful for hot paths (bootstrap, delta apply, hydrate)
135
+ * where a missing store points to silent data loss. Callers that
136
+ * already expect optional behavior (e.g. lazy lookups) can omit it.
137
+ */
138
+ getStore(modelName: string, context?: string): import("./stores/ObjectStore.js").ObjectStore | InMemoryObjectStore | undefined;
139
+ /** Get store or throw if not found (for operations that require the store). */
140
+ private getRequiredStore;
141
+ /** Log preserved fields during partial UPDATE merge (debug helper) */
142
+ private logPreservedFields;
143
+ open(userId: string, organizationId: string, version?: number): Promise<void>;
144
+ /**
145
+ * Compact a record before persisting to IndexedDB
146
+ * - Removes null/undefined fields
147
+ * - Removes empty arrays and empty objects
148
+ * - Drops redundant fields: __typename, __class, clientId, syncStatus
149
+ *
150
+ * ARCHITECTURE: By design, this method receives plain objects, not MobX observables:
151
+ * - WebSocket deltas: Already JSON-parsed (SyncedStore.ts:889)
152
+ * - Optimistic updates: Models call toJSON() which uses toJS() (SlideLayer.ts:224)
153
+ * - Bootstrap data: Plain JSON from server
154
+ *
155
+ * Note: We do NOT drop required defaults; server provides them.
156
+ */
157
+ private compactRecord;
158
+ /**
159
+ * Mark that the next bootstrap must be a full bootstrap.
160
+ * Called when a sync group change ("G" delta) is received — the client must
161
+ * re-fetch all data from the server to purge models from revoked sync groups.
162
+ */
163
+ markRequiresFullBootstrap(): void;
164
+ /**
165
+ * Smart bootstrap requirements based on data freshness
166
+ */
167
+ requiredBootstrap(): Promise<BootstrapRequirements>;
168
+ /**
169
+ * Bootstrap database with data from Go server
170
+ */
171
+ bootstrapFromServer(requirements: BootstrapRequirements,
172
+ /** Full sync-group subscription list — what the WS subscribes to
173
+ * AND what gets persisted as `subscribedSyncGroups` for the
174
+ * shrinkage check. Caller supplies the complete list, not just
175
+ * team-derived groups. */
176
+ syncGroups: readonly string[], onProgress?: (loaded: number) => void): Promise<BootstrapResult>;
177
+ /**
178
+ * Process incoming delta from WebSocket - simplified
179
+ *
180
+ * ⚠️ PERFORMANCE NOTE: This method is called for each individual delta.
181
+ * For batch processing, use processDeltaBatch() instead to avoid
182
+ * transaction overhead (2x transactions per delta = major bottleneck).
183
+ *
184
+ * 📝 PARTIAL DELTA PATTERN:
185
+ * - Server sends only changed fields: {id, position: {...}, updatedAt}
186
+ * - UPDATE deltas are MERGED with existing records: {...existing, ...delta}
187
+ * - This preserves fields not included in the delta (e.g., deckId, title)
188
+ * - Explicit null values ARE preserved: {position: null} clears the field
189
+ */
190
+ processDelta(delta: {
191
+ syncId?: number;
192
+ /**
193
+ * Includes 'G' and 'S' defensively — those are routed upstream by
194
+ * BaseSyncedStore.processDeltaWithBatching and should not reach here,
195
+ * but the switch returns a no-op verify if one slips through (e.g.
196
+ * replayed from the bootstrap queue) rather than crashing the engine.
197
+ */
198
+ actionType: 'I' | 'U' | 'D' | 'A' | 'V' | 'C' | 'G' | 'S';
199
+ modelName: string;
200
+ modelId: string;
201
+ data: ModelData | null;
202
+ }): Promise<{
203
+ action: 'add' | 'update' | 'remove' | 'archive' | 'verify';
204
+ modelName: string;
205
+ modelId: string;
206
+ data?: ModelData | null;
207
+ }>;
208
+ /**
209
+ * ✅ PERFORMANCE FIX: Process multiple deltas in a single IndexedDB transaction
210
+ *
211
+ * This method dramatically improves sync performance by:
212
+ * 1. Batch-reading all existing records for UPDATEs (outside transaction for speed)
213
+ * 2. Opening a single transaction per store for all writes
214
+ * 3. Merging UPDATE deltas with existing data to preserve unmodified fields
215
+ * 4. Updating metadata only once at the end with highest syncId
216
+ *
217
+ * Performance impact: 186 deltas goes from ~372 transactions to just 1 transaction
218
+ *
219
+ * 📝 PARTIAL DELTA MERGE PATTERN:
220
+ * - UPDATE deltas contain only changed fields
221
+ * - We merge with existing: {...existing, ...delta}
222
+ * - Preserves deckId, title, settings etc. when updating just position
223
+ * - Handles explicit null: {field: null} clears the field correctly
224
+ *
225
+ * 🔄 LINEAR-STYLE CONFLICT RESOLUTION:
226
+ * - Builds a map of DELETE deltas with their syncIds
227
+ * - Before processing UPDATE/INSERT, checks for DELETE with higher syncId
228
+ * - Skips stale updates for entities that will be/were deleted
229
+ * - Prevents 404 errors from fetching already-deleted entities
230
+ */
231
+ processDeltaBatch(deltas: Array<{
232
+ syncId?: number;
233
+ /**
234
+ * Includes 'G' and 'S' defensively — they're routed upstream and
235
+ * shouldn't reach batch processing, but the switch inside returns
236
+ * no-op verify for them if one slips through.
237
+ */
238
+ actionType: 'I' | 'U' | 'D' | 'A' | 'V' | 'C' | 'G' | 'S';
239
+ modelName: string;
240
+ modelId: string;
241
+ data: ModelData | null;
242
+ /**
243
+ * Server-stamped transaction id from the originating client's
244
+ * commit op. Threaded through to the result so the receive
245
+ * pipeline can recognize echoes of the local client's own
246
+ * mutations and skip the pool mutation in
247
+ * `SyncClient.applyDeltaBatchToPool`. Optional because system-
248
+ * emitted deltas (sync_group changes, schema-derived ops) don't
249
+ * have a client transaction.
250
+ */
251
+ transactionId?: string;
252
+ }>): Promise<{
253
+ results: Array<{
254
+ action: 'add' | 'update' | 'remove' | 'archive' | 'verify';
255
+ modelName: string;
256
+ modelId: string;
257
+ data?: ModelData | null;
258
+ transactionId?: string;
259
+ }>;
260
+ /**
261
+ * Highest syncId whose IDB store transaction actually committed in this
262
+ * batch. The runtime delta cursor (WS `lastSyncId`, server-side
263
+ * `lastAckedSyncId`) must only advance to THIS value — not the input
264
+ * batch's range max — or it diverges from the persisted view and the
265
+ * next catch-up request skips the un-persisted gap forever. Mirrors
266
+ * the metadata-cursor invariant at `updateWorkspaceMetadata` below.
267
+ * 0 when nothing persisted.
268
+ */
269
+ persistedSyncId: number;
270
+ }>;
271
+ /** Get raw data for hydration */
272
+ hydrateModels(modelName: string): Promise<ModelData[]>;
273
+ /** Put a single record to IndexedDB (for self-healing corrupted records) */
274
+ putRecord(modelName: string, id: string, data: Record<string, unknown>): Promise<void>;
275
+ /** Get data by index. `value` is an IDB key — string, number, Date,
276
+ * BufferSource, or array thereof. */
277
+ getDataByIndex(modelName: string, indexName: string, value: IDBValidKey): Promise<ModelData[]>;
278
+ /**
279
+ * Update workspace metadata
280
+ */
281
+ /**
282
+ * Get the last sync ID from workspace metadata
283
+ */
284
+ /** Read workspace metadata from IDB (returns null if db not open). */
285
+ getWorkspaceMetadata(): Promise<WorkspaceMetadata | null>;
286
+ getLastSyncId(): Promise<number>;
287
+ getVersionVector(): Promise<Record<string, number> | null>;
288
+ updateWorkspaceMetadata(metadata: Partial<WorkspaceMetadata>): Promise<void>;
289
+ /** Transaction persistence for offline/retry support.
290
+ * Returns either the IDB-backed ObjectStore or its in-memory twin
291
+ * (`InMemoryObjectStore`) — both expose the same async put/get/
292
+ * delete/getAll/getAllFromIndex surface, so callers don't need to
293
+ * branch on which one they got back. */
294
+ private get transactionStore();
295
+ saveTransaction(transaction: PersistedTransaction): Promise<void>;
296
+ removeTransaction(id: string): Promise<void>;
297
+ getPersistedTransactions(): Promise<PersistedTransaction[]>;
298
+ cleanupOldTransactions(maxAge: number): Promise<number>;
299
+ /**
300
+ * Store management
301
+ *
302
+ * `getStore(modelName, context?)` is defined near the top of this
303
+ * class — single accessor for both inMemory and IDB modes.
304
+ */
305
+ getAllStores(): Map<string, import("./stores/ObjectStore.js").ObjectStore> | Map<string, InMemoryObjectStore>;
306
+ /**
307
+ * Model persistence tracking
308
+ */
309
+ setModelPersisted(modelName: string, persisted: boolean): Promise<void>;
310
+ isModelPersisted(modelName: string): Promise<boolean>;
311
+ /**
312
+ * Statistics
313
+ */
314
+ getStats(): Promise<{
315
+ database: DatabaseInfo | null;
316
+ stores: {
317
+ totalStores: number;
318
+ storeTypes: {
319
+ full: number;
320
+ partial: number;
321
+ };
322
+ readiness: {
323
+ ready: number;
324
+ notReady: number;
325
+ };
326
+ totalRecords: number;
327
+ storeDetails: Array<{
328
+ modelName: string;
329
+ storeName: string;
330
+ strategy: LoadStrategy;
331
+ ready: boolean;
332
+ count: number;
333
+ }>;
334
+ };
335
+ metadata: WorkspaceMetadata | null;
336
+ }>;
337
+ /**
338
+ * Lifecycle
339
+ */
340
+ isOpen(): boolean;
341
+ close(): Promise<void>;
342
+ clear(): Promise<void>;
343
+ }
344
+ export {};