@brass-build/client 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (213) hide show
  1. package/AGENTS.md +72 -63
  2. package/CHANGELOG.md +97 -0
  3. package/README.md +325 -235
  4. package/dist/auth-flow.d.ts +10 -1
  5. package/dist/auth-flow.d.ts.map +1 -1
  6. package/dist/auth-flow.js +64 -20
  7. package/dist/auth-flow.js.map +1 -1
  8. package/dist/client.d.ts +4 -0
  9. package/dist/client.d.ts.map +1 -1
  10. package/dist/client.js +245 -76
  11. package/dist/client.js.map +1 -1
  12. package/dist/document-checkpoints.d.ts +1 -0
  13. package/dist/document-checkpoints.d.ts.map +1 -1
  14. package/dist/document-checkpoints.js +27 -0
  15. package/dist/document-checkpoints.js.map +1 -1
  16. package/dist/document-engine.d.ts +4 -0
  17. package/dist/document-engine.d.ts.map +1 -0
  18. package/dist/document-engine.js +9 -0
  19. package/dist/document-engine.js.map +1 -0
  20. package/dist/document-signals.d.ts +31 -1
  21. package/dist/document-signals.d.ts.map +1 -1
  22. package/dist/document-signals.js +59 -0
  23. package/dist/document-signals.js.map +1 -1
  24. package/dist/document-streams.d.ts +8 -1
  25. package/dist/document-streams.d.ts.map +1 -1
  26. package/dist/document-streams.js +79 -8
  27. package/dist/document-streams.js.map +1 -1
  28. package/dist/document-thumbnail-capture.d.ts +20 -0
  29. package/dist/document-thumbnail-capture.d.ts.map +1 -1
  30. package/dist/document-thumbnail-capture.js +247 -9
  31. package/dist/document-thumbnail-capture.js.map +1 -1
  32. package/dist/documents-namespace.d.ts.map +1 -1
  33. package/dist/documents-namespace.js +22 -3
  34. package/dist/documents-namespace.js.map +1 -1
  35. package/dist/documents.d.ts +49 -16
  36. package/dist/documents.d.ts.map +1 -1
  37. package/dist/documents.js +981 -237
  38. package/dist/documents.js.map +1 -1
  39. package/dist/embed-protocol.d.ts +3 -0
  40. package/dist/embed-protocol.d.ts.map +1 -0
  41. package/dist/embed-protocol.js +26 -0
  42. package/dist/embed-protocol.js.map +1 -0
  43. package/dist/emitter.d.ts.map +1 -1
  44. package/dist/emitter.js +8 -1
  45. package/dist/emitter.js.map +1 -1
  46. package/dist/export-guest.d.ts.map +1 -1
  47. package/dist/export-guest.js +14 -6
  48. package/dist/export-guest.js.map +1 -1
  49. package/dist/fetch-deadline.d.ts +22 -0
  50. package/dist/fetch-deadline.d.ts.map +1 -0
  51. package/dist/fetch-deadline.js +96 -0
  52. package/dist/fetch-deadline.js.map +1 -0
  53. package/dist/fetch-retry.d.ts +1 -0
  54. package/dist/fetch-retry.d.ts.map +1 -1
  55. package/dist/fetch-retry.js +12 -5
  56. package/dist/fetch-retry.js.map +1 -1
  57. package/dist/handle-types.d.ts +150 -0
  58. package/dist/handle-types.d.ts.map +1 -0
  59. package/dist/handle-types.js +8 -0
  60. package/dist/handle-types.js.map +1 -0
  61. package/dist/handles.d.ts +48 -48
  62. package/dist/handles.d.ts.map +1 -1
  63. package/dist/handles.js +3122 -501
  64. package/dist/handles.js.map +1 -1
  65. package/dist/hosted-runtime.d.ts.map +1 -1
  66. package/dist/hosted-runtime.js +8 -12
  67. package/dist/hosted-runtime.js.map +1 -1
  68. package/dist/hosted-ui.d.ts +0 -1
  69. package/dist/hosted-ui.d.ts.map +1 -1
  70. package/dist/hosted-ui.js +29 -24
  71. package/dist/hosted-ui.js.map +1 -1
  72. package/dist/importer.d.ts.map +1 -1
  73. package/dist/importer.js +204 -8
  74. package/dist/importer.js.map +1 -1
  75. package/dist/index.d.ts +10 -10
  76. package/dist/index.d.ts.map +1 -1
  77. package/dist/index.js +11 -2
  78. package/dist/index.js.map +1 -1
  79. package/dist/internal.d.ts +2 -1
  80. package/dist/internal.d.ts.map +1 -1
  81. package/dist/internal.js +1 -0
  82. package/dist/internal.js.map +1 -1
  83. package/dist/join-coverage.d.ts +12 -0
  84. package/dist/join-coverage.d.ts.map +1 -0
  85. package/dist/join-coverage.js +37 -0
  86. package/dist/join-coverage.js.map +1 -0
  87. package/dist/jwt.d.ts.map +1 -1
  88. package/dist/jwt.js +5 -1
  89. package/dist/jwt.js.map +1 -1
  90. package/dist/launch-context.js +2 -2
  91. package/dist/launch-context.js.map +1 -1
  92. package/dist/mutate-batching.d.ts +25 -2
  93. package/dist/mutate-batching.d.ts.map +1 -1
  94. package/dist/mutate-batching.js +57 -10
  95. package/dist/mutate-batching.js.map +1 -1
  96. package/dist/open-document.d.ts +30 -1
  97. package/dist/open-document.d.ts.map +1 -1
  98. package/dist/open-document.js +1905 -322
  99. package/dist/open-document.js.map +1 -1
  100. package/dist/presence.d.ts +28 -0
  101. package/dist/presence.d.ts.map +1 -1
  102. package/dist/presence.js +149 -7
  103. package/dist/presence.js.map +1 -1
  104. package/dist/record-paging.d.ts +335 -71
  105. package/dist/record-paging.d.ts.map +1 -1
  106. package/dist/record-paging.js +590 -127
  107. package/dist/record-paging.js.map +1 -1
  108. package/dist/selection-persistence.d.ts.map +1 -1
  109. package/dist/selection-persistence.js +11 -1
  110. package/dist/selection-persistence.js.map +1 -1
  111. package/dist/serializer.d.ts +30 -1
  112. package/dist/serializer.d.ts.map +1 -1
  113. package/dist/session-persistence.d.ts.map +1 -1
  114. package/dist/session-persistence.js +9 -8
  115. package/dist/session-persistence.js.map +1 -1
  116. package/dist/session-toolbar.d.ts +0 -1
  117. package/dist/session-toolbar.d.ts.map +1 -1
  118. package/dist/session-toolbar.js +356 -83
  119. package/dist/session-toolbar.js.map +1 -1
  120. package/dist/session.d.ts.map +1 -1
  121. package/dist/session.js +87 -18
  122. package/dist/session.js.map +1 -1
  123. package/dist/tail-ops.d.ts +14 -4
  124. package/dist/tail-ops.d.ts.map +1 -1
  125. package/dist/tail-ops.js +75 -15
  126. package/dist/tail-ops.js.map +1 -1
  127. package/dist/topic-lifecycle.d.ts +4 -0
  128. package/dist/topic-lifecycle.d.ts.map +1 -1
  129. package/dist/topic-lifecycle.js +25 -1
  130. package/dist/topic-lifecycle.js.map +1 -1
  131. package/dist/types.d.ts +47 -1
  132. package/dist/types.d.ts.map +1 -1
  133. package/dist/undo.d.ts +2 -3
  134. package/dist/undo.d.ts.map +1 -1
  135. package/dist/undo.js +11 -0
  136. package/dist/undo.js.map +1 -1
  137. package/dist/unload-guard.d.ts +5 -0
  138. package/dist/unload-guard.d.ts.map +1 -0
  139. package/dist/unload-guard.js +88 -0
  140. package/dist/unload-guard.js.map +1 -0
  141. package/dist/version-bar.d.ts +4 -3
  142. package/dist/version-bar.d.ts.map +1 -1
  143. package/dist/version-bar.js +162 -20
  144. package/dist/version-bar.js.map +1 -1
  145. package/dist/version.d.ts +2 -2
  146. package/dist/version.js +1 -1
  147. package/dist/vite.d.ts +18 -2
  148. package/dist/vite.d.ts.map +1 -1
  149. package/dist/vite.js +133 -8
  150. package/dist/vite.js.map +1 -1
  151. package/dist/when-saved.d.ts +2 -0
  152. package/dist/when-saved.d.ts.map +1 -0
  153. package/dist/when-saved.js +70 -0
  154. package/dist/when-saved.js.map +1 -0
  155. package/dist/ws-client.d.ts +27 -3
  156. package/dist/ws-client.d.ts.map +1 -1
  157. package/dist/ws-client.js +408 -89
  158. package/dist/ws-client.js.map +1 -1
  159. package/dist/ws-frame-limit.d.ts.map +1 -1
  160. package/dist/ws-frame-limit.js +23 -17
  161. package/dist/ws-frame-limit.js.map +1 -1
  162. package/docs/app-manifest.md +7 -8
  163. package/docs/custom-chrome.md +21 -22
  164. package/docs/hosted-ui-advanced.md +14 -17
  165. package/docs/imported-documents.md +53 -197
  166. package/docs/presence.md +45 -21
  167. package/docs/schemas.md +12 -17
  168. package/docs/streams.md +55 -57
  169. package/package.json +4 -3
  170. package/src/auth-flow.ts +90 -23
  171. package/src/client.ts +262 -80
  172. package/src/document-checkpoints.ts +30 -0
  173. package/src/document-engine.ts +15 -0
  174. package/src/document-signals.ts +120 -8
  175. package/src/document-streams.ts +95 -9
  176. package/src/document-thumbnail-capture.ts +253 -9
  177. package/src/documents-namespace.ts +38 -13
  178. package/src/documents.ts +1103 -290
  179. package/src/embed-protocol.ts +25 -0
  180. package/src/emitter.ts +8 -1
  181. package/src/export-guest.ts +15 -9
  182. package/src/fetch-deadline.ts +119 -0
  183. package/src/fetch-retry.ts +14 -5
  184. package/src/handle-types.ts +303 -0
  185. package/src/handles.ts +3407 -683
  186. package/src/hosted-runtime.ts +8 -12
  187. package/src/hosted-ui.ts +28 -32
  188. package/src/importer.ts +216 -8
  189. package/src/index.ts +29 -18
  190. package/src/internal.ts +7 -0
  191. package/src/join-coverage.ts +42 -0
  192. package/src/jwt.ts +8 -1
  193. package/src/launch-context.ts +2 -2
  194. package/src/mutate-batching.ts +60 -11
  195. package/src/open-document.ts +2441 -502
  196. package/src/presence.ts +210 -11
  197. package/src/record-paging.ts +686 -137
  198. package/src/selection-persistence.ts +10 -1
  199. package/src/serializer.ts +33 -1
  200. package/src/session-persistence.ts +9 -8
  201. package/src/session-toolbar.ts +387 -89
  202. package/src/session.ts +91 -17
  203. package/src/tail-ops.ts +76 -10
  204. package/src/topic-lifecycle.ts +31 -1
  205. package/src/types.ts +56 -4
  206. package/src/undo.ts +13 -5
  207. package/src/unload-guard.ts +91 -0
  208. package/src/version-bar.ts +183 -26
  209. package/src/version.ts +1 -1
  210. package/src/vite.ts +175 -10
  211. package/src/when-saved.ts +66 -0
  212. package/src/ws-client.ts +461 -92
  213. package/src/ws-frame-limit.ts +23 -17
