@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
package/dist/tail-ops.js CHANGED
@@ -14,33 +14,93 @@ import { BrassError } from './errors.js';
14
14
  function isUrlOp(op) {
15
15
  return typeof op.op_blob_url === 'string';
16
16
  }
17
+ /**
18
+ * What the spilled entries in this tail say they will cost to fetch.
19
+ *
20
+ * Read before any of them is fetched, so a load can state the whole of what it
21
+ * is about to download rather than discovering it. An entry naming no size
22
+ * counts zero, which understates the total: a bar that finishes early is a
23
+ * worse answer than one that never moves, and a much better one than a bar
24
+ * that goes backwards when the rest arrives.
25
+ */
26
+ export function declaredTailBytes(tailOps) {
27
+ let total = 0;
28
+ for (const op of tailOps) {
29
+ if (!isUrlOp(op))
30
+ continue;
31
+ const declared = op.op_blob_bytes;
32
+ if (typeof declared === 'number' && declared > 0)
33
+ total += declared;
34
+ }
35
+ return total;
36
+ }
37
+ /**
38
+ * How many spilled ops a join fetches at once.
39
+ *
40
+ * A browser refuses to open an unbounded number of sockets: past a few
41
+ * hundred in flight it fails the rest of them outright with
42
+ * `ERR_INSUFFICIENT_RESOURCES`, which arrives as a rejected fetch and
43
+ * fails the whole join. Chrome's own per-host cap is 6, so a higher bound
44
+ * here only queues inside the browser; this is low enough to stay clear of
45
+ * the failure and high enough that the queue drains at the connection
46
+ * limit rather than the loop's.
47
+ */
48
+ const TAIL_FETCH_CONCURRENCY = 8;
17
49
  /**
18
50
  * Fetch any tail op whose bytes live behind a signed URL, leaving inline
19
51
  * ops untouched, and return the tail in its original order.
20
52
  *
21
- * Ordering matters and concurrency does not disturb it: the fetches run
22
- * together but each result lands back at its own index, so the caller
23
- * still applies ops in ascending seq.
53
+ * Ordering matters and concurrency does not disturb it: each result lands
54
+ * back at its own index, so the caller still applies ops in ascending seq.
24
55
  *
25
56
  * A failed fetch throws rather than dropping the op. Skipping one would
26
57
  * leave the reader a document missing an edit it will never be sent
27
58
  * again, which reads as data loss; failing the join sends it back through
28
59
  * a path that can succeed.
29
60
  */
