js-bao-wss-client 2.2.0-alpha.0 → 2.2.0-alpha.2

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.
@@ -1,6 +1,6 @@
1
1
  import { Observable } from "lib0/observable";
2
2
  import * as Y from "yjs";
3
- import { DatabaseConfig } from "js-bao";
3
+ import { initJsBao, DatabaseConfig } from "js-bao";
4
4
  import type { DiscoveredSchema } from "js-bao";
5
5
  import type { TypedModelConstructor } from "./types/typed-model-constructor";
6
6
  import { LogLevel } from "./internal/logger";
@@ -11,6 +11,7 @@ import { type AnalyticsEventInput } from "./internal/analyticsQueue";
11
11
  import { type GoogleClientsConfig } from "./internal/authController";
12
12
  import { type RequestOptions } from "./internal/httpClient";
13
13
  import { type DocumentPermission as DocumentAccessLevel, type LocalDocumentEntry, type LocalMetadataEntry, type DocumentDebugSnapshot } from "./internal/documentManager";
14
+ import { type OfflineReplayNotice } from "js-bao";
14
15
  import { DocumentsAPI, DocumentContext, type DocumentInfo, type ResolveAliasParams, type CreateDocumentOptions } from "./api/documentsApi";
15
16
  import { type CacheFacade } from "./api/cacheFacade";
16
17
  import { MeAPI } from "./api/meApi";
@@ -22,6 +23,7 @@ import { DatabasesAPI } from "./api/databasesApi";
22
23
  import { GroupsAPI } from "./api/groupsApi";
23
24
  import { CronTriggersAPI } from "./api/cronTriggersApi";
24
25
  import { LocksAPI } from "./api/locksApi";
26
+ import { FunctionsAPI } from "./api/functionsApi";
25
27
  import { ResourceMetadataAPI } from "./api/resourceMetadataApi";
26
28
  import { RuleSetsAPI } from "./api/ruleSetsApi";
27
29
  import { BlobBucketsAPI } from "./api/blobBucketsApi";