@@ -6,69 +6,222 @@ export declare const BODY_FIELD = "params";
6
6
  export declare const META_KEY = "meta";
7
7
  export declare const RECORDS_KEY = "instances";
8
8
  export declare const ORDER_KEY = "instance_order";
9
- /** `meta` key holding a paged store's page count; absent (or 0) means
10
- * unpaged. The read path detects pages by tag; only an in-place edit needs
11
- * the count, to hash a key to its page. */
12
- export declare const PAGE_COUNT_KEY = "page_count";
13
- /** `meta` key holding the paging codec's scheme number, stamped on a paged
14
- * write. The scheme fixes the page-key hash (`pageKeyFor`), the `p<n>` key
15
- * format, and the packed-record layout together: a reader that hashes a key
16
- * with a different scheme than the store was written under targets the wrong
17
- * page on an in-place edit, silently writing a record into a page it does not
18
- * belong to. The stamp lets a pinned reader detect a store written under a
19
- * scheme it does not implement and refuse the edit instead of corrupting it.
20
- * Absent means the current scheme (paged stores written before the stamp
21
- * existed used scheme 1's hash and layout). */
22
- export declare const PAGING_SCHEME_KEY = "paging_scheme";
23
- /** The paging scheme this build writes and can edit. Bump ONLY alongside a
24
- * change to `pageKeyFor`'s hash, the `p<n>` key format, or the packed-record
25
- * layout, so an older pinned reader trips `isPagingSchemeEditable` and fails
26
- * loud rather than editing a store it would mis-hash. */
27
- export declare const CURRENT_PAGING_SCHEME = 1;
28
- /** Whether a store stamped with `scheme` can be edited in place by this build.
29
- * Absent / non-numeric / `0` is a scheme-1 store (the stamp postdates it), so
30
- * editable; any scheme at or below the current one is editable; a higher
31
- * scheme is not (this reader would hash into the wrong page). Reads stay
32
- * best-effort and are not gated here; only an in-place edit can persist the
33
- * mis-hash, so the edit path is where the guard belongs. */
34
- export declare function isPagingSchemeEditable(scheme: unknown): boolean;
9
+ /** Prefix on the `meta` key marking ONE root map paged (`meta` holds
10
+ * `paged:instances` -> `true`). A root whose key is absent, or holds anything
11
+ * but `true`, is unpaged; a document with no paged root carries no such key.
12
+ *
13
+ * Per root rather than one flag for the document, so paging is a property of
14
+ * a collection rather than of a reserved name. One flag would force the read
15
+ * side to hardcode WHICH root it described, since a document-wide answer
16
+ * handed to every root would make `meta` and `header` read as paged the
17
+ * moment the records did. Keyed by root, a root with no key is simply
18
+ * unpaged, which is the answer those roots want anyway.
19
+ *
20
+ * A key per root rather than one entry naming them all. A map entry is
21
+ * written whole, so an entry holding every paged root is read-modify-write:
22
+ * two peers crossing the threshold on two different roots at once each write
23
+ * the whole entry, the two resolve last-writer-wins, and the root the losing
24
+ * write named is left unmarked. Nothing recovers it. Every reader then takes
25
+ * the unpaged path over a map holding nothing but pages, so the store's own
26
+ * bookkeeping keys read back as the records and the records reach nobody,
27
+ * while the raw entry count sits far below the threshold that would page the
28
+ * root again. A key per root means two roots are two keys, which merge.
29
+ *
30
+ * A flag rather than a page count. Pages are keyed by writing session and
31
+ * index (`brass:p:<peer>:<n>`) and a reader locates a record through the index
32
+ * it builds from the pages' `keys` fields, so no reader needs to know how many
33
+ * pages there are; a stored count would be a number that drifts as the store
34
+ * grows and that nothing checks.
35
+ *
36
+ * A plain value rather than a container: it is read on the hot path
37
+ * (`_isPaged` on every keyed read and edit), where one `get` of a scalar is
38
+ * the cheapest answer available. */
39
+ export declare const PAGED_ROOT_PREFIX = "paged:";
40
+ /** The `meta` key marking `rootKey` paged. */
41
+ export declare function pagedRootKey(rootKey: string): string;
42
+ /** Whether a value read from `meta` at `pagedRootKey(root)` marks that root
43
+ * paged. The one place the marker's stored form is interpreted, so the SDK's
44
+ * handle path and the store readers cannot disagree about what marks a root. */
45
+ export declare function isPagedMarker(marker: unknown): boolean;
35
46
  /** Above this many records the store is written paged; at or below it it keeps
36
- * the one-container-per-record shape. */
37
- export declare const UNPAGED_MAX_RECORDS = 50000;
38
- /** The tag a page container carries in place of a record tag, so a reader
39
- * tells a page (body = record triples) from a single record (body = one
40
- * plain value). */
47
+ * the one-container-per-record shape.
48
+ *
49
+ * Set where paging starts paying for itself on every axis but one. Measured
50
+ * on the two shapes at equal record counts (`scripts/bench/paging-threshold.mts`),
51
+ * the paged store writes ~3x faster, opens ~5x faster, and stores ~1.7x
52
+ * smaller here, against ~1.4x on a single edit, and that last penalty
53
+ * inverts by 25,000 records. Below a few hundred records the paged store is
54
+ * actually LARGER, since per-page gzip overhead outweighs what it saves. */
55
+ export declare const UNPAGED_MAX_RECORDS = 5000;
56
+ /** The tag a page container carries in place of a record tag, which labels it
57
+ * in a raw dump of the stored document. A READER never decides from it: what
58
+ * makes an entry a page is its key (`SESSION_PAGE_PREFIX`), so a record whose
59
+ * own tag happens to be this string is still a record. */
41
60
  export declare const PAGE_TAG = "__page__";