30
- export async function resolveTailOps(tailOps, fetchImpl = fetch) {
31
- if (!tailOps.some(isUrlOp)) {
61
+ export async function resolveTailOps(tailOps, fetchImpl = fetch,
62
+ // Told how many BYTES of the spilled ops are in hand, as each lands. A
63
+ // document whose tail spilled fetches hundreds of objects here, eight at a
64
+ // time, inside the join and before anything else reports: without this the
65
+ // whole stretch is silent, and a load that is working looks exactly like one
66
+ // that has hung.
67
+ //
68
+ // Bytes rather than objects because this is half of one download, not a
69
+ // stage of its own. The snapshot that follows is measured in bytes, and a
70
+ // reader watching a load has no use for the distinction between an op that
71
+ // spilled and the snapshot it will be folded into.
72
+ onProgress) {
73
+ const spilled = tailOps.filter(isUrlOp).length;
74
+ if (spilled === 0) {
32
75
  return tailOps;
33
76
  }
34
- return Promise.all(tailOps.map(async (op) => {
35
- if (!isUrlOp(op))
36
- return op;
37
- // The URL is pre-signed, so it carries no Brass headers: adding one
38
- // would fall outside the signature and be refused.
39
- const response = await fetchImpl(op.op_blob_url, { method: 'GET' });
40
- if (!response.ok) {
41
- throw new BrassError('Tail op fetch failed', { status: response.status });
77
+ const out = Array.from({ length: tailOps.length });
78
+ let loadedBytes = 0;
79
+ onProgress?.(0);
80
+ let next = 0;
81
+ const worker = async () => {
82
+ for (;;) {
83
+ const i = next++;
84
+ if (i >= tailOps.length)
85
+ return;
86
+ const op = tailOps[i];
87
+ if (!isUrlOp(op)) {
88
+ out[i] = op;
89
+ continue;
90
+ }
91
+ // The URL is pre-signed, so it carries no Brass headers: adding one
92
+ // would fall outside the signature and be refused.
93
+ const response = await fetchImpl(op.op_blob_url, { method: 'GET' });
94
+ if (!response.ok) {
95
+ throw new BrassError('Tail op fetch failed', { status: response.status });
96
+ }
97
+ const body = await response.text();
98
+ out[i] = { seq: op.seq, op_blob_b64: body };
99
+ loadedBytes += body.length;
100
+ onProgress?.(loadedBytes);
42
101
  }
43
- return { seq: op.seq, op_blob_b64: await response.text() };
44
- }));
102
+ };
103
+ await Promise.all(Array.from({ length: Math.min(TAIL_FETCH_CONCURRENCY, tailOps.length) }, () => worker()));
104
+ return out;
45
105
  }
46
106
  //# sourceMappingURL=tail-ops.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tail-ops.js","sourceRoot":"","sources":["../src/tail-ops.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,EAAE;AACF,oEAAoE;AACpE,yEAAyE;AACzE,sEAAsE;AACtE,sEAAsE;AACtE,uBAAuB;AACvB,EAAE;AACF,qEAAqE;AACrE,wEAAwE;AACxE,uEAAuE;AACvE,yCAAyC;AAEzC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAazC,SAAS,OAAO,CAAC,EAAc;IAC7B,OAAO,OAAQ,EAAgC,CAAC,WAAW,KAAK,QAAQ,CAAC;AAC3E,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAA8B,EAC9B,YAA0B,KAAK;IAE/B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3B,OAAO,OAA2B,CAAC;IACrC,CAAC;IACD,OAAO,OAAO,CAAC,GAAG,CAChB,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;QACvB,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YAAE,OAAO,EAAE,CAAC;QAC5B,oEAAoE;QACpE,mDAAmD;QACnD,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,EAAE,CAAC,WAAW,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QACpE,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,UAAU,CAAC,sBAAsB,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QAC5E,CAAC;QACD,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;IAC7D,CAAC,CAAC,CACH,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"tail-ops.js","sourceRoot":"","sources":["../src/tail-ops.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,EAAE;AACF,oEAAoE;AACpE,yEAAyE;AACzE,sEAAsE;AACtE,sEAAsE;AACtE,uBAAuB;AACvB,EAAE;AACF,qEAAqE;AACrE,wEAAwE;AACxE,uEAAuE;AACvE,yCAAyC;AAEzC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAiBzC,SAAS,OAAO,CAAC,EAAc;IAC7B,OAAO,OAAQ,EAAgC,CAAC,WAAW,KAAK,QAAQ,CAAC;AAC3E,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAA8B;IAC9D,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,EAAE,IAAI,OAAO,EAAE,CAAC;QACzB,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YAAE,SAAS;QAC3B,MAAM,QAAQ,GAAI,EAAkC,CAAC,aAAa,CAAC;QACnE,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,GAAG,CAAC;YAAE,KAAK,IAAI,QAAQ,CAAC;IACtE,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,sBAAsB,GAAG,CAAC,CAAC;AAEjC;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAA8B,EAC9B,YAA0B,KAAK;AAC/B,uEAAuE;AACvE,2EAA2E;AAC3E,2EAA2E;AAC3E,6EAA6E;AAC7E,iBAAiB;AACjB,EAAE;AACF,wEAAwE;AACxE,0EAA0E;AAC1E,2EAA2E;AAC3E,mDAAmD;AACnD,UAA0C;IAE1C,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;IAC/C,IAAI,OAAO,KAAK,CAAC,EAAE,CAAC;QAClB,OAAO,OAA2B,CAAC;IACrC,CAAC;IACD,MAAM,GAAG,GAAqB,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACrE,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC;IAChB,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,MAAM,MAAM,GAAG,KAAK,IAAmB,EAAE;QACvC,SAAS,CAAC;YACR,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC;YACjB,IAAI,CAAC,IAAI,OAAO,CAAC,MAAM;gBAAE,OAAO;YAChC,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,CAAE,CAAC;YACvB,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC;gBACjB,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;gBACZ,SAAS;YACX,CAAC;YACD,oEAAoE;YACpE,mDAAmD;YACnD,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,EAAE,CAAC,WAAW,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;YACpE,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,IAAI,UAAU,CAAC,sBAAsB,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;YAC5E,CAAC;YACD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACnC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;YAC5C,WAAW,IAAI,IAAI,CAAC,MAAM,CAAC;YAC3B,UAAU,EAAE,CAAC,WAAW,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC,CAAC;IACF,MAAM,OAAO,CAAC,GAAG,CACf,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,sBAAsB,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,CAC5E,MAAM,EAAE,CACT,CACF,CAAC;IACF,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -28,6 +28,9 @@ export type TopicEffect = {
28
28
  kind: 'drop_held';
29
29
  } | {
30
30
  kind: 'drop_listeners';
31
+ } | {
32
+ kind: 'deliver_error';
33
+ reason: string;
31
34
  } | {
32
35
  kind: 'fire_error';
33
36
  reason: string;
@@ -37,5 +40,6 @@ export interface StepResult {
37
40
  effects: TopicEffect[];
38
41
  }
39
42
  export declare function holdsFrames(state: TopicState): boolean;
43
+ export declare function isFrameScopedReason(reason: string): boolean;
40
44
  export declare function step(state: TopicState, event: TopicEvent): StepResult;
41
45
  //# sourceMappingURL=topic-lifecycle.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"topic-lifecycle.d.ts","sourceRoot":"","sources":["../src/topic-lifecycle.ts"],"names":[],"mappings":"AAwBA,MAAM,MAAM,UAAU,GAClB,MAAM,GACN,aAAa,GACb,aAAa,GACb,UAAU,GACV,UAAU,CAAC;AAEf,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,UAAU,CAAC;IAGlB,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,eAAO,MAAM,UAAU,EAAE,UAAiD,CAAC;AAE3E,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAC1B;IAAE,IAAI,EAAE,kBAAkB,CAAA;CAAE,GAC5B;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,GACzB;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAC1B;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtC,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAC1B;IAAE,IAAI,EAAE,kBAAkB,CAAA;CAAE,GAE5B;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,GACtB;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GAGrB;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAC1B;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3C,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,UAAU,CAAC;IAClB,OAAO,EAAE,WAAW,EAAE,CAAC;CACxB;AAKD,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAEtD;AAqCD,wBAAgB,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,GAAG,UAAU,CA8GrE"}
1
+ {"version":3,"file":"topic-lifecycle.d.ts","sourceRoot":"","sources":["../src/topic-lifecycle.ts"],"names":[],"mappings":"AA6BA,MAAM,MAAM,UAAU,GAClB,MAAM,GACN,aAAa,GACb,aAAa,GACb,UAAU,GACV,UAAU,CAAC;AAEf,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,UAAU,CAAC;IAGlB,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,eAAO,MAAM,UAAU,EAAE,UAAiD,CAAC;AAE3E,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAC1B;IAAE,IAAI,EAAE,kBAAkB,CAAA;CAAE,GAC5B;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,GACzB;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAC1B;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtC,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAC1B;IAAE,IAAI,EAAE,kBAAkB,CAAA;CAAE,GAE5B;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,GACtB;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GAGrB;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAI1B;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACzC;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3C,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,UAAU,CAAC;IAClB,OAAO,EAAE,WAAW,EAAE,CAAC;CACxB;AAKD,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAEtD;AAMD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE3D;AAyCD,wBAAgB,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,GAAG,UAAU,CAuHrE"}
@@ -17,20 +17,35 @@
17
17
  // `retrySpent` survives into a same-connection re-subscribe so the
18
18
  // retry stays one-per-topic-per-connection.
19
19
  //
20
+ // A frame-scoped reason (`isFrameScopedReason`) is the exception to all of
21
+ // that: it describes the frame the server could not process, not the
22
+ // subscription it arrived on, so every live phase keeps its state and hands
23
+ // the error to the topic's callbacks, which hold the frame that drew it.
24
+ //
20
25
  // Invariant: every transition into `tornDown` emits `send_unsubscribe`,
21
26
  // so no server-side subscription row can outlive the client-side state
22
27
  // (an orphan row would have its `last_seen` kept fresh by the heartbeat,
23
28
  // making it immune to the server's stale reaper).
24
29
  export const IDLE_TOPIC = { phase: 'idle', retrySpent: false };
25
30
  // True while topic-scoped frames must be held back: sending before the
26
- // `subscribed` ack races the server's SUB# row write and draws a spurious
31
+ // `subscribed` ack races the server's subscription record write and draws a spurious
27
32
  // `forbidden`.
28
33
  export function holdsFrames(state) {
29
34
  return state.phase === 'subscribing' || state.phase === 'retrying';
30
35
  }
36
+ // True for a reason that judges one frame rather than the subscription.
37
+ // `unavailable` answers a durable op write the server was authorised to
38
+ // take and could not store right now, so the topic stays up and the writer
39
+ // re-sends the op.
40
+ export function isFrameScopedReason(reason) {
41
+ return reason === 'unavailable';
42
+ }
31
43
  const SEND_SUBSCRIBE = { kind: 'send_subscribe' };
32
44
  const FLUSH_HELD = { kind: 'flush_held' };
33
45
  const DROP_HELD = { kind: 'drop_held' };
46
+ function deliverError(state, reason) {
47
+ return { state, effects: [{ kind: 'deliver_error', reason }] };
48
+ }
34
49
  // Rejection / spent-retry teardown. `send_unsubscribe` releases any
35
50
  // server-side row a completed retry may have re-created (the invariant in
36
51
  // the header); `unsubscribe` is idempotent server-side, so sending it when
@@ -77,6 +92,9 @@ export function step(state, event) {
77
92
  effects: [FLUSH_HELD],
78
93
  };
79
94
  case 'error':
95
+ if (isFrameScopedReason(event.reason)) {
96
+ return deliverError(state, event.reason);
97
+ }
80
98
  // Never established on this connection: the rejection is final.
81
99
  return tearDown(state, event.reason);
82
100
  case 'socket_open':
@@ -92,6 +110,9 @@ export function step(state, event) {
92
110
  case 'established':
93
111
  switch (event.type) {
94
112
  case 'error':
113
+ if (isFrameScopedReason(event.reason)) {
114
+ return deliverError(state, event.reason);
115
+ }
95
116
  // A mid-stream `not_subscribed` is an eviction (the server
96
117
  // dropped the subscription row while this client stayed alive,
97
118
  // e.g. a presence reap that raced a live-but-quiet connection),
@@ -121,6 +142,9 @@ export function step(state, event) {
121
142
  case 'retrying':
122
143
  switch (event.type) {
123
144
  case 'error':
145
+ if (isFrameScopedReason(event.reason)) {
146
+ return deliverError(state, event.reason);
147
+ }
124
148
  // An eviction draws errors for EVERY frame in flight against the
125
149
  // reaped row; the trailing ones land while the retry's subscribe
126
150
  // is unacked and describe frames that predate it, so the retry
@@ -1 +1 @@
1
- {"version":3,"file":"topic-lifecycle.js","sourceRoot":"","sources":["../src/topic-lifecycle.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"topic-lifecycle.js","sourceRoot":"","sources":["../src/topic-lifecycle.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { HostedUiTheme } from './hosted-ui.js';
1
2
  export interface BrassUser {
2
3
  sub: string;
3
4
  email?: string;
@@ -9,7 +10,7 @@ export interface BrassInitOptions {
9
10
  apiBaseUrl?: string;
10
11
  wsBaseUrl?: string;
11
12
  dashboardBaseUrl?: string;
12
- hostedUiTheme?: 'light' | 'dark' | 'auto';
13
+ hostedUiTheme?: HostedUiTheme;
13
14
  openIncompatibleDocuments?: boolean;
14
15
  syncDocToUrl?: boolean;
15
16
  docUrlParam?: string;
@@ -19,4 +20,49 @@ export interface BrassInitOptions {
19
20
  export type AuthStatus = 'unknown' | 'signed-in' | 'signed-out' | 'guest';
20
21
  export type UserChangeListener = (user: BrassUser | null) => void;
21
22
  export type ErrorListener = (error: Error) => void;
23
+ export interface UndoControllerOptions {
24
+ maxUndoSteps?: number;
25
+ }
26
+ /**
27
+ * A document's own view of how its sync is going, as the client sees it.
28
+ *
29
+ * The server records what reached it, so the facts that separate a write
30
+ * that was lost from a client that is merely slow live only here. Read it
31
+ * when a save is taking longer than it should; `Brass.onError` reports
32
+ * failures, and this reports the state a failure has not yet been declared
33
+ * for.
34
+ */
35
+ export interface DocSyncDiagnostics {
36
+ /** Ops committed locally that the server has not acknowledged. */
37
+ unackedOps: number;
38
+ /** How long the oldest of them has been waiting, in ms. 0 when none. */
39
+ oldestUnackedMs: number;
40
+ /**
41
+ * The oldest unacked op's correlator. The same id rides the op to the
42
+ * server, so it is what an operator matches a stuck save against the
43
+ * server's record of the write.
44
+ */
45
+ oldestClientOpId: string | null;
46
+ /**
47
+ * Sockets the SDK has opened since it was constructed, past the first.
48
+ * Every open document shares one socket, so this is a fact about the
49
+ * client rather than about this document, and it counts a deliberate
50
+ * close and re-open alongside a drop.
51
+ */
52
+ reconnects: number;
53
+ /**
54
+ * Since any acknowledgement landed on this socket, in ms, or null when
55
+ * none ever has. A connection answering nothing and one merely behind
56
+ * look the same from a single op's age; this is what tells them apart.
57
+ */
58
+ lastAckAgeMs: number | null;
59
+ /** Bytes on the socket against the transport's in-flight budget. */
60
+ inFlightBytes: number;
61
+ /** Ops too large for the socket, travelling over HTTP right now. */
62
+ httpOpsInFlight: number;
63
+ /** Rounds the durability handshake has spent reconciling. */
64
+ healRounds: number;
65
+ /** Whether the page is hidden, which throttles the client's timers. */
66
+ hidden: boolean;
67
+ }
22
68
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAI/B,WAAW,CAAC,EAAE,MAAM,CAAC;IAGrB,UAAU,CAAC,EAAE,MAAM,CAAC;IAOpB,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAK1B,aAAa,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;IAM1C,yBAAyB,CAAC,EAAE,OAAO,CAAC;IAOpC,YAAY,CAAC,EAAE,OAAO,CAAC;IAGvB,WAAW,CAAC,EAAE,MAAM,CAAC;IAGrB,cAAc,CAAC,EAAE,MAAM,CAAC;IAOxB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAWD,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,WAAW,GAAG,YAAY,GAAG,OAAO,CAAC;AAE1E,MAAM,MAAM,kBAAkB,GAAG,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,KAAK,IAAI,CAAC;AAKlE,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpD,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAI/B,WAAW,CAAC,EAAE,MAAM,CAAC;IAGrB,UAAU,CAAC,EAAE,MAAM,CAAC;IAOpB,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAK1B,aAAa,CAAC,EAAE,aAAa,CAAC;IAM9B,yBAAyB,CAAC,EAAE,OAAO,CAAC;IAQpC,YAAY,CAAC,EAAE,OAAO,CAAC;IAGvB,WAAW,CAAC,EAAE,MAAM,CAAC;IAGrB,cAAc,CAAC,EAAE,MAAM,CAAC;IAOxB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAWD,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,WAAW,GAAG,YAAY,GAAG,OAAO,CAAC;AAE1E,MAAM,MAAM,kBAAkB,GAAG,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,KAAK,IAAI,CAAC;AAKlE,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;AAEnD,MAAM,WAAW,qBAAqB;IAGpC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,kBAAkB;IACjC,kEAAkE;IAClE,UAAU,EAAE,MAAM,CAAC;IACnB,wEAAwE;IACxE,eAAe,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC;;;;;OAKG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,oEAAoE;IACpE,aAAa,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,eAAe,EAAE,MAAM,CAAC;IACxB,6DAA6D;IAC7D,UAAU,EAAE,MAAM,CAAC;IACnB,uEAAuE;IACvE,MAAM,EAAE,OAAO,CAAC;CACjB"}
package/dist/undo.d.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import { type LoroDoc } from 'loro-crdt';
2
- export interface UndoControllerOptions {
3
- maxUndoSteps?: number;
4
- }
2
+ import type { UndoControllerOptions } from './types.js';
3
+ export declare const PAGING_COMMIT_ORIGIN = "brass.paging";
5
4
  export declare class UndoController {
6
5
  private readonly _mgr;
7
6
  private _groupOpen;
@@ -1 +1 @@
1
- {"version":3,"file":"undo.d.ts","sourceRoot":"","sources":["../src/undo.ts"],"names":[],"mappings":"AAIA,OAAO,EAAe,KAAK,OAAO,EAAE,MAAM,WAAW,CAAC;AAkBtD,MAAM,WAAW,qBAAqB;IAGpC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAID,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAc;IAOnC,OAAO,CAAC,UAAU,CAAS;gBAEf,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,qBAAqB;IAgB7D,IAAI,IAAI,OAAO;IAIf,IAAI,IAAI,OAAO;IAIf,OAAO,CAAC,YAAY;IAapB,OAAO,IAAI,OAAO;IAIlB,OAAO,IAAI,OAAO;IASlB,QAAQ,IAAI,IAAI;IAWhB,KAAK,IAAI,IAAI;IAYb,IAAI,IAAI,IAAI;CAWb"}
1
+ {"version":3,"file":"undo.d.ts","sourceRoot":"","sources":["../src/undo.ts"],"names":[],"mappings":"AAIA,OAAO,EAAe,KAAK,OAAO,EAAE,MAAM,WAAW,CAAC;AAEtD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AA2BxD,eAAO,MAAM,oBAAoB,iBAAiB,CAAC;AAInD,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAc;IAOnC,OAAO,CAAC,UAAU,CAAS;gBAEf,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,qBAAqB;IAiB7D,IAAI,IAAI,OAAO;IAIf,IAAI,IAAI,OAAO;IAIf,OAAO,CAAC,YAAY;IAapB,OAAO,IAAI,OAAO;IAIlB,OAAO,IAAI,OAAO;IASlB,QAAQ,IAAI,IAAI;IAWhB,KAAK,IAAI,IAAI;IAYb,IAAI,IAAI,IAAI;CAWb"}
package/dist/undo.js CHANGED
@@ -17,6 +17,16 @@ const UNDO_MERGE_INTERVAL_MS = 0;
17
17
  // Cap on retained undo steps (Loro's default is 100). 200 at typical AEC
18
18
  // entity sizes is a few hundred KB, well below anything that matters.
19
19
  const DEFAULT_MAX_UNDO_STEPS = 200;
20
+ // Commit origin the paged marker (`meta.paged:<root>`) is stamped with, and
21
+ // the one origin the undo stack ignores.
22
+ //
23
+ // The marker says which shape a root's records are stored in, so it is a fact
24
+ // about the store rather than a step the reader took: undoing it leaves the
25
+ // pages the crossing mutation sealed behind a marker that says unpaged, which
26
+ // every reader answers by handing back the page entries themselves. The write
27
+ // that carries it therefore commits alone, so nothing an app authored is
28
+ // excluded alongside it.
29
+ export const PAGING_COMMIT_ORIGIN = 'brass.paging';
20
30
  // Thin wrapper around Loro's UndoManager exposing only what the Document
21
31
  // needs. Owned by the Document; not part of the public SDK surface.
22
32
  export class UndoController {
@@ -32,6 +42,7 @@ export class UndoController {
32
42
  this._mgr = new UndoManager(loroDoc, {
33
43
  mergeInterval: UNDO_MERGE_INTERVAL_MS,
34
44
  maxUndoSteps: options?.maxUndoSteps ?? DEFAULT_MAX_UNDO_STEPS,
45
+ excludeOriginPrefixes: [PAGING_COMMIT_ORIGIN],
35
46
  });
36
47
  // Open the implicit group so commits before the first `createCheckpoint`
37
48
  // still bracket as one undo step.
package/dist/undo.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"undo.js","sourceRoot":"","sources":["../src/undo.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"undo.js","sourceRoot":"","sources":["../src/undo.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export interface UnloadTarget {
2
+ addEventListener(type: 'beforeunload', listener: (e: Event) => void): void;
3
+ removeEventListener(type: 'beforeunload', listener: (e: Event) => void): void;
4
+ }
5
+ //# sourceMappingURL=unload-guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unload-guard.d.ts","sourceRoot":"","sources":["../src/unload-guard.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,YAAY;IAC3B,gBAAgB,CAAC,IAAI,EAAE,cAAc,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAAC;IAC3E,mBAAmB,CAAC,IAAI,EAAE,cAAc,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAAC;CAC/E"}
@@ -0,0 +1,88 @@
1
+ // Native "leave site?" confirmation while a document holds ops the server
2
+ // has not acked. Reloading or navigating away drops those ops with the tab,
3
+ // so the browser's own prompt is the last point at which the writer can
4
+ // choose to stay.
5
+ //
6
+ // One registry rather than a listener per document: several documents can be
7
+ // open at once (and one the app has closed can still be parked in the SDK's
8
+ // cache with ops in flight), while the prompt is a property of the page. The
9
+ // registry keys on the owning Document so a count only ever leaves when that
10
+ // document acks its ops or closes, and the listener is attached only while
11
+ // the total is above zero. A permanently attached listener prompts on every
12
+ // navigation, which teaches readers to dismiss it.
13
+ const outstandingByOwner = new Map();
14
+ let handler = null;
15
+ // The target the handler is attached to, so a detach cannot go to a
16
+ // different one than the attach did.
17
+ let attachedTo = null;
18
+ // `undefined` means "resolve from the environment"; a test overrides it with
19
+ // a fake target, or with `null` to stand in for a non-browser host.
20
+ let targetOverride;
21
+ function resolveTarget() {
22
+ if (targetOverride !== undefined)
23
+ return targetOverride;
24
+ const candidate = globalThis.window;
25
+ if (typeof candidate !== 'object' || candidate === null)
26
+ return null;
27
+ const target = candidate;
28
+ if (typeof target.addEventListener !== 'function')
29
+ return null;
30
+ if (typeof target.removeEventListener !== 'function')
31
+ return null;
32
+ return target;
33
+ }
34
+ function sync() {
35
+ let total = 0;
36
+ for (const count of outstandingByOwner.values())
37
+ total += count;
38
+ if (total === 0) {
39
+ if (handler && attachedTo) {
40
+ attachedTo.removeEventListener('beforeunload', handler);
41
+ }
42
+ handler = null;
43
+ attachedTo = null;
44
+ return;
45
+ }
46
+ if (handler)
47
+ return;
48
+ const target = resolveTarget();
49
+ if (!target)
50
+ return;
51
+ handler = (e) => {
52
+ // `preventDefault` is the whole signal. Browsers show their own wording
53
+ // and ignore anything the handler returns or assigns.
54
+ e.preventDefault();
55
+ };
56
+ attachedTo = target;
57
+ target.addEventListener('beforeunload', handler);
58
+ }
59
+ // Report how many un-acked ops `owner` holds. Zero forgets it.
60
+ /** @internal */
61
+ export function trackUnsavedWork(owner, count) {
62
+ if (count > 0)
63
+ outstandingByOwner.set(owner, count);
64
+ else
65
+ outstandingByOwner.delete(owner);
66
+ sync();
67
+ }
68
+ // Forget `owner` entirely, whatever it last reported. Called from
69
+ // `Document.close()`, where the ops go away with the document.
70
+ /** @internal */
71
+ export function releaseUnsavedWork(owner) {
72
+ if (!outstandingByOwner.delete(owner))
73
+ return;
74
+ sync();
75
+ }
76
+ // Point the guard at a fake target and drop every tracked owner, so one
77
+ // test's documents cannot hold the listener open across the next.
78
+ /** @internal */
79
+ export function _setUnloadTargetForTesting(target) {
80
+ if (handler && attachedTo) {
81
+ attachedTo.removeEventListener('beforeunload', handler);
82
+ }
83
+ handler = null;
84
+ attachedTo = null;
85
+ outstandingByOwner.clear();
86
+ targetOverride = target;
87
+ }
88
+ //# sourceMappingURL=unload-guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unload-guard.js","sourceRoot":"","sources":["../src/unload-guard.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,4EAA4E;AAC5E,wEAAwE;AACxE,kBAAkB;AAClB,EAAE;AACF,6EAA6E;AAC7E,4EAA4E;AAC5E,6EAA6E;AAC7E,6EAA6E;AAC7E,2EAA2E;AAC3E,4EAA4E;AAC5E,mDAAmD;AAOnD,MAAM,kBAAkB,GAAG,IAAI,GAAG,EAAkB,CAAC;AACrD,IAAI,OAAO,GAAgC,IAAI,CAAC;AAChD,oEAAoE;AACpE,qCAAqC;AACrC,IAAI,UAAU,GAAwB,IAAI,CAAC;AAC3C,6EAA6E;AAC7E,oEAAoE;AACpE,IAAI,cAA+C,CAAC;AAEpD,SAAS,aAAa;IACpB,IAAI,cAAc,KAAK,SAAS;QAAE,OAAO,cAAc,CAAC;IACxD,MAAM,SAAS,GAAI,UAAmC,CAAC,MAAM,CAAC;IAC9D,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,SAAS,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACrE,MAAM,MAAM,GAAG,SAAkC,CAAC;IAClD,IAAI,OAAO,MAAM,CAAC,gBAAgB,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IAC/D,IAAI,OAAO,MAAM,CAAC,mBAAmB,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IAClE,OAAO,MAAsB,CAAC;AAChC,CAAC;AAED,SAAS,IAAI;IACX,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,KAAK,IAAI,kBAAkB,CAAC,MAAM,EAAE;QAAE,KAAK,IAAI,KAAK,CAAC;IAEhE,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;QAChB,IAAI,OAAO,IAAI,UAAU,EAAE,CAAC;YAC1B,UAAU,CAAC,mBAAmB,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;QAC1D,CAAC;QACD,OAAO,GAAG,IAAI,CAAC;QACf,UAAU,GAAG,IAAI,CAAC;QAClB,OAAO;IACT,CAAC;IACD,IAAI,OAAO;QAAE,OAAO;IACpB,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;IAC/B,IAAI,CAAC,MAAM;QAAE,OAAO;IACpB,OAAO,GAAG,CAAC,CAAQ,EAAQ,EAAE;QAC3B,wEAAwE;QACxE,sDAAsD;QACtD,CAAC,CAAC,cAAc,EAAE,CAAC;IACrB,CAAC,CAAC;IACF,UAAU,GAAG,MAAM,CAAC;IACpB,MAAM,CAAC,gBAAgB,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;AACnD,CAAC;AAED,+DAA+D;AAC/D,gBAAgB;AAChB,MAAM,UAAU,gBAAgB,CAAC,KAAa,EAAE,KAAa;IAC3D,IAAI,KAAK,GAAG,CAAC;QAAE,kBAAkB,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;;QAC/C,kBAAkB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACtC,IAAI,EAAE,CAAC;AACT,CAAC;AAED,kEAAkE;AAClE,+DAA+D;AAC/D,gBAAgB;AAChB,MAAM,UAAU,kBAAkB,CAAC,KAAa;IAC9C,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,KAAK,CAAC;QAAE,OAAO;IAC9C,IAAI,EAAE,CAAC;AACT,CAAC;AAED,wEAAwE;AACxE,kEAAkE;AAClE,gBAAgB;AAChB,MAAM,UAAU,0BAA0B,CACxC,MAAuC;IAEvC,IAAI,OAAO,IAAI,UAAU,EAAE,CAAC;QAC1B,UAAU,CAAC,mBAAmB,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,GAAG,IAAI,CAAC;IACf,UAAU,GAAG,IAAI,CAAC;IAClB,kBAAkB,CAAC,KAAK,EAAE,CAAC;IAC3B,cAAc,GAAG,MAAM,CAAC;AAC1B,CAAC"}
@@ -1,11 +1,11 @@
1
1
  export interface VersionBarDeps {
2
2
  dashboardBaseUrl: string;
3
3
  theme?: 'light' | 'dark' | 'auto';
4
- getSessionToken?: () => string | null | undefined;
5
- checkoutVersion: (version: number) => void;
6
- returnToHead: () => void;
4
+ checkoutVersion: (version: number) => Promise<void>;
5
+ returnToHead: () => Promise<void>;
7
6
  fork: (fromVersion: number, name?: string) => void;
8
7
  browse: () => void;
8
+ currentVersion: () => number | null;
9
9
  close: () => void;
10
10
  }
11
11
  export interface VersionBarContext {
@@ -13,6 +13,7 @@ export interface VersionBarContext {
13
13
  branch: string | undefined;
14
14
  version: number | null;
15
15
  branchName?: string | undefined;
16
+ pinned?: boolean;
16
17
  }
17
18
  export interface VersionBarFrame {
18
19
  update(ctx: VersionBarContext): void;
@@ -1 +1 @@
1
- {"version":3,"file":"version-bar.d.ts","sourceRoot":"","sources":["../src/version-bar.ts"],"names":[],"mappings":"AAyBA,MAAM,WAAW,cAAc;IAG7B,gBAAgB,EAAE,MAAM,CAAC;IAEzB,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;IAGlC,eAAe,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAElD,eAAe,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,IAAI,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,MAAM,EAAE,MAAM,IAAI,CAAC;IAInB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAG3B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAGvB,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC;AAED,MAAM,WAAW,eAAe;IAI9B,MAAM,CAAC,GAAG,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACrC,OAAO,IAAI,IAAI,CAAC;CACjB;AAOD,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,WAAW,EACjB,IAAI,EAAE,cAAc,GACnB,eAAe,CAoJjB"}
1
+ {"version":3,"file":"version-bar.d.ts","sourceRoot":"","sources":["../src/version-bar.ts"],"names":[],"mappings":"AAmCA,MAAM,WAAW,cAAc;IAG7B,gBAAgB,EAAE,MAAM,CAAC;IAEzB,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;IAIlC,eAAe,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,YAAY,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,IAAI,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,MAAM,EAAE,MAAM,IAAI,CAAC;IAInB,cAAc,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IAIpC,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAG3B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAGvB,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAIhC,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAI9B,MAAM,CAAC,GAAG,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACrC,OAAO,IAAI,IAAI,CAAC;CACjB;AAWD,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,WAAW,EACjB,IAAI,EAAE,cAAc,GACnB,eAAe,CA4RjB"}