@@ -91,6 +93,7 @@ export type { DocumentDebugSnapshot, DocumentPermission, LocalDocumentEntry, Loc
91
93
  export type { LogLevel } from "./internal/logger";
92
94
  export type { RequestOptions } from "./internal/httpClient";
93
95
  export type { LocksAPI } from "./api/locksApi";
96
+ export type { FunctionsAPI, FunctionInvokeOptions, FunctionInvokeResult, FunctionInvokeStatus, } from "./api/functionsApi";
94
97
  export type { LockHandle, LockContention, AcquireResponse, AcquireOptions, BlockingAcquireOptions, ReleaseResult, RenewResult, LockStatus, LockListEntry, LockListResult, } from "./api/locksApi";
95
98
  export type { ResourceMetadataAPI } from "./api/resourceMetadataApi";
96
99
  export type { ResourceMetadataReadResult, ResourceMetadataWriteResult, ResourceMetadataBatchRequestItem, ResourceMetadataBatchParams, ResourceMetadataBatchCategoryResult, ResourceMetadataBatchResourceResult, ResourceMetadataBatchResult, ResourceMetadataListEntry, ResourceMetadataListResult, ResourceMetadataDeleteResult, ResourceMetadataResolveParams, ResourceMetadataResolveResult, } from "./api/resourceMetadataApi";
@@ -410,6 +413,27 @@ export interface JsBaoClientOptions {
410
413
  enabled?: boolean;
411
414
  };
412
415
  databaseConfig?: DatabaseConfig;
416
+ /**
417
+ * What this device may keep of a large document.
418
+ *
419
+ * Loading a large document materializes its records into local storage. On a
420
+ * platform whose quota will not take the whole document, `models` names the
421
+ * ones worth the space — the rest are left unloaded, and the models named
422
+ * are queryable as usual. With none configured, a device short of space is
423
+ * refused with a typed error rather than loaded arbitrarily, and a platform
424
+ * with no durable storage at all is always refused.
425
+ *
426
+ * `capability` overrides the platform probe, for a host that owns its own
427
+ * store and knows what it can hold.
428
+ */
429
+ largeDocumentStorage?: {
430
+ capability?: {
431
+ persistent: boolean;
432
+ quotaBytes: number | null;
433
+ usedBytes?: number;
434
+ };
435
+ models?: string[];
436
+ };
413
437
  storageConfig?: StorageConfig;
414
438
  /**
415
439
  * Custom Yjs persistence factory for document storage.
@@ -488,6 +512,21 @@ export interface DocumentSyncStateChangedEvent {
488
512
  documentId: string;
489
513
  state: "syncing" | "synced" | "stale" | "error";
490
514
  }
515
+ /**
516
+ * Payload of the `documentOfflineWritesResolved` event
517
+ * (`client.on("documentOfflineWritesResolved", ...)`).
518
+ *
519
+ * Fired when a large document that was away replays what it wrote offline and
520
+ * some of it did not simply apply: a write the online side clearly beat is
521
+ * DROPPED, and one whose order cannot be established is applied but reported.
522
+ * Silence means every offline write replayed cleanly.
523
+ */
524
+ export interface DocumentOfflineWritesResolvedEvent {
525
+ documentId: string;
526
+ /** The epoch the writes were replayed onto. */
527
+ epoch: number;
528
+ notices: OfflineReplayNotice[];
529
+ }
491
530
  /**
492
531
  * Options for `client.syncMetadata()`. Controls whether the sync covers all
493
532
  * of the user's document metadata or a single document (`scope` /
@@ -1481,6 +1520,35 @@ export interface EvictAllLocalOptions {
1481
1520
  * handler)`: the handler's argument type is `JsBaoEvents[name]`. See each
1482
1521
  * payload interface for when its event fires.
1483
1522
  */
1523
+ /**
1524
+ * How a large document's base snapshot load is going.
1525
+ *
1526
+ * A cold open of a large document streams a base of up to gigabytes before the
1527
+ * document is usable, which can take minutes. An app with nothing to show for
1528
+ * that is indistinguishable from one that has hung, so the load reports itself:
1529
+ * `started` once the manifest is in hand (which is where `totalRows` comes
1530
+ * from, so a progress bar exists before the first chunk lands), `progress` per
1531
+ * chunk, `model` as each model becomes queryable, and `loaded` at the end.
1532
+ */
1533
+ export interface DocumentSnapshotLoadEvent {
1534
+ documentId: string;
1535
+ phase: "started" | "progress" | "model" | "loaded";
1536
+ /** The epoch the snapshot is a base for. */
1537
+ epoch: number;
1538
+ rows: number;
1539
+ totalRows: number;
1540
+ chunks: number;
1541
+ totalChunks: number;
1542
+ /** The model the event concerns, when it concerns one. */
1543
+ model?: string;
1544
+ }
1545
+ /**
1546
+ * Every event the client emits, mapped to the payload its listener receives.
1547
+ *
1548
+ * `client.on(name, handler)` is typed from this map, so the handler's argument
1549
+ * is the payload type listed here — pick the event you want and follow the
1550
+ * link to see what it carries.
1551
+ */
1484
1552
  export interface JsBaoEvents {
1485
1553
  error: {
1486
1554
  error: unknown;
@@ -1516,9 +1584,11 @@ export interface JsBaoEvents {
1516
1584
  documentOpened: DocumentEvent;
1517
1585
  documentMetadataChanged: DocumentMetadataChangedEvent;
1518
1586
  documentSyncStateChanged: DocumentSyncStateChangedEvent;
1587
+ documentOfflineWritesResolved: DocumentOfflineWritesResolvedEvent;
1519
1588
  permission: PermissionEvent;
1520
1589
  sync: SyncEvent;
1521
1590
  awareness: AwarenessEvent;
1591
+ "document:snapshot-load": DocumentSnapshotLoadEvent;
1522
1592
  "blobs:upload-progress": BlobUploadProgressEvent;
1523
1593
  "blobs:upload-completed": BlobUploadCompletedEvent;
1524
1594
  "blobs:upload-failed": BlobUploadFailedEvent;
@@ -1703,9 +1773,162 @@ export declare class JsBaoClient extends Observable<any> {
1703
1773
  private jwtPersistenceCleared;
1704
1774
  private docOpensInFlight;
1705
1775
  private dbReady;
1776
+ /**
1777
+ * This client's own js-bao instance (#3039), destroyed with the client.
1778
+ *
1779
+ * Was impossible while `initJsBao` memoized one process-wide instance:
1780
+ * tearing it down would have taken every other client's engine with it.
1781
+ */
1782
+ private jsBaoInstance;
1706
1783
  private jsBaoConnectDoc;
1707
1784
  private jsBaoDisconnectDoc;
1708
1785
  private jsBaoIsDocumentConnected;
1786
+ /**
1787
+ * #2816, behavior 9 — the ORM side of format-2's durable acknowledgement:
1788
+ * the sequences a document's local writes have reached, and the prune the
1789
+ * server's `update.ack` authorizes. `null` on a legacy document.
1790
+ */
1791
+ private jsBaoFormat2SyncMarks;
1792
+ private jsBaoFormat2Acknowledge;
1793
+ /**
1794
+ * #2816 — the epoch a document's own RECORD DATABASE says it follows,
1795
+ * readable before the ORM binds the document. `0` when that database holds
1796
+ * no document whatever the client's metadata claims; `null` when the engine
1797
+ * cannot be asked, which is not evidence either way.
1798
+ */
1799
+ private jsBaoFormat2StoredEpoch;
1800
+ private jsBaoFormat2NoteEpoch;
1801
+ /**
1802
+ * #2816, behavior 18 — record that a document was in touch with the server,
1803
+ * and the offline window the server reported. Past that window without a
1804
+ * sync the ORM refuses local writes and keeps serving reads.
1805
+ */
1806
+ private jsBaoFormat2NoteSync;
1807
+ /**
1808
+ * #2816, behavior 18 — record the offline window the handshake reported,
1809
+ * without claiming a sync. The number is the server's whatever else the
1810
+ * frame says; the mark it is measured from has to be earned.
1811
+ */
1812
+ private jsBaoFormat2NoteWindow;
1813
+ /**
1814
+ * #2816 — resolves once a large document's derived query tables have caught
1815
+ * up with its merged view. Awaited before an update from the room counts as
1816
+ * applied, so `find()` and `query()` never answer from different epochs.
1817
+ */
1818
+ private jsBaoWhenFormat2ProjectionSettled;
1819
+ private jsBaoFormat2NoteClockOffset;
1820
+ private jsBaoFormat2ForgetPendingOps;
1821
+ /**
1822
+ * #2816, behavior 17 — rewrite the pending ops a replay resolution narrowed.
1823
+ * A write that survived only in part must be recorded as the surviving part,
1824
+ * or the restore path would put the whole one back after a crash.
1825
+ */
1826
+ private jsBaoFormat2NarrowPendingOps;
1827
+ /**
1828
+ * What the sealed overlays of a catch-up said was written online, per
1829
+ * document (#2816, behavior 17). Built while the chain is applied — those
1830
+ * artifacts are the online side of every conflict — and consumed by the move
1831
+ * that replays this client's offline writes onto the epoch it landed on.
1832
+ */
1833
+ /**
1834
+ * A returning client's replay, held until the epoch it joined has synced
1835
+ * (#2816, behavior 17). Keyed by document; the timer is the fallback for a
1836
+ * sync that never completes.
1837
+ */
1838
+ private readonly format2PendingReplays;
1839
+ /**
1840
+ * The last `epoch.info` this client acted on, per document — what a rebuild
1841
+ * started outside the handshake needs to plan itself (#2816).
1842
+ */
1843
+ private readonly format2LastHandshakes;
1844
+ private readonly format2ConflictLedgers;
1845
+ /**
1846
+ * Documents already being rebuilt because an offline delete lost (#2816,
1847
+ * behavior 17).
1848
+ *
1849
+ * The rebuild replays the same resolution when it lands, and it would reach
1850
+ * the same conclusion — so without this the document would ask to be rebuilt
1851
+ * out of the rebuild, forever. Cleared once the move it was rebuilt for has
1852
+ * gone through.
1853
+ */
1854
+ private readonly format2RebuildingForDrop;
1855
+ /**
1856
+ * The last sync note per document, kept in memory for the same reason the
1857
+ * epoch mark is: `epoch.info` arrives before the ORM binds the document, so
1858
+ * there is no record store to write it into yet. It is written through the
1859
+ * first time one exists.
1860
+ */
1861
+ private readonly format2SyncNotes;
1862
+ /**
1863
+ * #2816, behavior 10 — what a client owes the next epoch, and the mark it
1864
+ * moves once that epoch's overlay is installed.
1865
+ */
1866
+ private jsBaoFormat2PendingOps;
1867
+ private jsBaoFormat2SetEpoch;
1868
+ private jsBaoFormat2RebindEpochDocument;
1869
+ /**
1870
+ * Folds one sealed epoch's archived overlay into the document's merged view
1871
+ * — the step a client behind by whole epochs repeats per archive to catch up
1872
+ * (#2816, behavior 12).
1873
+ */
1874
+ private jsBaoFormat2ApplySealedOverlay;
1875
+ /**
1876
+ * Throws away a merged view whose sealed-overlay chain was refused, so a
1877
+ * base snapshot can be loaded over nothing rather than over the state of an
1878
+ * epoch the room has left behind (#2816, behavior 12).
1879
+ */
1880
+ private jsBaoFormat2DiscardMergedView;
1881
+ /**
1882
+ * Folds the open epoch's overlay into the merged view again — the step that
1883
+ * finishes a cold load, because a base snapshot's rows REPLACE whatever the
1884
+ * open epoch had already contributed through the ordinary sync (#2816,
1885
+ * behavior 15).
1886
+ */
1887
+ private jsBaoFormat2RefoldOverlay;
1888
+ /**
1889
+ * Materializes a base snapshot into the document's merged view — how a
1890
+ * client with no local state opens a document that has rotated (#2816,
1891
+ * behavior 15).
1892
+ */
1893
+ private jsBaoFormat2LoadSnapshot;
1894
+ /**
1895
+ * Runs an epoch move with the document's local writes held back: a write
1896
+ * that lands on the sealed overlay after what is owed has been read off it
1897
+ * goes down with that document (#2816, behavior 10).
1898
+ */
1899
+ private jsBaoFormat2HoldWrites;
1900
+ /** Documents currently moving to a new epoch, so a repeat notice waits. */
1901
+ private readonly format2Rotations;
1902
+ /**
1903
+ * The freshest artifact grants each large document has been given (#2816).
1904
+ *
1905
+ * A grant lives an hour and a base snapshot can take longer, so a load that
1906
+ * outlives its signatures asks for new ones and keeps going; this is where
1907
+ * the answer lands.
1908
+ */
1909
+ private readonly format2Grants;
1910
+ /** Reads parked on a grant refresh, woken by the room's answer. */
1911
+ private readonly format2GrantWaiters;
1912
+ /**
1913
+ * The epoch each large document's connection reported. `epoch.info` arrives
1914
+ * during the handshake, before the ORM has built the record store that holds
1915
+ * the mark durably, so the transport remembers it until then.
1916
+ */
1917
+ private readonly format2EpochMarks;
1918
+ /**
1919
+ * Large documents that learned they are behind before the ORM had bound
1920
+ * them: the catch-up needs the merged view, so it is owed here and runs at
1921
+ * the bind. They stay silent until it has (#2816, behavior 12).
1922
+ */
1923
+ private readonly format2OwedCatchUps;
1924
+ /**
1925
+ * Large documents stopped on a superseded epoch: their overlay belongs to an
1926
+ * epoch the room has left behind, so nothing of their local state may be
1927
+ * sent. See `format2RequireReload`.
1928
+ */
1929
+ private readonly format2StaleEpochs;
1930
+ /** Outbound sequences per large document: queued, sent, acknowledged. */
1931
+ private readonly format2Ack;
1709
1932
  private jsBaoAddDocumentModelMapping;
1710
1933
  private jsBaoRemoveDocumentModelMapping;
1711
1934
  private readonly localUpdateOrigin;
@@ -1794,6 +2017,11 @@ export declare class JsBaoClient extends Observable<any> {
1794
2017
  /** Sub-API for the named lock API (acquire/release/renew/status/list).
1795
2018
  * @group Sub-APIs */
1796
2019
  locks: LocksAPI;
2020
+ /**
2021
+ * Server functions, available as `client.functions`. Invokes code an app's
2022
+ * team authored and pushed with `primitive config push`.
2023
+ */
2024
+ functions: FunctionsAPI;
1797
2025
  /** Sub-API for reading and writing typed resource metadata (single + batch).
1798
2026
  * @group Sub-APIs */
1799
2027
  resourceMetadata: ResourceMetadataAPI;
@@ -2039,6 +2267,14 @@ export declare class JsBaoClient extends Observable<any> {
2039
2267
  /** Get the global admin app ID.
2040
2268
  * @group Configuration */
2041
2269
  getGlobalAdminAppId(): string;
2270
+ /**
2271
+ * Build this client's js-bao instance.
2272
+ *
2273
+ * A seam, not an extension point: the constructor starts initialization
2274
+ * without awaiting it, so the destroy/init race has no other place a test
2275
+ * can hold the instance back from.
2276
+ */
2277
+ protected createJsBaoInstance(options: Parameters<typeof initJsBao>[0]): Promise<Awaited<ReturnType<typeof initJsBao>>>;
2042
2278
  private initializeJsBao;
2043
2279
  private _syncKvUserId;
2044
2280
  private getAuthPersistenceContext;
@@ -2327,6 +2563,332 @@ export declare class JsBaoClient extends Observable<any> {
2327
2563
  * background refresh or an interactive sign-in takes.
2328
2564
  */
2329
2565
  private handleWsAuthChallenge;
2566
+ /**
2567
+ * A large document's write is durable (#2816, behavior 9).
2568
+ *
2569
+ * The server sends this only after the update-log row and the inline
2570
+ * projection committed together, so this is the one event that may prune
2571
+ * `_pending_ops` — and the one that may report the document as having
2572
+ * nothing unsynced left.
2573
+ */
2574
+ private handleUpdateAck;
2575
+ /**
2576
+ * Move a large document onto the epoch that replaced the sealed one
2577
+ * (#2816, behavior 10).
2578
+ *
2579
+ * Serialized per document: a seal is broadcast to every connection, and a
2580
+ * late frame can draw an `epoch.resync` on top of it, so the same move can
2581
+ * be asked for more than once. Running them concurrently would race two
2582
+ * swaps of the same document's overlay.
2583
+ *
2584
+ * A client that cannot follow — it missed whole epochs, so its merged view
2585
+ * is behind by sealed overlays it never applied — is STOPPED rather than
2586
+ * resynced: see `format2RequireReload`.
2587
+ */
2588
+ private followEpochSeal;
2589
+ /**
2590
+ * The epoch a large document is on (#2816, behavior 10).
2591
+ *
2592
+ * The record store is the durable home of the mark, but it is built when the
2593
+ * ORM binds the document — after `epoch.info` has already been and gone. The
2594
+ * document's persisted metadata carries the same mark and IS loaded before
2595
+ * the handshake, so it answers in between; without it a restarted client
2596
+ * would read the connection's own report back as its current epoch and
2597
+ * conclude it was up to date whatever epoch its overlay really belongs to.
2598
+ * Whichever source answered is written through to the store the first time
2599
+ * one exists.
2600
+ */
2601
+ /**
2602
+ * Check a large document's epoch mark against its records, before the open
2603
+ * believes either (#2816).
2604
+ *
2605
+ * The mark is in the client's document metadata; the document is in the
2606
+ * record database. Those are two stores, and they can part company — an
2607
+ * in-memory merged view that a reload emptied, a database file replaced or
2608
+ * evicted, a store the app rebuilt. When the record database says it follows
2609
+ * no epoch, the mark is a claim with nothing behind it: left in place, this
2610
+ * client opens an empty document, reports itself current, and plans its next
2611
+ * save as a create that replaces a record the server still holds. Dropped,
2612
+ * it is simply a client with nothing local, and rebuilds from a base.
2613
+ *
2614
+ * Returns what the record database said, for the local-copy decision:
2615
+ * `null` means it could not be asked, which is not evidence either way.
2616
+ */
2617
+ private format2ReconcileEpochMark;
2618
+ private format2Epoch;
2619
+ /**
2620
+ * The epoch this client believes a document is on, for the BIND (#2816).
2621
+ *
2622
+ * The record store is created following epoch 0, and 0 is what "this
2623
+ * database holds no document" means to the open path — so the store has to
2624
+ * be told at the moment it is made, from what the client already knows: its
2625
+ * own durable mark, and the epoch a connection reported and this client
2626
+ * accepted (a client that is BEHIND notes nothing, so it cannot claim the
2627
+ * room's epoch here before the overlays it missed have landed).
2628
+ *
2629
+ * `undefined` when it knows of none, which leaves the store saying so.
2630
+ */
2631
+ private format2KnownEpoch;
2632
+ /**
2633
+ * Catch a large document up on the sealed overlays it missed (#2816,
2634
+ * behavior 12).
2635
+ *
2636
+ * A client that was away while the room rotated is behind by whole epochs.
2637
+ * It does not need the document back: the sealed overlays between the epoch
2638
+ * it holds and the one the room is on ARE the changes it missed, so applying
2639
+ * them in order — each bounded by the rotation threshold — brings its merged
2640
+ * view to the server's `records` state with no base on the wire.
2641
+ *
2642
+ * Serialized with the epoch moves for the same document: a seal arriving
2643
+ * mid-catch-up would otherwise swap the overlay underneath it.
2644
+ *
2645
+ * Returns `ok` when the document is on the room's epoch afterwards. When it
2646
+ * is not, `refused` says whether the CHAIN was the problem — a hole, a
2647
+ * discontinuity, or an archive retention pruned — as opposed to a download
2648
+ * that merely failed. Only the first is worth rebuilding from a base for;
2649
+ * the second is worth retrying.
2650
+ */
2651
+ private format2CatchUp;
2652
+ /**
2653
+ * Move this document onto `epoch` (#2816, behaviors 10/12).
2654
+ *
2655
+ * Installs a fresh overlay for that epoch carrying whatever is still
2656
+ * unacknowledged, and resyncs on it. Only ever called once the document's
2657
+ * merged view is the room's state again — after a chain has landed or a base
2658
+ * has been rebuilt — so the jump is no longer a jump over anything unknown.
2659
+ */
2660
+ private format2MoveOnto;
2661
+ /**
2662
+ * Hold a returning client's replay until the epoch it joined has synced
2663
+ * (#2816, behavior 17).
2664
+ *
2665
+ * The sync itself is the trigger — `syncComplete` is the room saying this
2666
+ * document now holds the epoch — but a sync that never completes must not
2667
+ * strand what this client owes: the timer states the writes anyway, which is
2668
+ * the plain offline-wins fallback the spec keeps for evidence that cannot be
2669
+ * had. Either way the writes are durable in `_pending_ops` the whole time.
2670
+ */
2671
+ private format2HoldReplay;
2672
+ /** Forget a held replay's timer, without running it. */
2673
+ private format2ClearHeldReplay;
2674
+ /**
2675
+ * State a returning client's owed writes on the epoch it joined, now that
2676
+ * the epoch's own content is here (#2816, behavior 17).
2677
+ *
2678
+ * The order is the behavior: what the open epoch holds is noted as conflict
2679
+ * evidence FIRST, so the resolution the replay runs sees the whole online
2680
+ * side — the sealed overlays the catch-up applied and the epoch it landed
2681
+ * on. Only then is the same dropped-delete question asked of it: a delete
2682
+ * this epoch's writes beat leaves a record whose other fields live only in a
2683
+ * base, so that document is rebuilt rather than settled on a row it cannot
2684
+ * state.
2685
+ */
2686
+ private format2SettlePendingReplay;
2687
+ /**
2688
+ * The sealed-epoch chain `epoch.info` described, parsed once.
2689
+ *
2690
+ * The frame is untrusted input, so an entry without a whole epoch number is
2691
+ * dropped rather than turned into `NaN` — a hole in the chain is refused by
2692
+ * the planner, which is the safe outcome; a `NaN` link would not be.
2693
+ */
2694
+ private format2SealedChain;
2695
+ /**
2696
+ * Open a large document the client has no local state for (#2816,
2697
+ * behavior 15).
2698
+ *
2699
+ * A fresh client is not behind — it holds no overlay at all — but on a
2700
+ * document that has rotated, the epoch it would join carries only the recent
2701
+ * changes. So it rebuilds a base first: the latest snapshot when the room
2702
+ * offered one, or the sealed overlays from the first epoch while no build
2703
+ * has completed yet. Either way the sealed overlays after that base are
2704
+ * applied on top, and the move onto the room's epoch resyncs the current
2705
+ * one — so the merged view ends up as the server's `records` table.
2706
+ *
2707
+ * Returns `ok: false` when the document cannot be rebuilt, which stops it
2708
+ * rather than opening a document with holes in it.
2709
+ */
2710
+ private format2ColdStart;
2711
+ /**
2712
+ * Rebuild a large document whose sealed-overlay chain was refused (#2816,
2713
+ * behavior 12's close-out).
2714
+ *
2715
+ * A hole in the chain, an epoch declaring a discontinuous base, or an
2716
+ * archive retention has pruned all mean the same thing: nothing available
2717
+ * turns this client's rows into the room's current state. It is therefore in
2718
+ * the position of a client with no local state — so it plans as one, and
2719
+ * discards the view it cannot repair before loading the base over it. Before
2720
+ * a snapshot loader existed this was a dead stop; it is now a reload.
2721
+ */
2722
+ private format2RebuildFromBase;
2723
+ /** How this document should be rebuilt, from the epoch it counts as holding. */
2724
+ private format2PlanRebuild;
2725
+ /** Run a rebuild plan against this document. */
2726
+ private format2RunRebuild;
2727
+ /**
2728
+ * Fold the open epoch's overlay over the base a cold load just installed
2729
+ * (#2816, behavior 15).
2730
+ *
2731
+ * The open epoch is the part of the document the rebuild does not carry: it
2732
+ * arrives as an ordinary Y.Doc sync, on no schedule relative to the load,
2733
+ * and every snapshot row REPLACES what the merged view held for its record.
2734
+ * So a record patched or deleted in the open epoch comes back as the base's
2735
+ * older row unless the overlay is folded once more at the end — which is
2736
+ * idempotent, an overlay entry being state rather than an operation.
2737
+ */
2738
+ private format2RefoldOverlay;
2739
+ /**
2740
+ * Throw away a merged view a refused chain left beyond repair.
2741
+ *
2742
+ * The rows belong to an epoch the room has left behind, and the base about
2743
+ * to be loaded over them is a set of rows rather than a diff — every record
2744
+ * deleted since would otherwise survive the reload.
2745
+ */
2746
+ private format2DiscardMergedView;
2747
+ /**
2748
+ * Materialize the base snapshot the handshake offered into this document's
2749
+ * merged view (#2816, behavior 15).
2750
+ */
2751
+ private format2LoadSnapshot;
2752
+ /**
2753
+ * Read a snapshot build through the ONE grant the handshake minted for it.
2754
+ *
2755
+ * `{path}` is the manifest and `{path}/{model}/{n}` is a chunk of the same
2756
+ * build (behavior 14). The client never learns an R2 key: it knows a signed
2757
+ * path and, from the manifest, which chunks that build holds.
2758
+ */
2759
+ private format2SnapshotSource;
2760
+ /**
2761
+ * Read one sealed epoch's archived overlay.
2762
+ *
2763
+ * The handshake hands out an origin-relative path carrying an expiring
2764
+ * signature for exactly that artifact (behavior 14) — the room is a Durable
2765
+ * Object and has no reliable idea which host this client reached it through,
2766
+ * while this client knows exactly. No key, and no other credential: the
2767
+ * signature IS the authorization.
2768
+ */
2769
+ private format2FetchArchive;
2770
+ /**
2771
+ * Ask the room for fresh artifact grants, mid-load (#2816).
2772
+ *
2773
+ * The reply is deliberately not an `epoch.info`: that frame is the
2774
+ * handshake, and answering one would re-run the cold-start/catch-up decision
2775
+ * on a document that is in the middle of being rebuilt. This asks for
2776
+ * signatures and nothing else.
2777
+ *
2778
+ * Resolves with what arrived, or `null` when nothing did within the window —
2779
+ * the caller then repeats its read with the grant it already had, which
2780
+ * fails and is reported, rather than waiting on a socket that may be gone.
2781
+ */
2782
+ private format2RefreshGrants;
2783
+ /**
2784
+ * Stop a large document whose overlay belongs to an epoch the room has left
2785
+ * behind (#2816, behavior 10).
2786
+ *
2787
+ * Everything this client could send from here is stale: its overlay holds
2788
+ * epoch-E state the room archived, folded into `records`, and has since
2789
+ * written past. A state-complete sync of it would not fill a gap — it would
2790
+ * overwrite newer authoritative values with older ones, and re-create rows
2791
+ * that were deleted epochs ago. So the document stops syncing and stops
2792
+ * pushing, keeps answering reads from its merged view, and says so with a
2793
+ * typed error. Applying the sealed overlays in between is the fast-forward
2794
+ * path (behavior 12); reloading from a snapshot is Phase 4. Until one of
2795
+ * those exists this is a hard stop, exactly as the plan specifies.
2796
+ */
2797
+ private format2RequireReload;
2798
+ /**
2799
+ * Record that a large document is in touch with the server (#2816,
2800
+ * behavior 18).
2801
+ *
2802
+ * Kept in memory as well as written through, because `epoch.info` — where
2803
+ * the window is reported — arrives before the ORM binds the document and
2804
+ * therefore before there is a record store to persist it into. The note is
2805
+ * flushed at the bind, exactly as the epoch mark is.
2806
+ */
2807
+ private format2NoteSync;
2808
+ /**
2809
+ * Wait for a large document's derived query tables to catch up with its
2810
+ * merged view (#2816).
2811
+ *
2812
+ * Only for format-2 documents: a legacy document has neither a merged view
2813
+ * nor a projection queue, and its update path is unchanged. A failure to
2814
+ * settle is the ORM's to report — it has already logged and withdrawn the
2815
+ * projection mark — and must not turn an applied update into an error here.
2816
+ */
2817
+ private format2SettleProjection;
2818
+ /**
2819
+ * Record the offline window the room reported, without claiming a sync
2820
+ * (#2816, behavior 18).
2821
+ *
2822
+ * `epoch.info` carries the window to every client that reaches the room,
2823
+ * including one that is behind by whole epochs — and that client's merged
2824
+ * view is NOT the room's state until its catch-up has run. Taking the mark
2825
+ * here would hand a document past its window its writes back on the strength
2826
+ * of a handshake whose catch-up then failed: it would go on recording
2827
+ * durable pending ops against a past nothing can reconcile them with. So the
2828
+ * number is taken and the mark is left to be earned, by a catch-up that
2829
+ * lands or by a document that was current all along.
2830
+ */
2831
+ private format2NoteWindow;
2832
+ /**
2833
+ * Measure this client's clock against the room's, and remember when each
2834
+ * sealed epoch ended (#2816, behavior 17).
2835
+ *
2836
+ * Both come off `epoch.info`, and both are needed later than it: the offset
2837
+ * stamps every local write, and the seal times bound the epochs a replay
2838
+ * compares an offline write with.
2839
+ */
2840
+ private format2NoteClock;
2841
+ /**
2842
+ * Resolve what a returning client still owes against what was written while
2843
+ * it was away (#2816, behavior 17, amended D1).
2844
+ *
2845
+ * Used only where a ledger exists — a catch-up has just folded the sealed
2846
+ * overlays that ARE the online side of every conflict. A write the online
2847
+ * side clearly beat is dropped, forgotten from `_pending_ops` so no later
2848
+ * move carries it, and reported; one whose order cannot be established is
2849
+ * kept and reported. A client that was simply present through a seal has no
2850
+ * ledger and carries everything, exactly as before.
2851
+ */
2852
+ private format2ResolveReplay;
2853
+ /**
2854
+ * Whether joining `epoch` would abandon an offline write this client cannot
2855
+ * take back (#2816, behavior 17).
2856
+ *
2857
+ * Asked BEFORE the move, and answered by running the same resolution the
2858
+ * move will run — it reads nothing and writes nothing, so asking twice costs
2859
+ * only the comparison. The one case is a dropped delete: the record it
2860
+ * removed is not in any artifact this client still holds, so the merged view
2861
+ * has to come from a base again before the delete may be forgotten.
2862
+ *
2863
+ * Answers false once a rebuild for this document is already under way, or
2864
+ * the rebuild would ask to be rebuilt out of itself.
2865
+ */
2866
+ private format2ReplayRequiresRebuild;
2867
+ /**
2868
+ * Write a held note through, once the document's store exists.
2869
+ *
2870
+ * A note with no time is a window this client was told about while it was
2871
+ * still behind: the number lands, the mark does not.
2872
+ */
2873
+ private format2FlushSyncNote;
2874
+ /**
2875
+ * Whether a large document is stopped on a superseded epoch, in which case
2876
+ * nothing of its local state may go out (see `format2RequireReload`).
2877
+ */
2878
+ private format2NeedsReload;
2879
+ /**
2880
+ * Run the catch-up a document owes, now that its merged view exists
2881
+ * (#2816, behavior 12).
2882
+ *
2883
+ * Called at the ORM bind and whenever a connection reports a later epoch on
2884
+ * an already-bound document. A document whose chain is REFUSED — a hole, a
2885
+ * discontinuity, a pruned archive — is rebuilt from the latest base instead
2886
+ * of stopped; only a document that cannot be rebuilt either is stopped and
2887
+ * told to reload.
2888
+ */
2889
+ private format2SettleOwedCatchUp;
2890
+ /** The pieces `followEpoch` moves, wired to this client's owners. */
2891
+ private format2RotationHost;
2330
2892
  private handleWebSocketMessage;
2331
2893
  private handleWebSocketClose;
2332
2894
  private handleWebSocketError;
@@ -2995,6 +3557,20 @@ export declare class JsBaoClient extends Observable<any> {
2995
3557
  * the wire on exactly the sessions where storage was slow or unavailable.
2996
3558
  */
2997
3559
  private _primeLocalOnlyFromLocalMetadata;
3560
+ /**
3561
+ * The format of a document being opened (#2816).
3562
+ *
3563
+ * A large document keeps its records in a persisted merged view and uses its
3564
+ * Y.Doc only as an epoch overlay, so js-bao has to be told at connect time —
3565
+ * an app should not have to carry that. The format is chosen at creation and
3566
+ * never migrated, so a locally cached answer is permanently valid and the
3567
+ * server is only asked when nothing local knows (and the answer is then kept
3568
+ * for the next open, which may be offline).
3569
+ *
3570
+ * `resolveDocumentFormat` never rejects: a document nothing knows about
3571
+ * opens as legacy, exactly as it does today.
3572
+ */
3573
+ private _resolveDocumentFormat;
2998
3574
  private _putMetadataToIdb;
2999
3575
  private _deleteMetadataFromIdb;
3000
3576
  private _enforceRetentionPolicy;