42
- /** A record packed inside a page body: `[key, tag, body]`. The tuple form
43
- * keeps a paged snapshot compact. */
44
- export type PackedRecord<B> = [key: string, tag: string, body: B];
45
- /** Encode a page's triples as its stored body: JSON-serialised, gzipped, held
46
- * as a latin1 string. A STRING body avoids loro's superlinear per-value
47
- * conversion of a deeply nested triple array; gzipping keeps a heavy file in
48
- * memory + export budget. (Full rationale in the substrate's `encodePageBody`.) */
49
- export declare function encodePageBody<B>(triples: PackedRecord<B>[]): string;
50
- /** Encode one record's `[key, tag, body]` triple as the JSON string it
51
- * occupies inside a page body. Split from page assembly so a large write can
61
+ /** Prefix on every key the record store writes for its own bookkeeping: the
62
+ * pages, a record's own container, a delete marker, a patch.
63
+ *
64
+ * A record and the bookkeeping about it share one map, so the two key spaces
65
+ * have to be told apart by something an app cannot produce. The map handle
66
+ * refuses a write under this prefix (`assertUsableRecordKey`), which makes the
67
+ * space exclusive: every key outside it is a record key, and every key inside
68
+ * it is the store's own. Nothing here inspects an app's VALUE to make that
69
+ * call, so no record can be mistaken for a page or a tombstone whatever it
70
+ * holds. */
71
+ export declare const RESERVED_KEY_PREFIX = "brass:";
72
+ /** Whether `key` names one of the store's own entries rather than a record. */
73
+ export declare function isReservedKey(key: string): boolean;
74
+ /** Refuse a record key the store cannot carry, at the moment an app writes it:
75
+ * one inside the reserved space, and `__proto__`.
76
+ *
77
+ * Rejecting the reserved space is what lets every reader decide what an entry
78
+ * is from the key alone. The alternative, escaping, would put the escape on
79
+ * the read of every key of every map, paged or not, and a store that pages
80
+ * later cannot escape what it already holds. */
81
+ export declare function assertUsableRecordKey(key: string): void;
82
+ /** The prefix on a record written as its OWN container in a paged store,
83
+ * which shadows the page's copy on read. A page body is one value, so an
84
+ * edit that rewrote its page would make the page the merge unit; a record in
85
+ * its own container merges on its own. */
86
+ export declare const OVERLAY_PREFIX = "brass:r:";
87
+ /** Pack one stored value into a page triple. A `null` tag is what says the
88
+ * body IS the record: an app's map holds whatever the app assigned, which has
89
+ * no tag to split off. A typed record arrives already split, and its tag is a
90
+ * string, so the two forms cannot be confused whatever the tag says. */
91
+ export declare function packWholeValue<B>(key: string, value: B): PackedRecord<B>;
92
+ /** Re-pack `value` in the same triple shape `packed` already uses, so a page
93
+ * rewritten in place keeps the form its readers expect: a typed record stays
94
+ * a tag beside a body, and an app's stays one whole value. A streaming
95
+ * read visits a page's triples without unpacking them, so a rewrite that
96
+ * changed the shape would hand it the wrong half of the record. */
97
+ export declare function repackRecord(packed: PackedRecord<unknown>, value: unknown): PackedRecord<unknown>;
98
+ /** The stored value a page triple carries: the value itself for a whole-value
99
+ * record, else the `{ type, params }` pair a typed one was split into. */
100
+ export declare function unpackRecord(packed: PackedRecord<unknown>): unknown;
101
+ /** The tag + body a page triple names, for a reader that walks the two
102
+ * separately, or null when the triple packs a whole value that is not a
103
+ * record.
104
+ *
105
+ * A page holds both forms: a typed record is packed as the tag and body it
106
+ * was already split into, and a map an app writes packs whatever the app
107
+ * assigned as one whole value. Both forms occur in ONE store, because an
108
+ * app's bulk add to a store of typed records seals its own pages, so a reader
109
+ * that took `packed[1]` for the tag would report every record those pages
110
+ * hold as having no type at all. */
111
+ export declare function unpackRecordPair(packed: PackedRecord<unknown>): {
112
+ tag: string;
113
+ body: unknown;
114
+ } | null;
115
+ /** The container key a record is written under, beside the pages. */
116
+ export declare function overlayKeyFor(recordKey: string): string;
117
+ /** The marker key standing for a record deleted out of a paged store. */
118
+ export declare function tombstoneKeyFor(recordKey: string): string;
119
+ /** The prefix on a page written by ONE editing session, which fills its pages
120
+ * in creation order.
121
+ *
122
+ * An app fills a map by appending, so a rule that scattered one mutation's
123
+ * records across every page would add a record or two to each of thousands of
124
+ * pages and rewrite every one of them again on the next mutation, which costs
125
+ * more than the per-record containers it replaces. Filling in creation order
126
+ * packs each mutation's records into its own dense pages, written complete
127
+ * and never rewritten.
128
+ *
129
+ * The token makes the key space exclusive to one writer. A page body is a
130
+ * single value, so two writers appending to the same page container resolve
131
+ * last-writer-wins and one writer's records are lost; with a per-session
132
+ * token no two writers ever address the same page. It is also what makes
133
+ * filling in creation order safe on reopen: a session never inherits, and so
134
+ * never rewrites, a page an earlier session sealed. */
135
+ export declare const SESSION_PAGE_PREFIX = "brass:p:";
136
+ /** The container key for page `index` of the session identified by `token`. */
137
+ export declare function sessionPageKey(token: string, index: number): string;
138
+ /** The `{ token, index }` a session page key names, or null for any other key.
139
+ * Used to seed a session's next page index above what the store already
140
+ * holds, so a reopened session cannot overwrite its own sealed pages. */
141
+ export declare function parseSessionPageKey(key: string): {
142
+ token: string;
143
+ index: number;
144
+ } | null;
145
+ /** A record packed inside a page: `[key, tag, body]`, where a `null` tag means
146
+ * the body is the record's WHOLE stored value (`packWholeValue`). The tuple
147
+ * form keeps a paged snapshot compact. It is how a reader HOLDS a page's
148
+ * records; a stored page splits the key off into its own field
149
+ * (`PAGE_KEYS_FIELD`). */
150
+ export type PackedRecord<B> = [key: string, tag: string | null, body: B];
151
+ /** Field on a page container holding the keys of the records its body packs,
152
+ * in the same order, so the two are zipped by index.
153
+ *
154
+ * The keys live apart from the bodies because finding a record in a page
155
+ * filled in creation order (`SESSION_PAGE_PREFIX`) means learning which page
156
+ * holds which key, and that question is answered by the keys alone. Packed
157
+ * beside the bodies, answering it costs decompressing and parsing every
158
+ * record in the store: measured at 250,000 records, 1.85 s against 0.24 s for
159
+ * the keys on their own. Splitting them costs no bytes, since the keys are
160
+ * stored once either way and compress better grouped than interleaved with
161
+ * the bodies. */
162
+ export declare const PAGE_KEYS_FIELD = "keys";
163
+ /** A page's two stored strings: the record bodies and the keys they belong
164
+ * to. */
165
+ export interface EncodedPage {
166
+ body: string;
167
+ keys: string;
168
+ /** The body's size BEFORE gzip, so a writer can charge a page in the same
169
+ * unit an ordinary map assignment is charged in. Taken here because the
170
+ * uncompressed string is built here and nothing else holds it. */
171
+ chars: number;
172
+ }
173
+ /** Encode a page's records as the two strings it stores. Each is JSON,
174
+ * gzipped, held as a latin1 string. A STRING avoids loro's superlinear
175
+ * per-value conversion of a nested array; gzipping keeps a heavy file in
176
+ * memory + export budget. (Full rationale in the substrate's page notes.) */
177
+ export declare function encodePage<B>(records: PackedRecord<B>[]): EncodedPage;
178
+ /** Encode one record's `[tag, body]` pair as the JSON string it occupies
179
+ * inside a page body. Split from page assembly so a large write can
52
180
  * stringify each record as it buckets and release the parsed body before the
53
- * gzip loop, rather than holding the whole parsed model live through it (see
54
- * `writeRecordStoreConsuming` for why that release keeps the encode fast). */
55
- export declare function encodeRecordForPage<B>(key: string, tag: string, body: B): string;
56
- /** Assemble a page body from records already JSON-encoded by
57
- * `encodeRecordForPage`: wrap in a JSON array, gzip, hold as a latin1 string.
58
- * Byte-identical to `encodePageBody` over the same triples, so the wire shape
59
- * is unchanged; the split exists only so the writer frees each parsed body
181
+ * gzip loop: holding a whole parsed model live through that loop makes GC
182
+ * marking scale with the live set and turns the encode into a wall. */
183
+ export declare function encodeRecordForPage<B>(tag: string | null, body: B): string;
184
+ /** Assemble a page from bodies already JSON-encoded by `encodeRecordForPage`
185
+ * and the keys they belong to. Byte-identical to `encodePage` over the same
186
+ * records; the split exists only so the writer frees each parsed body
60
187
  * first. */
