@tearleads/client-sdk 0.1.35 → 0.1.37

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/client/Tearleads.d.ts +4 -3
  2. package/client/Tearleads.js +4 -3
  3. package/client/Tearleads.js.map +1 -1
  4. package/internal/api-client/ApiClient.d.ts +3 -0
  5. package/internal/api-client/ApiClient.js +10 -7
  6. package/internal/api-client/ApiClient.js.map +1 -1
  7. package/internal/api-client/webSocketTickets.js +45 -0
  8. package/internal/api-client/webSocketTickets.js.map +1 -0
  9. package/internal/validators/operation/auth.d.ts +20 -0
  10. package/internal/validators/realtime/index.js +2 -2
  11. package/internal/validators/realtime/index.js.map +1 -1
  12. package/internal/validators/realtime/wsServerFrames.js +3 -8
  13. package/internal/validators/realtime/wsServerFrames.js.map +1 -1
  14. package/internal/validators/realtime/wsShared.js +6 -0
  15. package/internal/validators/realtime/wsShared.js.map +1 -1
  16. package/internal/validators/response/auth/verify.d.ts +8 -0
  17. package/internal/validators/response/auth/verify.js +3 -0
  18. package/internal/validators/response/auth/verify.js.map +1 -1
  19. package/package.json +1 -1
  20. package/stores/documents/documentStore/deferredInitialUpdate.js +9 -1
  21. package/stores/documents/documentStore/deferredInitialUpdate.js.map +1 -1
  22. package/stores/documents/documentStore/initialization.js +4 -0
  23. package/stores/documents/documentStore/initialization.js.map +1 -1
  24. package/stores/documents/documentStore.js +3 -3
  25. package/stores/documents/documentStore.js.map +1 -1
  26. package/sync/reconciliation/service.js +22 -12
  27. package/sync/reconciliation/service.js.map +1 -1
  28. package/sync/reconciliation/serviceTypes.d.ts +10 -1
  29. package/sync/reconciliation/serviceTypes.js.map +1 -1
  30. package/workflows/runtimeInput.d.ts +4 -3
  31. package/workflows/runtimeInput.js.map +1 -1