61
- export declare function encodePageBodyFromEncoded(encoded: string[]): string;
62
- /** Decode a page body back to its record triples. Returns [] for anything that
63
- * does not decompress to a JSON array, so a reader tolerates a corrupt or
64
- * stray page rather than throwing. */
65
- export declare function decodePageBody(body: unknown): PackedRecord<unknown>[];
66
- /** The page count for a record population: 0 (unpaged) at or below
67
- * `UNPAGED_MAX_RECORDS`, else ~`TARGET_PAGE_SIZE` records per page, capped at
68
- * `MAX_PAGES`. */
69
- export declare function pageCountFor(recordCount: number): number;
70
- /** The page key a record key lives in, for a store of `pageCount` pages. */
71
- export declare function pageKeyFor(key: string, pageCount: number): string;
188
+ export declare function encodePageFromEncoded(encoded: string[], keys: string[]): EncodedPage;
189
+ /** The record keys a page holds, from the page's own `keys` string. Reading
190
+ * this field alone is what makes learning a store's key locations cost the
191
+ * keys rather than every record body. */
192
+ export declare function decodePageKeys(keysField: unknown): string[];
193
+ /** A page's records, zipped back into `[key, tag, body]` triples from the two
194
+ * strings the page stores. A key with no body (or a body with no key) is
195
+ * dropped: the two arrays are written together and index each other, so a
196
+ * length mismatch means a page nothing can read as records. */
197
+ export declare function decodePageRecords(page: unknown): PackedRecord<unknown>[];
198
+ /** Mean JSON bytes of a record body, over a stride sample of at most
199
+ * `WIDTH_SAMPLE` records, which is what `recordsPerPage` sizes a page
200
+ * against. `bodyOf` returns the value the caller will pack as the triple's
201
+ * body: a typed record carries a tag beside a body, and an app's map packs
202
+ * its whole stored value (`packWholeValue`), so each caller weighs the bytes
203
+ * its own pages will hold.
204
+ *
205
+ * Returns 0, which keeps `recordsPerPage`'s plain record-count rule, for an
206
+ * empty population and for a body `JSON.stringify` refuses. Such a body fails
207
+ * the write regardless (a paged write stringifies each record, and loro
208
+ * rejects a non-JSON value), so the catch is not there to rescue it; it is
209
+ * there so that a page-size ESTIMATE is never what decides a write fails, and
210
+ * the failure stays with the code that owns the body. */
211
+ export declare function sampleBodyBytes<T>(records: readonly T[], bodyOf: (record: T) => unknown): number;
212
+ /** Records one page holds: `TARGET_PAGE_SIZE`, or fewer when that many bodies
213
+ * would exceed `TARGET_PAGE_BYTES`. `avgBodyBytes` of 0 or absent (a caller
214
+ * with no estimate) keeps the count rule. */
215
+ export declare function recordsPerPage(avgBodyBytes?: number): number;
216
+ /** How many pages a record population occupies: 0 (unpaged) at or below
217
+ * `UNPAGED_MAX_RECORDS`, else one page per `recordsPerPage(avgBodyBytes)`
218
+ * records.
219
+ *
220
+ * A projection, not a decision the write path takes. Pages are filled in
221
+ * creation order and allocated as a write needs them, so this is what
222
+ * `scripts/bench` uses to price container counts and what the hash-page
223
+ * fixtures use as their bucket modulus. */
224
+ export declare function pageCountFor(recordCount: number, avgBodyBytes?: number): number;
72
225
  /** A stored container's tag (`type`), or null for any value not in the
73
226
  * `{ type, params }` shape, so a reader skips a corrupt entry. A page carries
74
227
  * `PAGE_TAG`. */
@@ -79,21 +232,132 @@ export declare function decodeRecordValue(value: unknown): {
79
232
  tag: string;
80
233
  body: unknown;
81
234
  } | null;
82
- /** Whether a `meta.page_count` value denotes a PAGED store. The writer sets
83
- * it to a positive count only when it pages, and never on an unpaged write,
84
- * so a positive finite number is the authoritative "is paged" signal. */
85
- export declare function isPagedByPageCount(pageCount: unknown): boolean;
235
+ /** Prefix of a RECORD PATCH: the fields one edit changed, applied over the
236
+ * record's page copy on read.
237
+ *
238
+ * Giving an edited record a container of its own instead restores the
239
+ * per-container cost paging exists to remove, so a store whose records are
240
+ * all eventually edited ends up slower and larger than one that never paged.
241
+ * A patch keeps the record packed and costs one entry per edit rather than a
242
+ * container per edited record.
243
+ *
244
+ * The key carries the writing peer and a counter. The peer is what lets the
245
+ * patches be FOLDED back into their pages later without a lock: a CRDT delete
246
+ * only defeats a CONCURRENT write to the same key, and no two writers can
247
+ * name the same key while the peer is in it, so a peer editing during
248
+ * another's fold writes a key that fold never saw. A writer that re-mints a
249
+ * key it folded away itself is ordered after its own delete, so that write is
250
+ * not the race either.
251
+ *
252
+ * The counter orders the patches on ONE record, and is minted one above every
253
+ * counter that record already carries. That is what makes the fold causal: a
254
+ * patch written by someone who had already merged an earlier patch sorts
255
+ * above it, whoever wrote which. A counter that instead counted the WRITER's
256
+ * edits would put a busy session's first-ever edit of a record above a later
257
+ * session's, and the later edit would vanish as it was made.
258
+ *
259
+ * The record key goes last because it may contain a colon; the peer and
260
+ * counter may not.
261
+ *
262
+ * Each reserved space differs from its siblings at the character after
263
+ * `RESERVED_KEY_PREFIX`, so `classifyStoreKey` decides between them with one
264
+ * test each and no ordering to get right. */
265
+ export declare const PATCH_PREFIX = "brass:q:";
266
+ export declare function patchKeyFor(recordKey: string, peer: string, counter: number): string;
267
+ export interface ParsedPatchKey {
268
+ recordKey: string;
269
+ peer: string;
270
+ counter: string;
271
+ }
272
+ /** What one entry of a paged map is, decided from its key alone.
273
+ *
274
+ * `record` is the ordinary case: every key outside the reserved space names a
275
+ * record, whatever its value holds. `unknown` is a reserved key this build
276
+ * does not recognise, which a reader skips rather than reporting as a record,
277
+ * so a store written by a later build degrades to missing entries instead of
278
+ * entries named after the store's own bookkeeping. */
279
+ export type StoreEntryKind = {
280
+ kind: 'record';
281
+ recordKey: string;
282
+ } | {
283
+ kind: 'page';
284
+ } | {
285
+ kind: 'overlay';
286
+ recordKey: string;
287
+ } | {
288
+ kind: 'tombstone';
289
+ recordKey: string;
290
+ } | {
291
+ kind: 'patch';
292
+ parsed: ParsedPatchKey;
293
+ } | {
294
+ kind: 'unknown';
295
+ };
296
+ /** Classify one key of a paged map. The single place the key spaces are told
297
+ * apart, so a keyed read, a whole-store read, a streaming read, and the page
298
+ * index cannot disagree about which entry is which. */
299
+ export declare function classifyStoreKey(key: string): StoreEntryKind;
300
+ /** The parts of a patch key, or null when `key` is not one.
301
+ *
302
+ * The record key runs to the end of the string and may be empty, which is a
303
+ * record key like any other: the two colons after the prefix delimit the peer
304
+ * and the counter, so the tail needs no length of its own to be
305
+ * unambiguous. Reading an empty tail as "not a patch" instead leaves the
306
+ * entry classified `unknown`, which every reader skips, so the edit stays in
307
+ * the document and reaches nobody. */
308
+ export declare function parsePatchKey(key: string): ParsedPatchKey | null;
309
+ /** One patch: the fields an edit changed, plus the pair that orders it. */
310
+ export interface RecordPatch {
311
+ peer: string;
312
+ counter: string;
313
+ fields: unknown;
314
+ }
315
+ /** Apply `patches` over `base`, in the order every reader must agree on: by
316
+ * counter, then by peer id. The counter is per record and minted one above
317
+ * what that record already carries, so a patch whose writer had merged an
318
+ * earlier one applies over it. Peer id breaks the tie between two writers who
319
+ * had not seen each other, so both reach the same answer. */
320
+ export declare function applyRecordPatches(base: unknown, patches: RecordPatch[]): unknown;
321
+ /**
322
+ * Apply patches to a record a streaming read carries both as its whole stored
323
+ * value and as the `(tag, body)` pair split out of it, and return all three
324
+ * after the fold.
325
+ *
326
+ * A patch names the record's own fields, which for a typed record are
327
+ * `type` and `params` together, so a reader that walks tag and body
328
+ * separately has to re-split the result. Both readers of a paged store
329
+ * (the flattening one and the streaming one) resolve patches through this
330
+ * module, so an edit cannot read one way in the editor and another in a
331
+ * re-emitted file. The fold runs over the whole value for the same reason the
332
+ * streaming read carries one: a field beyond the pair is a field of the record
333
+ * and an edit may name it.
334
+ */
335
+ export declare function applyPatchesToRecord(record: unknown, tag: string, body: unknown, patches: RecordPatch[]): {
336
+ tag: string;
337
+ body: unknown;
338
+ record: unknown;
339
+ };
340
+ /** Where a paged store keeps each record, reported as a flatten resolves it.
341
+ * A reader that has to locate records by key (a keyed read over pages filled
342
+ * in creation order) takes its index from the walk that decodes the pages
343
+ * anyway, rather than decoding them a second time of its own. */
344
+ export interface RecordLocationSink {
345
+ /** `recordKey` is packed in the body of page `pageKey`. */
346
+ page(recordKey: string, pageKey: string): void;
347
+ /** A container of its own answers for `recordKey`, outranking any page. */
348
+ contained(recordKey: string): void;
349
+ /** A tombstone removes `recordKey`, whatever a page still holds. */
350
+ removed(recordKey: string): void;
351
+ }
86
352
  /** Flatten a possibly-PAGED `instances` lookup to the flat
87
353
  * `key -> { type, params }` lookup a reader consumes. An unpaged lookup is
88
354
  * returned unchanged (no allocation). The single place paging is undone on the
89
355
  * read side.
90
356
  *
91
- * `paged` is the AUTHORITATIVE page state, read from `meta.page_count` by the
92
- * caller (`isPagedByPageCount`). Page interpretation MUST be gated on it, not
93
- * on whether some entry is `PAGE_TAG`-tagged: a genuine record whose codec tag
94
- * happens to equal `PAGE_TAG` in an UNPAGED store is a real record, not a
95
- * page. Treating it as a page decodes its plain body as `decodePageBody`
96
- * (which returns `[]` for a non-page body), silently DROPPING the record, and
97
- * a crafted page-shaped body could forge records into the lookup. */
98
- export declare function flattenPagedLookup(lookup: Record<string, unknown>, paged: boolean): Record<string, unknown>;
357
+ * `paged` is the AUTHORITATIVE page state, read from the root's own `meta`
358
+ * key by the caller (`pagedRootKey` / `isPagedMarker`). Page interpretation
359
+ * MUST be gated on it: in an UNPAGED store every key is a record key,
360
+ * including one that looks reserved, because nothing refused it before the
361
+ * store was written. */
362
+ export declare function flattenPagedLookup(lookup: Record<string, unknown>, paged: boolean, into?: RecordLocationSink): Record<string, unknown>;
99
363
  //# sourceMappingURL=record-paging.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"record-paging.d.ts","sourceRoot":"","sources":["../src/record-paging.ts"],"names":[],"mappings":"AAmEA;wEACwE;AACxE,eAAO,MAAM,SAAS,SAAS,CAAC;AAChC,eAAO,MAAM,UAAU,WAAW,CAAC;AAEnC,mEAAmE;AACnE,eAAO,MAAM,QAAQ,SAAS,CAAC;AAC/B,eAAO,MAAM,WAAW,cAAc,CAAC;AACvC,eAAO,MAAM,SAAS,mBAAmB,CAAC;AAE1C;;4CAE4C;AAC5C,eAAO,MAAM,cAAc,eAAe,CAAC;AAE3C;;;;;;;;gDAQgD;AAChD,eAAO,MAAM,iBAAiB,kBAAkB,CAAC;AAEjD;;;0DAG0D;AAC1D,eAAO,MAAM,qBAAqB,IAAI,CAAC;AAEvC;;;;;6DAK6D;AAC7D,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAK/D;AAED;0CAC0C;AAC1C,eAAO,MAAM,mBAAmB,QAAS,CAAC;AAQ1C;;oBAEoB;AACpB,eAAO,MAAM,QAAQ,aAAa,CAAC;AAEnC;sCACsC;AACtC,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AAElE;;;oFAGoF;AACpF,wBAAgB,cAAc,CAAC,CAAC,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,CAEpE;AAED;;;;+EAI+E;AAC/E,wBAAgB,mBAAmB,CAAC,CAAC,EACnC,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,CAAC,GACN,MAAM,CAER;AAED;;;;aAIa;AACb,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,CAEnE;AAED;;uCAEuC;AACvC,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC,EAAE,CASrE;AAED;;mBAEmB;AACnB,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAGxD;AAeD,4EAA4E;AAC5E,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED;;kBAEkB;AAClB,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAI3D;AAED;kDACkD;AAClD,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,OAAO,GACb;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAMvC;AAED;;0EAE0E;AAC1E,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,OAAO,GAAG,OAAO,CAE9D;AAED;;;;;;;;;;;sEAWsE;AACtE,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,KAAK,EAAE,OAAO,GACb,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAyBzB"}
1
+ {"version":3,"file":"record-paging.d.ts","sourceRoot":"","sources":["../src/record-paging.ts"],"names":[],"mappings":"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"}