@@ -124,6 +124,7 @@ export declare const verifyOperation: Omit<{
124
124
  rootContainerId?: undefined;
125
125
  token?: undefined;
126
126
  userId?: undefined;
127
+ wsTicket?: undefined;
127
128
  }, {
128
129
  authenticated: false;
129
130
  error?: string | undefined;
@@ -132,6 +133,7 @@ export declare const verifyOperation: Omit<{
132
133
  rootContainerId?: undefined;
133
134
  token?: undefined;
134
135
  userId?: undefined;
136
+ wsTicket?: undefined;
135
137
  }, z.core.$ZodTypeInternals<{
136
138
  authenticated: false;
137
139
  error?: string | undefined;
@@ -140,6 +142,7 @@ export declare const verifyOperation: Omit<{
140
142
  rootContainerId?: undefined;
141
143
  token?: undefined;
142
144
  userId?: undefined;
145
+ wsTicket?: undefined;
143
146
  }, {
144
147
  authenticated: false;
145
148
  error?: string | undefined;
@@ -148,6 +151,7 @@ export declare const verifyOperation: Omit<{
148
151
  rootContainerId?: undefined;
149
152
  token?: undefined;
150
153
  userId?: undefined;
154
+ wsTicket?: undefined;
151
155
  }>>;
152
156
  readonly 404: z.ZodType<{
153
157
  authenticated: false;
@@ -157,6 +161,7 @@ export declare const verifyOperation: Omit<{
157
161
  rootContainerId?: undefined;
158
162
  token?: undefined;
159
163
  userId?: undefined;
164
+ wsTicket?: undefined;
160
165
  }, {
161
166
  authenticated: false;
162
167
  error?: string | undefined;
@@ -165,6 +170,7 @@ export declare const verifyOperation: Omit<{
165
170
  rootContainerId?: undefined;
166
171
  token?: undefined;
167
172
  userId?: undefined;
173
+ wsTicket?: undefined;
168
174
  }, z.core.$ZodTypeInternals<{
169
175
  authenticated: false;
170
176
  error?: string | undefined;
@@ -173,6 +179,7 @@ export declare const verifyOperation: Omit<{
173
179
  rootContainerId?: undefined;
174
180
  token?: undefined;
175
181
  userId?: undefined;
182
+ wsTicket?: undefined;
176
183
  }, {
177
184
  authenticated: false;
178
185
  error?: string | undefined;
@@ -181,6 +188,7 @@ export declare const verifyOperation: Omit<{
181
188
  rootContainerId?: undefined;
182
189
  token?: undefined;
183
190
  userId?: undefined;
191
+ wsTicket?: undefined;
184
192
  }>>;
185
193
  readonly 500: z.ZodType<{
186
194
  error: string;
@@ -205,6 +213,7 @@ export declare const verifyOperation: Omit<{
205
213
  rootContainerId: string | null;
206
214
  token: string;
207
215
  userId: string;
216
+ wsTicket: string;
208
217
  error?: undefined;
209
218
  }, {
210
219
  authenticated: true;
@@ -213,6 +222,7 @@ export declare const verifyOperation: Omit<{
213
222
  rootContainerId: string | null;
214
223
  token: string;
215
224
  userId: string;
225
+ wsTicket: string;
216
226
  error?: undefined;
217
227
  }, z.core.$ZodTypeInternals<{
218
228
  authenticated: true;
@@ -221,6 +231,7 @@ export declare const verifyOperation: Omit<{
221
231
  rootContainerId: string | null;
222
232
  token: string;
223
233
  userId: string;
234
+ wsTicket: string;
224
235
  error?: undefined;
225
236
  }, {
226
237
  authenticated: true;
@@ -229,6 +240,7 @@ export declare const verifyOperation: Omit<{
229
240
  rootContainerId: string | null;
230
241
  token: string;
231
242
  userId: string;
243
+ wsTicket: string;
232
244
  error?: undefined;
233
245
  }>>;
234
246
  };
@@ -251,6 +263,7 @@ export declare const verifyOperation: Omit<{
251
263
  rootContainerId?: undefined;
252
264
  token?: undefined;
253
265
  userId?: undefined;
266
+ wsTicket?: undefined;
254
267
  }, {
255
268
  authenticated: false;
256
269
  error?: string | undefined;
@@ -259,6 +272,7 @@ export declare const verifyOperation: Omit<{
259
272
  rootContainerId?: undefined;
260
273
  token?: undefined;
261
274
  userId?: undefined;
275
+ wsTicket?: undefined;
262
276
  }, z.core.$ZodTypeInternals<{
263
277
  authenticated: false;
264
278
  error?: string | undefined;
@@ -267,6 +281,7 @@ export declare const verifyOperation: Omit<{
267
281
  rootContainerId?: undefined;
268
282
  token?: undefined;
269
283
  userId?: undefined;
284
+ wsTicket?: undefined;
270
285
  }, {
271
286
  authenticated: false;
272
287
  error?: string | undefined;
@@ -275,6 +290,7 @@ export declare const verifyOperation: Omit<{
275
290
  rootContainerId?: undefined;
276
291
  token?: undefined;
277
292
  userId?: undefined;
293
+ wsTicket?: undefined;
278
294
  }>>;
279
295
  readonly 404: z.ZodType<{
280
296
  authenticated: false;
@@ -284,6 +300,7 @@ export declare const verifyOperation: Omit<{
284
300
  rootContainerId?: undefined;
285
301
  token?: undefined;
286
302
  userId?: undefined;
303
+ wsTicket?: undefined;
287
304
  }, {
288
305
  authenticated: false;
289
306
  error?: string | undefined;
@@ -292,6 +309,7 @@ export declare const verifyOperation: Omit<{
292
309
  rootContainerId?: undefined;
293
310
  token?: undefined;
294
311
  userId?: undefined;
312
+ wsTicket?: undefined;
295
313
  }, z.core.$ZodTypeInternals<{
296
314
  authenticated: false;
297
315
  error?: string | undefined;
@@ -300,6 +318,7 @@ export declare const verifyOperation: Omit<{
300
318
  rootContainerId?: undefined;
301
319
  token?: undefined;
302
320
  userId?: undefined;
321
+ wsTicket?: undefined;
303
322
  }, {
304
323
  authenticated: false;
305
324
  error?: string | undefined;
@@ -308,6 +327,7 @@ export declare const verifyOperation: Omit<{
308
327
  rootContainerId?: undefined;
309
328
  token?: undefined;
310
329
  userId?: undefined;
330
+ wsTicket?: undefined;
311
331
  }>>;
312
332
  readonly 500: z.ZodType<{
313
333
  error: string;
@@ -1,5 +1,5 @@
1
1
  export { MAX_WS_CLIENT_MESSAGE_BYTES, MAX_WS_INTEREST_CONTAINER_IDS, parseWsClientDeclaration, serializeWsClientDeclaration, WsClientDeclarationSchema, WsKnownContainersAddSchema, WsKnownContainersRemoveSchema, WsKnownContainersReplaceSchema, WsKnownOrganizationsReplaceSchema, } from "./wsClientDeclarations.js";
2
2
  export { WsContainerMutationCreatedHintSchema, WsDocumentMutationCreatedHintSchema, WsDocumentUpdateCreatedHintSchema, WsInvalidationHintSchema, WsSharedWithYouHintSchema, WsUserRegisteredHintSchema, } from "./wsInvalidationHints.js";
3
- export { parseWsServerMessage, serializeWsServerMessage, WsInterestStateFrameSchema, WsKnownContainersAckFrameSchema, WsKnownOrganizationsAckFrameSchema, WsOrganizationReadModelAccessRevokedFrameSchema, WsOrganizationReadModelChangedFrameSchema, WsResyncRequiredFrameSchema, WsServerControlFrameSchema, WsServerMessageSchema, } from "./wsServerFrames.js";
4
- export { MAX_WS_DECLARATION_ID_LENGTH } from "./wsShared.js";
3
+ export { parseWsServerMessage, serializeWsServerMessage, WsKnownContainersAckFrameSchema, WsKnownOrganizationsAckFrameSchema, WsOrganizationReadModelAccessRevokedFrameSchema, WsOrganizationReadModelChangedFrameSchema, WsResyncRequiredFrameSchema, WsServerControlFrameSchema, WsServerMessageSchema, } from "./wsServerFrames.js";
4
+ export { MAX_WS_DECLARATION_ID_LENGTH, WS_TICKET_TTL_SECONDS, } from "./wsShared.js";
5
5
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,2BAA2B,EAC3B,6BAA6B,EAC7B,wBAAwB,EACxB,4BAA4B,EAE5B,yBAAyB,EACzB,0BAA0B,EAC1B,6BAA6B,EAC7B,8BAA8B,EAC9B,iCAAiC,GAClC,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,oCAAoC,EACpC,mCAAmC,EACnC,iCAAiC,EAEjC,wBAAwB,EACxB,yBAAyB,EACzB,0BAA0B,GAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,oBAAoB,EACpB,wBAAwB,EACxB,0BAA0B,EAC1B,+BAA+B,EAC/B,kCAAkC,EAClC,+CAA+C,EAC/C,yCAAyC,EACzC,2BAA2B,EAE3B,0BAA0B,EAE1B,qBAAqB,GACtB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,4BAA4B,EAAE,MAAM,YAAY,CAAC","sourcesContent":["export {\n MAX_WS_CLIENT_MESSAGE_BYTES,\n MAX_WS_INTEREST_CONTAINER_IDS,\n parseWsClientDeclaration,\n serializeWsClientDeclaration,\n type WsClientDeclaration,\n WsClientDeclarationSchema,\n WsKnownContainersAddSchema,\n WsKnownContainersRemoveSchema,\n WsKnownContainersReplaceSchema,\n WsKnownOrganizationsReplaceSchema,\n} from \"./wsClientDeclarations\";\nexport {\n WsContainerMutationCreatedHintSchema,\n WsDocumentMutationCreatedHintSchema,\n WsDocumentUpdateCreatedHintSchema,\n type WsInvalidationHint,\n WsInvalidationHintSchema,\n WsSharedWithYouHintSchema,\n WsUserRegisteredHintSchema,\n} from \"./wsInvalidationHints\";\nexport {\n parseWsServerMessage,\n serializeWsServerMessage,\n WsInterestStateFrameSchema,\n WsKnownContainersAckFrameSchema,\n WsKnownOrganizationsAckFrameSchema,\n WsOrganizationReadModelAccessRevokedFrameSchema,\n WsOrganizationReadModelChangedFrameSchema,\n WsResyncRequiredFrameSchema,\n type WsServerControlFrame,\n WsServerControlFrameSchema,\n type WsServerMessage,\n WsServerMessageSchema,\n} from \"./wsServerFrames\";\nexport { MAX_WS_DECLARATION_ID_LENGTH } from \"./wsShared\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,2BAA2B,EAC3B,6BAA6B,EAC7B,wBAAwB,EACxB,4BAA4B,EAE5B,yBAAyB,EACzB,0BAA0B,EAC1B,6BAA6B,EAC7B,8BAA8B,EAC9B,iCAAiC,GAClC,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,oCAAoC,EACpC,mCAAmC,EACnC,iCAAiC,EAEjC,wBAAwB,EACxB,yBAAyB,EACzB,0BAA0B,GAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,oBAAoB,EACpB,wBAAwB,EACxB,+BAA+B,EAC/B,kCAAkC,EAClC,+CAA+C,EAC/C,yCAAyC,EACzC,2BAA2B,EAE3B,0BAA0B,EAE1B,qBAAqB,GACtB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,4BAA4B,EAC5B,qBAAqB,GACtB,MAAM,YAAY,CAAC","sourcesContent":["export {\n MAX_WS_CLIENT_MESSAGE_BYTES,\n MAX_WS_INTEREST_CONTAINER_IDS,\n parseWsClientDeclaration,\n serializeWsClientDeclaration,\n type WsClientDeclaration,\n WsClientDeclarationSchema,\n WsKnownContainersAddSchema,\n WsKnownContainersRemoveSchema,\n WsKnownContainersReplaceSchema,\n WsKnownOrganizationsReplaceSchema,\n} from \"./wsClientDeclarations\";\nexport {\n WsContainerMutationCreatedHintSchema,\n WsDocumentMutationCreatedHintSchema,\n WsDocumentUpdateCreatedHintSchema,\n type WsInvalidationHint,\n WsInvalidationHintSchema,\n WsSharedWithYouHintSchema,\n WsUserRegisteredHintSchema,\n} from \"./wsInvalidationHints\";\nexport {\n parseWsServerMessage,\n serializeWsServerMessage,\n WsKnownContainersAckFrameSchema,\n WsKnownOrganizationsAckFrameSchema,\n WsOrganizationReadModelAccessRevokedFrameSchema,\n WsOrganizationReadModelChangedFrameSchema,\n WsResyncRequiredFrameSchema,\n type WsServerControlFrame,\n WsServerControlFrameSchema,\n type WsServerMessage,\n WsServerMessageSchema,\n} from \"./wsServerFrames\";\nexport {\n MAX_WS_DECLARATION_ID_LENGTH,\n WS_TICKET_TTL_SECONDS,\n} from \"./wsShared\";\n"]}
@@ -8,13 +8,9 @@ import { parseWsJson, wsDeclarationIdSchema } from "./wsShared.js";
8
8
  * routed server events. Together with the hints they form the complete set of
9
9
  * frames a client may receive; anything else fails closed on both sides.
10
10
  */
11
- // The reconnect baseline frame: the container ids the server already holds for
12
- // this session. The matching declaration acknowledgement — not this frame — is
13
- // the client's ordering barrier for closing the lossy reconnect interval.
14
- export const WsInterestStateFrameSchema = z.object({
15
- type: z.literal("interest_state"),
16
- containerIds: z.array(z.string().min(1)),
17
- });
11
+ // A socket opens with no container interest. The acknowledgement of its first
12
+ // authoritative declaration is the client's ordering barrier for closing the
13
+ // lossy reconnect interval.
18
14
  export const WsKnownContainersAckFrameSchema = z.object({
19
15
  type: z.literal("known_containers_ack"),
20
16
  containerIds: z.array(z.string().min(1)),
@@ -42,7 +38,6 @@ export const WsOrganizationReadModelAccessRevokedFrameSchema = z.object({
42
38
  organizationId: uuidV4StringSchema,
43
39
  });
44
40
  export const WsServerControlFrameSchema = z.discriminatedUnion("type", [
45
- WsInterestStateFrameSchema,
46
41
  WsKnownContainersAckFrameSchema,
47
42
  WsKnownOrganizationsAckFrameSchema,
48
43
  WsResyncRequiredFrameSchema,
@@ -1 +1 @@
1
- {"version":3,"file":"wsServerFrames.js","sourceRoot":"","sources":["wsServerFrames.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAEL,wBAAwB,GACzB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAEhE;;;;;GAKG;AAEH,+EAA+E;AAC/E,+EAA+E;AAC/E,0EAA0E;AAC1E,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAC,MAAM,CAAC;IACjD,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC;IACjC,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CACzC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAAC,CAAC,MAAM,CAAC;IACtD,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,sBAAsB,CAAC;IACvC,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACxC,aAAa,EAAE,qBAAqB;CACrC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,kCAAkC,GAAG,CAAC,CAAC,MAAM,CAAC;IACzD,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,yBAAyB,CAAC;IAC1C,aAAa,EAAE,qBAAqB;IACpC,cAAc,EAAE,kBAAkB,CAAC,QAAQ,EAAE;IAC7C,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE;CACxB,CAAC,CAAC;AAEH,+EAA+E;AAC/E,yCAAyC;AACzC,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,CAAC,MAAM,CAAC;IAClD,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC;IAClC,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;CAChD,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,yCAAyC,GAAG,CAAC,CAAC,MAAM,CAAC;IAChE,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,iCAAiC,CAAC;IAClD,cAAc,EAAE,kBAAkB;IAClC,qBAAqB,EAAE,CAAC,CAAC,OAAO,EAAE;CACnC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,+CAA+C,GAAG,CAAC,CAAC,MAAM,CAAC;IACtE,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,wCAAwC,CAAC;IACzD,cAAc,EAAE,kBAAkB;CACnC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAC,kBAAkB,CAAC,MAAM,EAAE;IACrE,0BAA0B;IAC1B,+BAA+B;IAC/B,kCAAkC;IAClC,2BAA2B;IAC3B,yCAAyC;IACzC,+CAA+C;CAChD,CAAC,CAAC;AAIH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,kBAAkB,CAAC,MAAM,EAAE;IAChE,GAAG,0BAA0B,CAAC,OAAO;IACrC,GAAG,wBAAwB,CAAC,OAAO;CACpC,CAAC,CAAC;AAIH,gFAAgF;AAChF,MAAM,UAAU,wBAAwB,CAAC,OAAwB;IAC/D,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;AACjC,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,oBAAoB,CAClC,UAAkB;IAElB,OAAO,WAAW,CAAC,qBAAqB,EAAE,UAAU,CAAC,CAAC;AACxD,CAAC","sourcesContent":["import { z } from \"zod\";\nimport { uuidV4StringSchema } from \"../schema\";\nimport {\n type WsInvalidationHint,\n WsInvalidationHintSchema,\n} from \"./wsInvalidationHints\";\nimport { parseWsJson, wsDeclarationIdSchema } from \"./wsShared\";\n\n/**\n * Server→client websocket control frames: connection/interest lifecycle and\n * resync signals, as opposed to the invalidation hints that fan out interest-\n * routed server events. Together with the hints they form the complete set of\n * frames a client may receive; anything else fails closed on both sides.\n */\n\n// The reconnect baseline frame: the container ids the server already holds for\n// this session. The matching declaration acknowledgement — not this frame — is\n// the client's ordering barrier for closing the lossy reconnect interval.\nexport const WsInterestStateFrameSchema = z.object({\n type: z.literal(\"interest_state\"),\n containerIds: z.array(z.string().min(1)),\n});\n\nexport const WsKnownContainersAckFrameSchema = z.object({\n type: z.literal(\"known_containers_ack\"),\n containerIds: z.array(z.string().min(1)),\n declarationId: wsDeclarationIdSchema,\n});\n\nexport const WsKnownOrganizationsAckFrameSchema = z.object({\n type: z.literal(\"known_organizations_ack\"),\n declarationId: wsDeclarationIdSchema,\n organizationId: uuidV4StringSchema.nullable(),\n authorized: z.boolean(),\n});\n\n// A container's access changed; the client must reconcile it over HTTP and, if\n// still authorized, re-declare interest.\nexport const WsResyncRequiredFrameSchema = z.object({\n type: z.literal(\"resync_required\"),\n containerIds: z.array(z.string().min(1)).min(1),\n});\n\nexport const WsOrganizationReadModelChangedFrameSchema = z.object({\n type: z.literal(\"organization_read_model_changed\"),\n organizationId: uuidV4StringSchema,\n originatedFromSession: z.boolean(),\n});\n\nexport const WsOrganizationReadModelAccessRevokedFrameSchema = z.object({\n type: z.literal(\"organization_read_model_access_revoked\"),\n organizationId: uuidV4StringSchema,\n});\n\nexport const WsServerControlFrameSchema = z.discriminatedUnion(\"type\", [\n WsInterestStateFrameSchema,\n WsKnownContainersAckFrameSchema,\n WsKnownOrganizationsAckFrameSchema,\n WsResyncRequiredFrameSchema,\n WsOrganizationReadModelChangedFrameSchema,\n WsOrganizationReadModelAccessRevokedFrameSchema,\n]);\n\nexport type WsServerControlFrame = z.infer<typeof WsServerControlFrameSchema>;\n\nexport const WsServerMessageSchema = z.discriminatedUnion(\"type\", [\n ...WsServerControlFrameSchema.options,\n ...WsInvalidationHintSchema.options,\n]);\n\nexport type WsServerMessage = WsServerControlFrame | WsInvalidationHint;\n\n/** The single typed egress: the server cannot serialize an undeclared frame. */\nexport function serializeWsServerMessage(message: WsServerMessage): string {\n return JSON.stringify(message);\n}\n\n/** Malformed and unknown-tag server frames fail closed to null. */\nexport function parseWsServerMessage(\n rawMessage: string,\n): WsServerMessage | null {\n return parseWsJson(WsServerMessageSchema, rawMessage);\n}\n"]}
1
+ {"version":3,"file":"wsServerFrames.js","sourceRoot":"","sources":["wsServerFrames.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAEL,wBAAwB,GACzB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAEhE;;;;;GAKG;AAEH,8EAA8E;AAC9E,6EAA6E;AAC7E,4BAA4B;AAC5B,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAAC,CAAC,MAAM,CAAC;IACtD,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,sBAAsB,CAAC;IACvC,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACxC,aAAa,EAAE,qBAAqB;CACrC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,kCAAkC,GAAG,CAAC,CAAC,MAAM,CAAC;IACzD,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,yBAAyB,CAAC;IAC1C,aAAa,EAAE,qBAAqB;IACpC,cAAc,EAAE,kBAAkB,CAAC,QAAQ,EAAE;IAC7C,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE;CACxB,CAAC,CAAC;AAEH,+EAA+E;AAC/E,yCAAyC;AACzC,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,CAAC,MAAM,CAAC;IAClD,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC;IAClC,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;CAChD,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,yCAAyC,GAAG,CAAC,CAAC,MAAM,CAAC;IAChE,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,iCAAiC,CAAC;IAClD,cAAc,EAAE,kBAAkB;IAClC,qBAAqB,EAAE,CAAC,CAAC,OAAO,EAAE;CACnC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,+CAA+C,GAAG,CAAC,CAAC,MAAM,CAAC;IACtE,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,wCAAwC,CAAC;IACzD,cAAc,EAAE,kBAAkB;CACnC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAC,kBAAkB,CAAC,MAAM,EAAE;IACrE,+BAA+B;IAC/B,kCAAkC;IAClC,2BAA2B;IAC3B,yCAAyC;IACzC,+CAA+C;CAChD,CAAC,CAAC;AAIH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,kBAAkB,CAAC,MAAM,EAAE;IAChE,GAAG,0BAA0B,CAAC,OAAO;IACrC,GAAG,wBAAwB,CAAC,OAAO;CACpC,CAAC,CAAC;AAIH,gFAAgF;AAChF,MAAM,UAAU,wBAAwB,CAAC,OAAwB;IAC/D,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;AACjC,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,oBAAoB,CAClC,UAAkB;IAElB,OAAO,WAAW,CAAC,qBAAqB,EAAE,UAAU,CAAC,CAAC;AACxD,CAAC","sourcesContent":["import { z } from \"zod\";\nimport { uuidV4StringSchema } from \"../schema\";\nimport {\n type WsInvalidationHint,\n WsInvalidationHintSchema,\n} from \"./wsInvalidationHints\";\nimport { parseWsJson, wsDeclarationIdSchema } from \"./wsShared\";\n\n/**\n * Server→client websocket control frames: connection/interest lifecycle and\n * resync signals, as opposed to the invalidation hints that fan out interest-\n * routed server events. Together with the hints they form the complete set of\n * frames a client may receive; anything else fails closed on both sides.\n */\n\n// A socket opens with no container interest. The acknowledgement of its first\n// authoritative declaration is the client's ordering barrier for closing the\n// lossy reconnect interval.\nexport const WsKnownContainersAckFrameSchema = z.object({\n type: z.literal(\"known_containers_ack\"),\n containerIds: z.array(z.string().min(1)),\n declarationId: wsDeclarationIdSchema,\n});\n\nexport const WsKnownOrganizationsAckFrameSchema = z.object({\n type: z.literal(\"known_organizations_ack\"),\n declarationId: wsDeclarationIdSchema,\n organizationId: uuidV4StringSchema.nullable(),\n authorized: z.boolean(),\n});\n\n// A container's access changed; the client must reconcile it over HTTP and, if\n// still authorized, re-declare interest.\nexport const WsResyncRequiredFrameSchema = z.object({\n type: z.literal(\"resync_required\"),\n containerIds: z.array(z.string().min(1)).min(1),\n});\n\nexport const WsOrganizationReadModelChangedFrameSchema = z.object({\n type: z.literal(\"organization_read_model_changed\"),\n organizationId: uuidV4StringSchema,\n originatedFromSession: z.boolean(),\n});\n\nexport const WsOrganizationReadModelAccessRevokedFrameSchema = z.object({\n type: z.literal(\"organization_read_model_access_revoked\"),\n organizationId: uuidV4StringSchema,\n});\n\nexport const WsServerControlFrameSchema = z.discriminatedUnion(\"type\", [\n WsKnownContainersAckFrameSchema,\n WsKnownOrganizationsAckFrameSchema,\n WsResyncRequiredFrameSchema,\n WsOrganizationReadModelChangedFrameSchema,\n WsOrganizationReadModelAccessRevokedFrameSchema,\n]);\n\nexport type WsServerControlFrame = z.infer<typeof WsServerControlFrameSchema>;\n\nexport const WsServerMessageSchema = z.discriminatedUnion(\"type\", [\n ...WsServerControlFrameSchema.options,\n ...WsInvalidationHintSchema.options,\n]);\n\nexport type WsServerMessage = WsServerControlFrame | WsInvalidationHint;\n\n/** The single typed egress: the server cannot serialize an undeclared frame. */\nexport function serializeWsServerMessage(message: WsServerMessage): string {\n return JSON.stringify(message);\n}\n\n/** Malformed and unknown-tag server frames fail closed to null. */\nexport function parseWsServerMessage(\n rawMessage: string,\n): WsServerMessage | null {\n return parseWsJson(WsServerMessageSchema, rawMessage);\n}\n"]}
@@ -1,5 +1,11 @@
1
1
  import { z } from "zod";
2
2
  export const MAX_WS_DECLARATION_ID_LENGTH = 128;
3
+ /**
4
+ * Lifetime of a single-use websocket upgrade ticket. `POST /auth/verify`
5
+ * returns one for the first connect after login; later connects mint their own
6
+ * through `POST /auth/ws-ticket`.
7
+ */
8
+ export const WS_TICKET_TTL_SECONDS = 60;
3
9
  export const wsDeclarationIdSchema = z
4
10
  .string()
5
11
  .min(1)
@@ -1 +1 @@
1
- {"version":3,"file":"wsShared.js","sourceRoot":"","sources":["wsShared.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,4BAA4B,GAAG,GAAG,CAAC;AAEhD,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC;KACnC,MAAM,EAAE;KACR,GAAG,CAAC,CAAC,CAAC;KACN,GAAG,CAAC,4BAA4B,CAAC,CAAC;AAErC,MAAM,UAAU,WAAW,CACzB,MAAc,EACd,UAAkB;IAElB,IAAI,KAAc,CAAC;IACnB,IAAI,CAAC;QACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACvC,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7C,CAAC","sourcesContent":["import { z } from \"zod\";\n\nexport const MAX_WS_DECLARATION_ID_LENGTH = 128;\n\nexport const wsDeclarationIdSchema = z\n .string()\n .min(1)\n .max(MAX_WS_DECLARATION_ID_LENGTH);\n\nexport function parseWsJson<Schema extends z.ZodType>(\n schema: Schema,\n rawMessage: string,\n): z.output<Schema> | null {\n let value: unknown;\n try {\n value = JSON.parse(rawMessage);\n } catch {\n return null;\n }\n const parsed = schema.safeParse(value);\n return parsed.success ? parsed.data : null;\n}\n"]}
1
+ {"version":3,"file":"wsShared.js","sourceRoot":"","sources":["wsShared.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,4BAA4B,GAAG,GAAG,CAAC;AAEhD;;;;GAIG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,EAAE,CAAC;AAExC,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC;KACnC,MAAM,EAAE;KACR,GAAG,CAAC,CAAC,CAAC;KACN,GAAG,CAAC,4BAA4B,CAAC,CAAC;AAErC,MAAM,UAAU,WAAW,CACzB,MAAc,EACd,UAAkB;IAElB,IAAI,KAAc,CAAC;IACnB,IAAI,CAAC;QACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACvC,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7C,CAAC","sourcesContent":["import { z } from \"zod\";\n\nexport const MAX_WS_DECLARATION_ID_LENGTH = 128;\n\n/**\n * Lifetime of a single-use websocket upgrade ticket. `POST /auth/verify`\n * returns one for the first connect after login; later connects mint their own\n * through `POST /auth/ws-ticket`.\n */\nexport const WS_TICKET_TTL_SECONDS = 60;\n\nexport const wsDeclarationIdSchema = z\n .string()\n .min(1)\n .max(MAX_WS_DECLARATION_ID_LENGTH);\n\nexport function parseWsJson<Schema extends z.ZodType>(\n schema: Schema,\n rawMessage: string,\n): z.output<Schema> | null {\n let value: unknown;\n try {\n value = JSON.parse(rawMessage);\n } catch {\n return null;\n }\n const parsed = schema.safeParse(value);\n return parsed.success ? parsed.data : null;\n}\n"]}
@@ -6,6 +6,7 @@ export declare const VerifySuccessResponseSchema: z.ZodType<{
6
6
  rootContainerId: string | null;
7
7
  token: string;
8
8
  userId: string;
9
+ wsTicket: string;
9
10
  error?: undefined;
10
11
  }, {
11
12
  authenticated: true;
@@ -14,6 +15,7 @@ export declare const VerifySuccessResponseSchema: z.ZodType<{
14
15
  rootContainerId: string | null;
15
16
  token: string;
16
17
  userId: string;
18
+ wsTicket: string;
17
19
  error?: undefined;
18
20
  }, z.core.$ZodTypeInternals<{
19
21
  authenticated: true;
@@ -22,6 +24,7 @@ export declare const VerifySuccessResponseSchema: z.ZodType<{
22
24
  rootContainerId: string | null;
23
25
  token: string;
24
26
  userId: string;
27
+ wsTicket: string;
25
28
  error?: undefined;
26
29
  }, {
27
30
  authenticated: true;
@@ -30,6 +33,7 @@ export declare const VerifySuccessResponseSchema: z.ZodType<{
30
33
  rootContainerId: string | null;
31
34
  token: string;
32
35
  userId: string;
36
+ wsTicket: string;
33
37
  error?: undefined;
34
38
  }>>;
35
39
  export declare const VerifyFailureResponseSchema: z.ZodType<{
@@ -40,6 +44,7 @@ export declare const VerifyFailureResponseSchema: z.ZodType<{
40
44
  rootContainerId?: undefined;
41
45
  token?: undefined;
42
46
  userId?: undefined;
47
+ wsTicket?: undefined;
43
48
  }, {
44
49
  authenticated: false;
45
50
  error?: string | undefined;
@@ -48,6 +53,7 @@ export declare const VerifyFailureResponseSchema: z.ZodType<{
48
53
  rootContainerId?: undefined;
49
54
  token?: undefined;
50
55
  userId?: undefined;
56
+ wsTicket?: undefined;
51
57
  }, z.core.$ZodTypeInternals<{
52
58
  authenticated: false;
53
59
  error?: string | undefined;
@@ -56,6 +62,7 @@ export declare const VerifyFailureResponseSchema: z.ZodType<{
56
62
  rootContainerId?: undefined;
57
63
  token?: undefined;
58
64
  userId?: undefined;
65
+ wsTicket?: undefined;
59
66
  }, {
60
67
  authenticated: false;
61
68
  error?: string | undefined;
@@ -64,6 +71,7 @@ export declare const VerifyFailureResponseSchema: z.ZodType<{
64
71
  rootContainerId?: undefined;
65
72
  token?: undefined;
66
73
  userId?: undefined;
74
+ wsTicket?: undefined;
67
75
  }>>;
68
76
  export type VerifySuccessResponse = z.infer<typeof VerifySuccessResponseSchema>;
69
77
  export type VerifyFailureResponse = z.infer<typeof VerifyFailureResponseSchema>;
@@ -9,6 +9,8 @@ export const VerifySuccessResponseSchema = loosePlainObject({
9
9
  rootContainerId: nonEmptyStringSchema.nullable(),
10
10
  token: nonEmptyStringSchema,
11
11
  userId: nonEmptyStringSchema,
12
+ /** Single-use upgrade ticket for this session's first websocket connect. */
13
+ wsTicket: nonEmptyStringSchema,
12
14
  });
13
15
  export const VerifyFailureResponseSchema = loosePlainObject({
14
16
  authenticated: z.literal(false),
@@ -18,6 +20,7 @@ export const VerifyFailureResponseSchema = loosePlainObject({
18
20
  rootContainerId: z.never().optional(),
19
21
  token: z.never().optional(),
20
22
  userId: z.never().optional(),
23
+ wsTicket: z.never().optional(),
21
24
  });
22
25
  export function isVerifyResponse(value) {
23
26
  return (VerifySuccessResponseSchema.safeParse(value).success ||
@@ -1 +1 @@
1
- {"version":3,"file":"verify.js","sourceRoot":"","sources":["verify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEtE,MAAM,CAAC,MAAM,2BAA2B,GAAG,gBAAgB,CAAC;IAC1D,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;IAC9B,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE;IAC3B,4EAA4E;IAC5E,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE;IACnB,cAAc,EAAE,oBAAoB;IACpC,eAAe,EAAE,oBAAoB,CAAC,QAAQ,EAAE;IAChD,KAAK,EAAE,oBAAoB;IAC3B,MAAM,EAAE,oBAAoB;CAC7B,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,2BAA2B,GAAG,gBAAgB,CAAC;IAC1D,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;IAC/B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC5B,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE;IAC5B,cAAc,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE;IACpC,eAAe,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE;IACrC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE;IAC3B,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE;CAC7B,CAAC,CAAC;AAMH,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,OAAO,CACL,2BAA2B,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO;QACpD,2BAA2B,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CACrD,CAAC;AACJ,CAAC","sourcesContent":["import { z } from \"zod\";\nimport { loosePlainObject, nonEmptyStringSchema } from \"../../schema\";\n\nexport const VerifySuccessResponseSchema = loosePlainObject({\n authenticated: z.literal(true),\n error: z.never().optional(),\n /** Platform-operator flag; gates the root console, enforced server-side. */\n isRoot: z.boolean(),\n organizationId: nonEmptyStringSchema,\n rootContainerId: nonEmptyStringSchema.nullable(),\n token: nonEmptyStringSchema,\n userId: nonEmptyStringSchema,\n});\n\nexport const VerifyFailureResponseSchema = loosePlainObject({\n authenticated: z.literal(false),\n error: z.string().optional(),\n isRoot: z.never().optional(),\n organizationId: z.never().optional(),\n rootContainerId: z.never().optional(),\n token: z.never().optional(),\n userId: z.never().optional(),\n});\n\nexport type VerifySuccessResponse = z.infer<typeof VerifySuccessResponseSchema>;\nexport type VerifyFailureResponse = z.infer<typeof VerifyFailureResponseSchema>;\nexport type VerifyResponse = VerifySuccessResponse | VerifyFailureResponse;\n\nexport function isVerifyResponse(value: unknown): value is VerifyResponse {\n return (\n VerifySuccessResponseSchema.safeParse(value).success ||\n VerifyFailureResponseSchema.safeParse(value).success\n );\n}\n"]}
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["verify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEtE,MAAM,CAAC,MAAM,2BAA2B,GAAG,gBAAgB,CAAC;IAC1D,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;IAC9B,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE;IAC3B,4EAA4E;IAC5E,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE;IACnB,cAAc,EAAE,oBAAoB;IACpC,eAAe,EAAE,oBAAoB,CAAC,QAAQ,EAAE;IAChD,KAAK,EAAE,oBAAoB;IAC3B,MAAM,EAAE,oBAAoB;IAC5B,4EAA4E;IAC5E,QAAQ,EAAE,oBAAoB;CAC/B,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,2BAA2B,GAAG,gBAAgB,CAAC;IAC1D,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;IAC/B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC5B,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE;IAC5B,cAAc,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE;IACpC,eAAe,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE;IACrC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE;IAC3B,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE;IAC5B,QAAQ,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE;CAC/B,CAAC,CAAC;AAMH,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,OAAO,CACL,2BAA2B,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO;QACpD,2BAA2B,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CACrD,CAAC;AACJ,CAAC","sourcesContent":["import { z } from \"zod\";\nimport { loosePlainObject, nonEmptyStringSchema } from \"../../schema\";\n\nexport const VerifySuccessResponseSchema = loosePlainObject({\n authenticated: z.literal(true),\n error: z.never().optional(),\n /** Platform-operator flag; gates the root console, enforced server-side. */\n isRoot: z.boolean(),\n organizationId: nonEmptyStringSchema,\n rootContainerId: nonEmptyStringSchema.nullable(),\n token: nonEmptyStringSchema,\n userId: nonEmptyStringSchema,\n /** Single-use upgrade ticket for this session's first websocket connect. */\n wsTicket: nonEmptyStringSchema,\n});\n\nexport const VerifyFailureResponseSchema = loosePlainObject({\n authenticated: z.literal(false),\n error: z.string().optional(),\n isRoot: z.never().optional(),\n organizationId: z.never().optional(),\n rootContainerId: z.never().optional(),\n token: z.never().optional(),\n userId: z.never().optional(),\n wsTicket: z.never().optional(),\n});\n\nexport type VerifySuccessResponse = z.infer<typeof VerifySuccessResponseSchema>;\nexport type VerifyFailureResponse = z.infer<typeof VerifyFailureResponseSchema>;\nexport type VerifyResponse = VerifySuccessResponse | VerifyFailureResponse;\n\nexport function isVerifyResponse(value: unknown): value is VerifyResponse {\n return (\n VerifySuccessResponseSchema.safeParse(value).success ||\n VerifyFailureResponseSchema.safeParse(value).success\n );\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tearleads/client-sdk",
3
- "version": "0.1.35",
3
+ "version": "0.1.37",
4
4
  "description": "React-free Tearleads client runtime: local SQLite persistence, keys, sync, encrypted blobs, and domain workflows.",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
@@ -20,6 +20,14 @@ import { captureDocumentStoreSyncGeneration, isDocumentStoreSyncGenerationCurren
20
20
  export async function settleDeferredInitialUpdate(state, writeGeneration) {
21
21
  if (!state.deferInitialUpdate)
22
22
  return;
23
+ // Before initialization finishes no attach has touched a live doc, and a
24
+ // reload here would install one behind initialization's back (or mark a
25
+ // not-yet-created document removed). Lift the hold; initialization then
26
+ // restores the empty marker and schedules the pass that ships the birth.
27
+ if (!state.initialized) {
28
+ state.deferInitialUpdate = false;
29
+ return;
30
+ }
23
31
  // A pass exports the live doc, so it must hold only durable content (see
24
32
  // restoreDurableLiveDocument) before the hold lifts. When that cannot be
25
33
  // shown, even after a transient failure, reinitialize from durable history
@@ -34,7 +42,7 @@ export async function settleDeferredInitialUpdate(state, writeGeneration) {
34
42
  ensureDocumentStoreInitialized(state, () => requestDocumentStoreSync(state));
35
43
  }
36
44
  else if (!durable) {
37
- // No live doc to leak (the store never became ready): just lift it.
45
+ // No live doc remains to leak (a concurrent removal): just lift it.
38
46
  state.deferInitialUpdate = false;
39
47
  }
40
48
  }
@@ -1 +1 @@
1
- {"version":3,"file":"deferredInitialUpdate.js","sourceRoot":"","sources":["deferredInitialUpdate.ts"],"names":[],"mappings":"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","sourcesContent":["import { encodeVersionVector, satisfiesVersionVector } from \"@tearleads/loro\";\nimport { createPendingUpdateFields } from \"../../../data/documents/documentSync\";\nimport { requestDocumentStoreSync } from \"../registry\";\nimport {\n type AttachmentWriteGeneration,\n captureAttachmentWriteGeneration,\n isAttachmentWriteGenerationCurrent,\n} from \"./attachmentWriteGeneration\";\nimport { reloadDocumentFromDurableHistory } from \"./durableDocumentReload\";\nimport { ensureDocumentStoreInitialized } from \"./initialization\";\nimport {\n advancePendingBaseVersion,\n pendingDeltaSinceBase,\n persistDocument,\n} from \"./persistence\";\nimport { type DocumentStoreState, resetDocumentStore } from \"./state\";\nimport {\n captureDocumentStoreSyncGeneration,\n isDocumentStoreSyncGenerationCurrent,\n} from \"./syncGeneration\";\n\n/**\n * Runs after the first attach on a store opened with `deferInitialUpdate`.\n * Creation committed the birth without a pending update, leaving the marker at\n * the empty version so that attach's delta would carry it, and scheduled sync\n * passes wait meanwhile (see `canRunScheduledSync`) so none ships the birth on\n * its own. When the attach did not land (staging failed or returned null, its\n * persist was refused, or the store could not attach), enqueue the deferred\n * tail now so the document still syncs, without its attachment. Either way,\n * lift the hold and request the pass it skipped.\n */\nexport async function settleDeferredInitialUpdate(\n state: DocumentStoreState,\n writeGeneration: AttachmentWriteGeneration | null,\n): Promise<void> {\n if (!state.deferInitialUpdate) return;\n // A pass exports the live doc, so it must hold only durable content (see\n // restoreDurableLiveDocument) before the hold lifts. When that cannot be\n // shown, even after a transient failure, reinitialize from durable history\n // rather than latch the hold: the reset lifts it and drops the live doc.\n let durable = false;\n try {\n durable = await restoreDurableLiveDocument(state);\n } finally {\n if (!durable && state.deferInitialUpdate && state.doc) {\n resetDocumentStore(state);\n ensureDocumentStoreInitialized(state, () =>\n requestDocumentStoreSync(state),\n );\n } else if (!durable) {\n // No live doc to leak (the store never became ready): just lift it.\n state.deferInitialUpdate = false;\n }\n }\n if (!durable) return;\n state.deferInitialUpdate = false;\n try {\n await enqueueDeferredTail(state, writeGeneration);\n } finally {\n requestDocumentStoreSync(state);\n }\n}\n\nfunction isLiveDocumentDurable(state: DocumentStoreState): boolean {\n return (\n state.doc !== null &&\n state.record !== null &&\n satisfiesVersionVector(\n state.record.snapshotEndVersion,\n encodeVersionVector(state.doc),\n )\n );\n}\n\n/**\n * A failed attach whose rollback reload could not run (its generation went\n * stale mid-stage) leaves the uncommitted slot in the live doc, and that slot\n * must never sync without its staged bytes. Reload durable history under a\n * fresh generation before trusting the live doc.\n */\nasync function restoreDurableLiveDocument(\n state: DocumentStoreState,\n): Promise<boolean> {\n if (isLiveDocumentDurable(state)) return true;\n const generation = captureDocumentStoreSyncGeneration(state, state.doc);\n if (generation) {\n await reloadDocumentFromDurableHistory({\n expectedGeneration: generation,\n preserveQueuedWritesWhenIdentityMatches: true,\n state,\n });\n }\n return isLiveDocumentDurable(state);\n}\n\nasync function enqueueDeferredTail(\n state: DocumentStoreState,\n writeGeneration: AttachmentWriteGeneration | null,\n): Promise<void> {\n // A reset or relink owns the replacement store; its deferred tail stays\n // durable and the next write or sync pass materializes it. With no attach\n // (nothing to attach, or the store was not writable) the live store owns it.\n const generation = writeGeneration ?? captureAttachmentWriteGeneration(state);\n if (!generation || !isAttachmentWriteGenerationCurrent(state, generation)) {\n return;\n }\n const currentDoc = state.doc;\n const baseVersion = state.pendingBaseVersion;\n if (!currentDoc || baseVersion === null) return;\n const documentVersion = encodeVersionVector(currentDoc);\n // Settled: the attach (or an earlier write) already enqueued the birth.\n if (satisfiesVersionVector(baseVersion, documentVersion)) return;\n const syncGeneration = captureDocumentStoreSyncGeneration(state, currentDoc);\n if (!syncGeneration) return;\n const pendingUpdate = createPendingUpdateFields(\n pendingDeltaSinceBase(state, currentDoc),\n );\n if (!pendingUpdate) return;\n const persisted = await persistDocument(\n state,\n currentDoc,\n { snapshotEndVersion: documentVersion },\n {\n pendingUpdate,\n preserveSnapshotStructuredFields: true,\n preserveSnapshotText: true,\n },\n syncGeneration,\n );\n if (\n !persisted ||\n !isDocumentStoreSyncGenerationCurrent(state, syncGeneration)\n ) {\n return;\n }\n advancePendingBaseVersion(state, currentDoc);\n}\n"]}
1
+ {"version":3,"file":"deferredInitialUpdate.js","sourceRoot":"","sources":["deferredInitialUpdate.ts"],"names":[],"mappings":"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","sourcesContent":["import { encodeVersionVector, satisfiesVersionVector } from \"@tearleads/loro\";\nimport { createPendingUpdateFields } from \"../../../data/documents/documentSync\";\nimport { requestDocumentStoreSync } from \"../registry\";\nimport {\n type AttachmentWriteGeneration,\n captureAttachmentWriteGeneration,\n isAttachmentWriteGenerationCurrent,\n} from \"./attachmentWriteGeneration\";\nimport { reloadDocumentFromDurableHistory } from \"./durableDocumentReload\";\nimport { ensureDocumentStoreInitialized } from \"./initialization\";\nimport {\n advancePendingBaseVersion,\n pendingDeltaSinceBase,\n persistDocument,\n} from \"./persistence\";\nimport { type DocumentStoreState, resetDocumentStore } from \"./state\";\nimport {\n captureDocumentStoreSyncGeneration,\n isDocumentStoreSyncGenerationCurrent,\n} from \"./syncGeneration\";\n\n/**\n * Runs after the first attach on a store opened with `deferInitialUpdate`.\n * Creation committed the birth without a pending update, leaving the marker at\n * the empty version so that attach's delta would carry it, and scheduled sync\n * passes wait meanwhile (see `canRunScheduledSync`) so none ships the birth on\n * its own. When the attach did not land (staging failed or returned null, its\n * persist was refused, or the store could not attach), enqueue the deferred\n * tail now so the document still syncs, without its attachment. Either way,\n * lift the hold and request the pass it skipped.\n */\nexport async function settleDeferredInitialUpdate(\n state: DocumentStoreState,\n writeGeneration: AttachmentWriteGeneration | null,\n): Promise<void> {\n if (!state.deferInitialUpdate) return;\n // Before initialization finishes no attach has touched a live doc, and a\n // reload here would install one behind initialization's back (or mark a\n // not-yet-created document removed). Lift the hold; initialization then\n // restores the empty marker and schedules the pass that ships the birth.\n if (!state.initialized) {\n state.deferInitialUpdate = false;\n return;\n }\n // A pass exports the live doc, so it must hold only durable content (see\n // restoreDurableLiveDocument) before the hold lifts. When that cannot be\n // shown, even after a transient failure, reinitialize from durable history\n // rather than latch the hold: the reset lifts it and drops the live doc.\n let durable = false;\n try {\n durable = await restoreDurableLiveDocument(state);\n } finally {\n if (!durable && state.deferInitialUpdate && state.doc) {\n resetDocumentStore(state);\n ensureDocumentStoreInitialized(state, () =>\n requestDocumentStoreSync(state),\n );\n } else if (!durable) {\n // No live doc remains to leak (a concurrent removal): just lift it.\n state.deferInitialUpdate = false;\n }\n }\n if (!durable) return;\n state.deferInitialUpdate = false;\n try {\n await enqueueDeferredTail(state, writeGeneration);\n } finally {\n requestDocumentStoreSync(state);\n }\n}\n\nfunction isLiveDocumentDurable(state: DocumentStoreState): boolean {\n return (\n state.doc !== null &&\n state.record !== null &&\n satisfiesVersionVector(\n state.record.snapshotEndVersion,\n encodeVersionVector(state.doc),\n )\n );\n}\n\n/**\n * A failed attach whose rollback reload could not run (its generation went\n * stale mid-stage) leaves the uncommitted slot in the live doc, and that slot\n * must never sync without its staged bytes. Reload durable history under a\n * fresh generation before trusting the live doc.\n */\nasync function restoreDurableLiveDocument(\n state: DocumentStoreState,\n): Promise<boolean> {\n if (isLiveDocumentDurable(state)) return true;\n const generation = captureDocumentStoreSyncGeneration(state, state.doc);\n if (generation) {\n await reloadDocumentFromDurableHistory({\n expectedGeneration: generation,\n preserveQueuedWritesWhenIdentityMatches: true,\n state,\n });\n }\n return isLiveDocumentDurable(state);\n}\n\nasync function enqueueDeferredTail(\n state: DocumentStoreState,\n writeGeneration: AttachmentWriteGeneration | null,\n): Promise<void> {\n // A reset or relink owns the replacement store; its deferred tail stays\n // durable and the next write or sync pass materializes it. With no attach\n // (nothing to attach, or the store was not writable) the live store owns it.\n const generation = writeGeneration ?? captureAttachmentWriteGeneration(state);\n if (!generation || !isAttachmentWriteGenerationCurrent(state, generation)) {\n return;\n }\n const currentDoc = state.doc;\n const baseVersion = state.pendingBaseVersion;\n if (!currentDoc || baseVersion === null) return;\n const documentVersion = encodeVersionVector(currentDoc);\n // Settled: the attach (or an earlier write) already enqueued the birth.\n if (satisfiesVersionVector(baseVersion, documentVersion)) return;\n const syncGeneration = captureDocumentStoreSyncGeneration(state, currentDoc);\n if (!syncGeneration) return;\n const pendingUpdate = createPendingUpdateFields(\n pendingDeltaSinceBase(state, currentDoc),\n );\n if (!pendingUpdate) return;\n const persisted = await persistDocument(\n state,\n currentDoc,\n { snapshotEndVersion: documentVersion },\n {\n pendingUpdate,\n preserveSnapshotStructuredFields: true,\n preserveSnapshotText: true,\n },\n syncGeneration,\n );\n if (\n !persisted ||\n !isDocumentStoreSyncGenerationCurrent(state, syncGeneration)\n ) {\n return;\n }\n advancePendingBaseVersion(state, currentDoc);\n}\n"]}
@@ -220,6 +220,10 @@ export function ensureDocumentStoreInitialized(state, scheduleSync) {
220
220
  }
221
221
  const initializePromise = initializeDocumentStore(state, scheduleSync).catch((error) => {
222
222
  state.initializePromise = null;
223
+ // A caller that deferred the birth for its attach may give up once
224
+ // opening fails; never leave its durable birth holding sync. No attach
225
+ // has reached a live doc yet, so lifting the hold ships nothing unsafe.
226
+ state.deferInitialUpdate = false;
223
227
  if (isDatabaseUnavailableError(error)) {
224
228
  return;
225
229
  }
@@ -1 +1 @@
1
- {"version":3,"file":"initialization.js","sourceRoot":"","sources":["initialization.ts"],"names":[],"mappings":"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","sourcesContent":["import { bytesToBase64 } from \"@tearleads/encoding\";\nimport {\n emptyVersionVector,\n encodeVersionVector,\n exportAllUpdates,\n exportFullHistorySnapshot,\n mergeVersionVectors,\n} from \"@tearleads/loro\";\nimport {\n DEFAULT_DOCUMENT_ACCESS_EPOCH,\n DEFAULT_DOCUMENT_KIND,\n} from \"../../../data/documents/documentConstants\";\nimport {\n initializeStoredDocumentKind,\n readStoredDocumentState,\n} from \"../../../data/documents/documentKinds\";\nimport type { DocumentSummary } from \"../../../data/documents/documentSummary\";\nimport { createPendingUpdateFields } from \"../../../data/documents/documentSync\";\nimport {\n type DocumentRecord,\n isDatabaseUnavailableError,\n loadPersistedDocumentStoreState,\n} from \"../../../workflows/documents\";\nimport type { DocumentStoreRelinkInput } from \"../types\";\nimport { chainIdentityWrite } from \"./identityWriteChain\";\nimport {\n installPersistedAttachments,\n type LoadedDocumentStoreState,\n} from \"./initializationAttachments\";\nimport {\n type RestoredHistoryState,\n restoredRemoteTailCoverage,\n restorePersistedDocumentContent,\n} from \"./initializationHistory\";\nimport {\n healLocalAttachmentDetachState,\n recoverDroppedAttachmentSlots,\n} from \"./initializationRecovery\";\nimport type { DocumentRelinkCommitSideEffect } from \"./internalRelink\";\nimport { runDocumentOrphanMaintenance } from \"./orphanMaintenance\";\nimport {\n advancePendingBaseVersion,\n documentSummaryFromRecord,\n persistDocument,\n saveDocumentRecord,\n} from \"./persistence\";\nimport { logRevalidationScheduled } from \"./remoteRevalidationTelemetry\";\nimport {\n type DocumentState,\n type DocumentStoreState,\n setReadySnapshot,\n} from \"./state\";\nimport { createStoredDocument } from \"./storedDocument\";\nimport {\n allowDocumentStoreRemoteSync,\n captureDocumentStoreSyncGeneration,\n invalidateDocumentStoreRemoteSync,\n isDocumentStoreSyncGenerationCurrent,\n markDocumentStoreRemoteSyncPending,\n} from \"./syncGeneration\";\n\nasync function createInitialDocumentRecord(\n state: DocumentStoreState,\n nextDoc: DocumentState,\n): ReturnType<typeof saveDocumentRecord> {\n initializeStoredDocumentKind(\n nextDoc,\n state.initialDocumentKind,\n state.runtime.infra.documentProjectors,\n );\n if (state.initialText.length > 0) {\n nextDoc.getText(\"text\").update(state.initialText);\n }\n const initialDocumentState = readStoredDocumentState(\n nextDoc,\n state.runtime.infra.documentProjectors,\n );\n const hasInitialContent =\n state.initialText.length > 0 ||\n state.initialDocumentKind !== DEFAULT_DOCUMENT_KIND;\n const initialUpdate = hasInitialContent\n ? createPendingUpdateFields(exportAllUpdates(nextDoc))\n : null;\n // A deferred birth still commits its checkpoint, but leaves the marker at the\n // empty version with nothing queued: the promised attach exports every op\n // since that marker, so one update carries the birth and the attachment.\n const birthDurability = !initialUpdate\n ? {}\n : state.deferInitialUpdate\n ? { pendingBaseVersionOverride: emptyVersionVector() }\n : { pendingUpdate: initialUpdate };\n\n const created: DocumentRecord = {\n id: state.localId,\n containerId: state.runtime.state.containerId ?? null,\n documentId: state.initialDocumentId,\n documentKind: initialDocumentState.documentKind,\n text: initialDocumentState.text,\n title: initialDocumentState.title,\n snapshotEndVersion: encodeVersionVector(nextDoc),\n accessEpoch: DEFAULT_DOCUMENT_ACCESS_EPOCH,\n accessStateHash: null,\n effectiveAccessLevel: \"admin\",\n lastCommitLsn: null,\n contentKeyBundle: null,\n documentKekTargets: null,\n documentManifestBundle: null,\n };\n // The create-only persistence primitive commits the canonical row and birth\n // checkpoint together. A concurrent initializer either wins both or adopts\n // both, so it cannot replace another pane's history or keying state.\n const persisted = await saveDocumentRecord(\n state,\n nextDoc,\n {\n ...created,\n snapshotEndVersion: encodeVersionVector(nextDoc),\n },\n {\n historyCheckpoint: {\n coveredTailIds: [],\n endVersionVector: encodeVersionVector(nextDoc),\n pruneCoveredLocalState: false,\n snapshot: bytesToBase64(exportFullHistorySnapshot(nextDoc)),\n },\n ...birthDurability,\n },\n );\n return persisted;\n}\n\nfunction installPersistedDocumentRecord(\n state: DocumentStoreState,\n record: NonNullable<DocumentStoreState[\"record\"]>,\n): void {\n state.record = record;\n state.pullContinuation = record.pullContinuation ?? null;\n}\n\ninterface RestoredInitialDocumentState {\n activePersistedState: LoadedDocumentStoreState;\n activeRecord: NonNullable<DocumentStoreState[\"record\"]>;\n doc: DocumentState;\n history: RestoredHistoryState | null;\n}\n\nasync function restoreLoadedInitialDocument(input: {\n initializeGeneration: number;\n nextDoc: DocumentState;\n persistedState: LoadedDocumentStoreState;\n state: DocumentStoreState;\n}): Promise<RestoredInitialDocumentState | null> {\n const { initializeGeneration, persistedState, state } = input;\n const record = persistedState.document;\n if (!record) return null;\n const history = await restorePersistedDocumentContent(\n input.nextDoc,\n persistedState.historyRestoreState,\n );\n if (state.localWriteGeneration !== initializeGeneration) return null;\n installPersistedDocumentRecord(state, record);\n return {\n activePersistedState: persistedState,\n activeRecord: record,\n doc: input.nextDoc,\n history,\n };\n}\n\nasync function restoreOrCreateInitialDocument(input: {\n initializeGeneration: number;\n nextDoc: DocumentState;\n persistedState: LoadedDocumentStoreState;\n state: DocumentStoreState;\n}): Promise<RestoredInitialDocumentState | null> {\n const { initializeGeneration, persistedState, state } = input;\n if (persistedState.document) {\n return restoreLoadedInitialDocument(input);\n }\n\n const created = await createInitialDocumentRecord(state, input.nextDoc);\n if (!created || state.localWriteGeneration !== initializeGeneration) {\n return null;\n }\n const activePersistedState = await loadPersistedDocumentStoreState({\n execSql: state.runtime.infra.execSql,\n localId: state.localId,\n persistence: state.persistence,\n });\n if (state.localWriteGeneration !== initializeGeneration) {\n return null;\n }\n if (!activePersistedState.document) {\n throw new Error(\"Document creation completed without a durable record\");\n }\n const replacementDoc = await createStoredDocument(state);\n return restoreLoadedInitialDocument({\n initializeGeneration,\n nextDoc: replacementDoc,\n persistedState: activePersistedState,\n state,\n });\n}\n\nfunction restorePendingBaseVersion(input: {\n activeRecord: NonNullable<DocumentStoreState[\"record\"]>;\n doc: DocumentState;\n history: RestoredHistoryState | null;\n state: DocumentStoreState;\n}): void {\n const { activeRecord, doc, history, state } = input;\n const markerBase =\n activeRecord.pendingBaseVersion ??\n (activeRecord.snapshotEndVersion.length > 0\n ? activeRecord.snapshotEndVersion\n : null);\n if (markerBase === null) {\n advancePendingBaseVersion(state, doc);\n return;\n }\n\n const remoteCoverage = restoredRemoteTailCoverage(history);\n state.pendingBaseVersion =\n remoteCoverage.length > 0\n ? mergeVersionVectors([markerBase, ...remoteCoverage])\n : markerBase;\n}\n\nasync function initializeDocumentStore(\n state: DocumentStoreState,\n scheduleSync: () => void,\n) {\n if (state.runtime.infra.dbStatus !== \"ready\") {\n return;\n }\n\n // A store reset while this fire-and-forget initialization is loading (a\n // runtime swap, or a local-edits discard that re-seeds the persisted rows)\n // must win: assigning the state loaded BEFORE the reset would bring the\n // replaced record and doc back to life. Every reset bumps the local write\n // generation, so a stale capture here aborts before each assignment batch.\n const initializeGeneration = state.localWriteGeneration;\n\n const nextDoc = await createStoredDocument(state);\n const persistedState = await loadPersistedDocumentStoreState({\n execSql: state.runtime.infra.execSql,\n localId: state.localId,\n persistence: state.persistence,\n });\n if (state.localWriteGeneration !== initializeGeneration) {\n return;\n }\n const restored = await restoreOrCreateInitialDocument({\n initializeGeneration,\n nextDoc,\n persistedState,\n state,\n });\n if (!restored) {\n return;\n }\n const activePersistedState = restored.activePersistedState;\n installPersistedAttachments(state, activePersistedState);\n\n state.doc = restored.doc;\n // Restore the durable outgoing-delta marker. Re-seeding it to the restored\n // document's version would move it PAST any device-first `deferRemoteSync`\n // op (persisted into the durable history but deliberately left un-enqueued\n // and behind the marker), permanently dropping that op from sync across a\n // restart. When a marker was persisted, restore it so the next edit still\n // re-derives the deferred delta. Only seed for rows that never persisted\n // one, from the RECORD's persisted frontier rather than the restored\n // document: a crash between the tail append and the queue/marker writes can\n // resurrect ops the outgoing queue never durably received, and seeding from\n // the restored document would classify those as covered and orphan them\n // from sync forever.\n restorePendingBaseVersion({\n activeRecord: restored.activeRecord,\n doc: restored.doc,\n history: restored.history,\n state,\n });\n // Heal attachment slots lost to an interrupted attach write before marking\n // ready, so the recovered slots are in the snapshot the editor first renders\n // and are queued for sync. recoverDroppedAttachmentSlots advances the marker\n // again for whatever it re-derives. Both helpers gate every durable write\n // on this generation (validated inside the writes' serialized mutations),\n // so a reset mid-helper cannot repopulate discarded state.\n const writeGeneration = captureDocumentStoreSyncGeneration(\n state,\n restored.doc,\n );\n if (!writeGeneration) {\n return;\n }\n await recoverDroppedAttachmentSlots(state, restored.doc, writeGeneration);\n if (state.localWriteGeneration !== initializeGeneration) {\n return;\n }\n await healLocalAttachmentDetachState(\n state,\n restored.doc,\n activePersistedState,\n writeGeneration,\n );\n if (state.localWriteGeneration !== initializeGeneration) {\n return;\n }\n state.initialized = true;\n state.initializePromise = null;\n setReadySnapshot(state, restored.doc, false);\n\n if (restored.activeRecord.documentId && state.scheduleStartupRemoteSync) {\n // Websocket invalidations are intentionally session-local. A process can\n // stop before receiving a peer device's update event, and no event survives\n // the restart to distinguish a clean local snapshot from a stale one. Probe\n // each opened remote document once after loading it; unopened documents stay\n // lazy, while body and attachment state for a restored window converges.\n allowDocumentStoreRemoteSync(state);\n markDocumentStoreRemoteSyncPending(state, \"independent\");\n logRevalidationScheduled(state.runtime, \"startup\");\n }\n scheduleSync();\n void runDocumentOrphanMaintenance(state);\n}\n\nexport function ensureDocumentStoreInitialized(\n state: DocumentStoreState,\n scheduleSync: () => void,\n) {\n if (\n state.initialized ||\n state.initializePromise ||\n state.runtime.infra.dbStatus !== \"ready\"\n ) {\n return;\n }\n\n const initializePromise = initializeDocumentStore(state, scheduleSync).catch(\n (error: unknown) => {\n state.initializePromise = null;\n\n if (isDatabaseUnavailableError(error)) {\n return;\n }\n\n throw error;\n },\n );\n state.initializePromise = initializePromise;\n void initializePromise.catch(() => undefined);\n}\n\nexport async function awaitInitializationForSync(state: DocumentStoreState) {\n if (!state.initializePromise) {\n return true;\n }\n\n try {\n await state.initializePromise;\n return true;\n } catch (error) {\n if (isDatabaseUnavailableError(error)) {\n return false;\n }\n\n throw error;\n }\n}\n\nexport async function ensureDocumentStoreReady(\n state: DocumentStoreState,\n scheduleSync: () => void,\n): Promise<boolean> {\n ensureDocumentStoreInitialized(state, scheduleSync);\n\n if (state.initialized) {\n return true;\n }\n\n if (!state.initializePromise) {\n return false;\n }\n\n return awaitInitializationForSync(state);\n}\n\nexport async function relinkDocumentStore(\n state: DocumentStoreState,\n input: DocumentStoreRelinkInput,\n scheduleSync: () => void,\n commitSideEffect?: DocumentRelinkCommitSideEffect,\n): Promise<DocumentSummary | null> {\n if (\n input.stillCurrent?.() === false ||\n !(await ensureDocumentStoreReady(state, scheduleSync)) ||\n input.stillCurrent?.() === false ||\n !state.doc\n ) {\n return null;\n }\n const currentDoc = state.doc;\n const generation = captureDocumentStoreSyncGeneration(state, currentDoc);\n if (!generation) return null;\n // Read the record and persist on the identity-write chain so an in-flight\n // eager create cannot interleave: a create that captured a null identity\n // before its network round trip would otherwise write the derived documentId\n // over the one this relink assigns.\n const persisted = await chainIdentityWrite(state, async () => {\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) return null;\n const currentDocumentId = state.record?.documentId ?? null;\n const currentAccessEpoch =\n state.record?.accessEpoch ?? DEFAULT_DOCUMENT_ACCESS_EPOCH;\n const patch: Partial<DocumentRecord> = {\n accessEpoch: Math.max(currentAccessEpoch, input.accessEpoch),\n accessStateHash:\n input.accessStateHash === undefined\n ? (state.record?.accessStateHash ?? null)\n : input.accessStateHash,\n containerId: input.containerId,\n documentId: input.documentId,\n };\n if (input.contentKeyBundle !== undefined) {\n patch.contentKeyBundle = input.contentKeyBundle;\n }\n if (input.documentKekTargets !== undefined) {\n patch.documentKekTargets = input.documentKekTargets;\n }\n if (input.documentManifestBundle !== undefined) {\n patch.documentManifestBundle = input.documentManifestBundle;\n }\n\n // Relink rewrites access/identity metadata, not content. If it lands while\n // the user is mid-edit, re-deriving text/structured fields from the\n // (possibly lagging) doc would republish a stale read over the live\n // optimistic snapshot and drop in-flight keystrokes; preserve the snapshot\n // like the keystroke and sync persists do.\n // A prior chained write may have cleared this store (resurrect-guard\n // refusal): persisting the captured doc against a null record would\n // resurrect the document as a create. The identity check runs inside\n // the chain, after every earlier write settled.\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n return null;\n }\n const result = await persistDocument(\n state,\n currentDoc,\n patch,\n {\n preserveSnapshotStructuredFields: true,\n preserveSnapshotText: true,\n stillCurrent: input.stillCurrent,\n },\n generation,\n commitSideEffect,\n );\n if (result && currentDocumentId !== input.documentId) {\n state.writerProjection = null;\n invalidateDocumentStoreRemoteSync(state);\n }\n return result;\n });\n // A refused persist means the durable row vanished mid-relink (resurrect\n // guard); there is no summary to report.\n if (!persisted) {\n return null;\n }\n if (persisted.updatedAt === undefined) {\n return null;\n }\n return documentSummaryFromRecord(\n persisted.record,\n persisted.updatedAt,\n state.runtime.infra.documentProjectors,\n );\n}\n"]}
1
+ {"version":3,"file":"initialization.js","sourceRoot":"","sources":["initialization.ts"],"names":[],"mappings":"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","sourcesContent":["import { bytesToBase64 } from \"@tearleads/encoding\";\nimport {\n emptyVersionVector,\n encodeVersionVector,\n exportAllUpdates,\n exportFullHistorySnapshot,\n mergeVersionVectors,\n} from \"@tearleads/loro\";\nimport {\n DEFAULT_DOCUMENT_ACCESS_EPOCH,\n DEFAULT_DOCUMENT_KIND,\n} from \"../../../data/documents/documentConstants\";\nimport {\n initializeStoredDocumentKind,\n readStoredDocumentState,\n} from \"../../../data/documents/documentKinds\";\nimport type { DocumentSummary } from \"../../../data/documents/documentSummary\";\nimport { createPendingUpdateFields } from \"../../../data/documents/documentSync\";\nimport {\n type DocumentRecord,\n isDatabaseUnavailableError,\n loadPersistedDocumentStoreState,\n} from \"../../../workflows/documents\";\nimport type { DocumentStoreRelinkInput } from \"../types\";\nimport { chainIdentityWrite } from \"./identityWriteChain\";\nimport {\n installPersistedAttachments,\n type LoadedDocumentStoreState,\n} from \"./initializationAttachments\";\nimport {\n type RestoredHistoryState,\n restoredRemoteTailCoverage,\n restorePersistedDocumentContent,\n} from \"./initializationHistory\";\nimport {\n healLocalAttachmentDetachState,\n recoverDroppedAttachmentSlots,\n} from \"./initializationRecovery\";\nimport type { DocumentRelinkCommitSideEffect } from \"./internalRelink\";\nimport { runDocumentOrphanMaintenance } from \"./orphanMaintenance\";\nimport {\n advancePendingBaseVersion,\n documentSummaryFromRecord,\n persistDocument,\n saveDocumentRecord,\n} from \"./persistence\";\nimport { logRevalidationScheduled } from \"./remoteRevalidationTelemetry\";\nimport {\n type DocumentState,\n type DocumentStoreState,\n setReadySnapshot,\n} from \"./state\";\nimport { createStoredDocument } from \"./storedDocument\";\nimport {\n allowDocumentStoreRemoteSync,\n captureDocumentStoreSyncGeneration,\n invalidateDocumentStoreRemoteSync,\n isDocumentStoreSyncGenerationCurrent,\n markDocumentStoreRemoteSyncPending,\n} from \"./syncGeneration\";\n\nasync function createInitialDocumentRecord(\n state: DocumentStoreState,\n nextDoc: DocumentState,\n): ReturnType<typeof saveDocumentRecord> {\n initializeStoredDocumentKind(\n nextDoc,\n state.initialDocumentKind,\n state.runtime.infra.documentProjectors,\n );\n if (state.initialText.length > 0) {\n nextDoc.getText(\"text\").update(state.initialText);\n }\n const initialDocumentState = readStoredDocumentState(\n nextDoc,\n state.runtime.infra.documentProjectors,\n );\n const hasInitialContent =\n state.initialText.length > 0 ||\n state.initialDocumentKind !== DEFAULT_DOCUMENT_KIND;\n const initialUpdate = hasInitialContent\n ? createPendingUpdateFields(exportAllUpdates(nextDoc))\n : null;\n // A deferred birth still commits its checkpoint, but leaves the marker at the\n // empty version with nothing queued: the promised attach exports every op\n // since that marker, so one update carries the birth and the attachment.\n const birthDurability = !initialUpdate\n ? {}\n : state.deferInitialUpdate\n ? { pendingBaseVersionOverride: emptyVersionVector() }\n : { pendingUpdate: initialUpdate };\n\n const created: DocumentRecord = {\n id: state.localId,\n containerId: state.runtime.state.containerId ?? null,\n documentId: state.initialDocumentId,\n documentKind: initialDocumentState.documentKind,\n text: initialDocumentState.text,\n title: initialDocumentState.title,\n snapshotEndVersion: encodeVersionVector(nextDoc),\n accessEpoch: DEFAULT_DOCUMENT_ACCESS_EPOCH,\n accessStateHash: null,\n effectiveAccessLevel: \"admin\",\n lastCommitLsn: null,\n contentKeyBundle: null,\n documentKekTargets: null,\n documentManifestBundle: null,\n };\n // The create-only persistence primitive commits the canonical row and birth\n // checkpoint together. A concurrent initializer either wins both or adopts\n // both, so it cannot replace another pane's history or keying state.\n const persisted = await saveDocumentRecord(\n state,\n nextDoc,\n {\n ...created,\n snapshotEndVersion: encodeVersionVector(nextDoc),\n },\n {\n historyCheckpoint: {\n coveredTailIds: [],\n endVersionVector: encodeVersionVector(nextDoc),\n pruneCoveredLocalState: false,\n snapshot: bytesToBase64(exportFullHistorySnapshot(nextDoc)),\n },\n ...birthDurability,\n },\n );\n return persisted;\n}\n\nfunction installPersistedDocumentRecord(\n state: DocumentStoreState,\n record: NonNullable<DocumentStoreState[\"record\"]>,\n): void {\n state.record = record;\n state.pullContinuation = record.pullContinuation ?? null;\n}\n\ninterface RestoredInitialDocumentState {\n activePersistedState: LoadedDocumentStoreState;\n activeRecord: NonNullable<DocumentStoreState[\"record\"]>;\n doc: DocumentState;\n history: RestoredHistoryState | null;\n}\n\nasync function restoreLoadedInitialDocument(input: {\n initializeGeneration: number;\n nextDoc: DocumentState;\n persistedState: LoadedDocumentStoreState;\n state: DocumentStoreState;\n}): Promise<RestoredInitialDocumentState | null> {\n const { initializeGeneration, persistedState, state } = input;\n const record = persistedState.document;\n if (!record) return null;\n const history = await restorePersistedDocumentContent(\n input.nextDoc,\n persistedState.historyRestoreState,\n );\n if (state.localWriteGeneration !== initializeGeneration) return null;\n installPersistedDocumentRecord(state, record);\n return {\n activePersistedState: persistedState,\n activeRecord: record,\n doc: input.nextDoc,\n history,\n };\n}\n\nasync function restoreOrCreateInitialDocument(input: {\n initializeGeneration: number;\n nextDoc: DocumentState;\n persistedState: LoadedDocumentStoreState;\n state: DocumentStoreState;\n}): Promise<RestoredInitialDocumentState | null> {\n const { initializeGeneration, persistedState, state } = input;\n if (persistedState.document) {\n return restoreLoadedInitialDocument(input);\n }\n\n const created = await createInitialDocumentRecord(state, input.nextDoc);\n if (!created || state.localWriteGeneration !== initializeGeneration) {\n return null;\n }\n const activePersistedState = await loadPersistedDocumentStoreState({\n execSql: state.runtime.infra.execSql,\n localId: state.localId,\n persistence: state.persistence,\n });\n if (state.localWriteGeneration !== initializeGeneration) {\n return null;\n }\n if (!activePersistedState.document) {\n throw new Error(\"Document creation completed without a durable record\");\n }\n const replacementDoc = await createStoredDocument(state);\n return restoreLoadedInitialDocument({\n initializeGeneration,\n nextDoc: replacementDoc,\n persistedState: activePersistedState,\n state,\n });\n}\n\nfunction restorePendingBaseVersion(input: {\n activeRecord: NonNullable<DocumentStoreState[\"record\"]>;\n doc: DocumentState;\n history: RestoredHistoryState | null;\n state: DocumentStoreState;\n}): void {\n const { activeRecord, doc, history, state } = input;\n const markerBase =\n activeRecord.pendingBaseVersion ??\n (activeRecord.snapshotEndVersion.length > 0\n ? activeRecord.snapshotEndVersion\n : null);\n if (markerBase === null) {\n advancePendingBaseVersion(state, doc);\n return;\n }\n\n const remoteCoverage = restoredRemoteTailCoverage(history);\n state.pendingBaseVersion =\n remoteCoverage.length > 0\n ? mergeVersionVectors([markerBase, ...remoteCoverage])\n : markerBase;\n}\n\nasync function initializeDocumentStore(\n state: DocumentStoreState,\n scheduleSync: () => void,\n) {\n if (state.runtime.infra.dbStatus !== \"ready\") {\n return;\n }\n\n // A store reset while this fire-and-forget initialization is loading (a\n // runtime swap, or a local-edits discard that re-seeds the persisted rows)\n // must win: assigning the state loaded BEFORE the reset would bring the\n // replaced record and doc back to life. Every reset bumps the local write\n // generation, so a stale capture here aborts before each assignment batch.\n const initializeGeneration = state.localWriteGeneration;\n\n const nextDoc = await createStoredDocument(state);\n const persistedState = await loadPersistedDocumentStoreState({\n execSql: state.runtime.infra.execSql,\n localId: state.localId,\n persistence: state.persistence,\n });\n if (state.localWriteGeneration !== initializeGeneration) {\n return;\n }\n const restored = await restoreOrCreateInitialDocument({\n initializeGeneration,\n nextDoc,\n persistedState,\n state,\n });\n if (!restored) {\n return;\n }\n const activePersistedState = restored.activePersistedState;\n installPersistedAttachments(state, activePersistedState);\n\n state.doc = restored.doc;\n // Restore the durable outgoing-delta marker. Re-seeding it to the restored\n // document's version would move it PAST any device-first `deferRemoteSync`\n // op (persisted into the durable history but deliberately left un-enqueued\n // and behind the marker), permanently dropping that op from sync across a\n // restart. When a marker was persisted, restore it so the next edit still\n // re-derives the deferred delta. Only seed for rows that never persisted\n // one, from the RECORD's persisted frontier rather than the restored\n // document: a crash between the tail append and the queue/marker writes can\n // resurrect ops the outgoing queue never durably received, and seeding from\n // the restored document would classify those as covered and orphan them\n // from sync forever.\n restorePendingBaseVersion({\n activeRecord: restored.activeRecord,\n doc: restored.doc,\n history: restored.history,\n state,\n });\n // Heal attachment slots lost to an interrupted attach write before marking\n // ready, so the recovered slots are in the snapshot the editor first renders\n // and are queued for sync. recoverDroppedAttachmentSlots advances the marker\n // again for whatever it re-derives. Both helpers gate every durable write\n // on this generation (validated inside the writes' serialized mutations),\n // so a reset mid-helper cannot repopulate discarded state.\n const writeGeneration = captureDocumentStoreSyncGeneration(\n state,\n restored.doc,\n );\n if (!writeGeneration) {\n return;\n }\n await recoverDroppedAttachmentSlots(state, restored.doc, writeGeneration);\n if (state.localWriteGeneration !== initializeGeneration) {\n return;\n }\n await healLocalAttachmentDetachState(\n state,\n restored.doc,\n activePersistedState,\n writeGeneration,\n );\n if (state.localWriteGeneration !== initializeGeneration) {\n return;\n }\n state.initialized = true;\n state.initializePromise = null;\n setReadySnapshot(state, restored.doc, false);\n\n if (restored.activeRecord.documentId && state.scheduleStartupRemoteSync) {\n // Websocket invalidations are intentionally session-local. A process can\n // stop before receiving a peer device's update event, and no event survives\n // the restart to distinguish a clean local snapshot from a stale one. Probe\n // each opened remote document once after loading it; unopened documents stay\n // lazy, while body and attachment state for a restored window converges.\n allowDocumentStoreRemoteSync(state);\n markDocumentStoreRemoteSyncPending(state, \"independent\");\n logRevalidationScheduled(state.runtime, \"startup\");\n }\n scheduleSync();\n void runDocumentOrphanMaintenance(state);\n}\n\nexport function ensureDocumentStoreInitialized(\n state: DocumentStoreState,\n scheduleSync: () => void,\n) {\n if (\n state.initialized ||\n state.initializePromise ||\n state.runtime.infra.dbStatus !== \"ready\"\n ) {\n return;\n }\n\n const initializePromise = initializeDocumentStore(state, scheduleSync).catch(\n (error: unknown) => {\n state.initializePromise = null;\n // A caller that deferred the birth for its attach may give up once\n // opening fails; never leave its durable birth holding sync. No attach\n // has reached a live doc yet, so lifting the hold ships nothing unsafe.\n state.deferInitialUpdate = false;\n\n if (isDatabaseUnavailableError(error)) {\n return;\n }\n\n throw error;\n },\n );\n state.initializePromise = initializePromise;\n void initializePromise.catch(() => undefined);\n}\n\nexport async function awaitInitializationForSync(state: DocumentStoreState) {\n if (!state.initializePromise) {\n return true;\n }\n\n try {\n await state.initializePromise;\n return true;\n } catch (error) {\n if (isDatabaseUnavailableError(error)) {\n return false;\n }\n\n throw error;\n }\n}\n\nexport async function ensureDocumentStoreReady(\n state: DocumentStoreState,\n scheduleSync: () => void,\n): Promise<boolean> {\n ensureDocumentStoreInitialized(state, scheduleSync);\n\n if (state.initialized) {\n return true;\n }\n\n if (!state.initializePromise) {\n return false;\n }\n\n return awaitInitializationForSync(state);\n}\n\nexport async function relinkDocumentStore(\n state: DocumentStoreState,\n input: DocumentStoreRelinkInput,\n scheduleSync: () => void,\n commitSideEffect?: DocumentRelinkCommitSideEffect,\n): Promise<DocumentSummary | null> {\n if (\n input.stillCurrent?.() === false ||\n !(await ensureDocumentStoreReady(state, scheduleSync)) ||\n input.stillCurrent?.() === false ||\n !state.doc\n ) {\n return null;\n }\n const currentDoc = state.doc;\n const generation = captureDocumentStoreSyncGeneration(state, currentDoc);\n if (!generation) return null;\n // Read the record and persist on the identity-write chain so an in-flight\n // eager create cannot interleave: a create that captured a null identity\n // before its network round trip would otherwise write the derived documentId\n // over the one this relink assigns.\n const persisted = await chainIdentityWrite(state, async () => {\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) return null;\n const currentDocumentId = state.record?.documentId ?? null;\n const currentAccessEpoch =\n state.record?.accessEpoch ?? DEFAULT_DOCUMENT_ACCESS_EPOCH;\n const patch: Partial<DocumentRecord> = {\n accessEpoch: Math.max(currentAccessEpoch, input.accessEpoch),\n accessStateHash:\n input.accessStateHash === undefined\n ? (state.record?.accessStateHash ?? null)\n : input.accessStateHash,\n containerId: input.containerId,\n documentId: input.documentId,\n };\n if (input.contentKeyBundle !== undefined) {\n patch.contentKeyBundle = input.contentKeyBundle;\n }\n if (input.documentKekTargets !== undefined) {\n patch.documentKekTargets = input.documentKekTargets;\n }\n if (input.documentManifestBundle !== undefined) {\n patch.documentManifestBundle = input.documentManifestBundle;\n }\n\n // Relink rewrites access/identity metadata, not content. If it lands while\n // the user is mid-edit, re-deriving text/structured fields from the\n // (possibly lagging) doc would republish a stale read over the live\n // optimistic snapshot and drop in-flight keystrokes; preserve the snapshot\n // like the keystroke and sync persists do.\n // A prior chained write may have cleared this store (resurrect-guard\n // refusal): persisting the captured doc against a null record would\n // resurrect the document as a create. The identity check runs inside\n // the chain, after every earlier write settled.\n if (!isDocumentStoreSyncGenerationCurrent(state, generation)) {\n return null;\n }\n const result = await persistDocument(\n state,\n currentDoc,\n patch,\n {\n preserveSnapshotStructuredFields: true,\n preserveSnapshotText: true,\n stillCurrent: input.stillCurrent,\n },\n generation,\n commitSideEffect,\n );\n if (result && currentDocumentId !== input.documentId) {\n state.writerProjection = null;\n invalidateDocumentStoreRemoteSync(state);\n }\n return result;\n });\n // A refused persist means the durable row vanished mid-relink (resurrect\n // guard); there is no summary to report.\n if (!persisted) {\n return null;\n }\n if (persisted.updatedAt === undefined) {\n return null;\n }\n return documentSummaryFromRecord(\n persisted.record,\n persisted.updatedAt,\n state.runtime.infra.documentProjectors,\n );\n}\n"]}
@@ -57,9 +57,9 @@ function updateDocumentStoreRuntime(state, nextRuntime, scheduleSync) {
57
57
  if (state.snapshot.ready) {
58
58
  if (serverEventsReconnected) {
59
59
  // The invalidation stream is lossy while disconnected. Once the server
60
- // has restored this session's interest baseline, every already-open
61
- // remote document needs one HTTP probe to cover peer writes made during
62
- // the gap. This also closes iOS background/resume reconnects where the
60
+ // has acknowledged this socket's authoritative interest declaration,
61
+ // every already-open remote document needs one HTTP probe to cover peer
62
+ // writes made during the gap. This also closes iOS background/resume reconnects where the
63
63
  // native network source remained online throughout.
64
64
  requestRemoteDocumentStoreSync(state, scheduleSync);
65
65
  logRevalidationScheduled(state.runtime, "reconnect");