@brass-build/client 0.1.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 (258) hide show
  1. package/AGENTS.md +255 -0
  2. package/CHANGELOG.md +15 -0
  3. package/LICENSE +21 -0
  4. package/README.md +836 -0
  5. package/dist/api-fetch.d.ts +16 -0
  6. package/dist/api-fetch.d.ts.map +1 -0
  7. package/dist/api-fetch.js +97 -0
  8. package/dist/api-fetch.js.map +1 -0
  9. package/dist/api-headers.d.ts +3 -0
  10. package/dist/api-headers.d.ts.map +1 -0
  11. package/dist/api-headers.js +25 -0
  12. package/dist/api-headers.js.map +1 -0
  13. package/dist/auth-flow.d.ts +23 -0
  14. package/dist/auth-flow.d.ts.map +1 -0
  15. package/dist/auth-flow.js +76 -0
  16. package/dist/auth-flow.js.map +1 -0
  17. package/dist/client.d.ts +106 -0
  18. package/dist/client.d.ts.map +1 -0
  19. package/dist/client.js +1278 -0
  20. package/dist/client.js.map +1 -0
  21. package/dist/doc-url-sync.d.ts +19 -0
  22. package/dist/doc-url-sync.d.ts.map +1 -0
  23. package/dist/doc-url-sync.js +181 -0
  24. package/dist/doc-url-sync.js.map +1 -0
  25. package/dist/document-branches.d.ts +32 -0
  26. package/dist/document-branches.d.ts.map +1 -0
  27. package/dist/document-branches.js +89 -0
  28. package/dist/document-branches.js.map +1 -0
  29. package/dist/document-checkpoints.d.ts +24 -0
  30. package/dist/document-checkpoints.d.ts.map +1 -0
  31. package/dist/document-checkpoints.js +115 -0
  32. package/dist/document-checkpoints.js.map +1 -0
  33. package/dist/document-commands.d.ts +93 -0
  34. package/dist/document-commands.d.ts.map +1 -0
  35. package/dist/document-commands.js +423 -0
  36. package/dist/document-commands.js.map +1 -0
  37. package/dist/document-signals.d.ts +53 -0
  38. package/dist/document-signals.d.ts.map +1 -0
  39. package/dist/document-signals.js +114 -0
  40. package/dist/document-signals.js.map +1 -0
  41. package/dist/document-streams.d.ts +22 -0
  42. package/dist/document-streams.d.ts.map +1 -0
  43. package/dist/document-streams.js +98 -0
  44. package/dist/document-streams.js.map +1 -0
  45. package/dist/document-thumbnail-capture.d.ts +27 -0
  46. package/dist/document-thumbnail-capture.d.ts.map +1 -0
  47. package/dist/document-thumbnail-capture.js +160 -0
  48. package/dist/document-thumbnail-capture.js.map +1 -0
  49. package/dist/documents-namespace.d.ts +134 -0
  50. package/dist/documents-namespace.d.ts.map +1 -0
  51. package/dist/documents-namespace.js +190 -0
  52. package/dist/documents-namespace.js.map +1 -0
  53. package/dist/documents.d.ts +146 -0
  54. package/dist/documents.d.ts.map +1 -0
  55. package/dist/documents.js +2045 -0
  56. package/dist/documents.js.map +1 -0
  57. package/dist/emitter.d.ts +15 -0
  58. package/dist/emitter.d.ts.map +1 -0
  59. package/dist/emitter.js +90 -0
  60. package/dist/emitter.js.map +1 -0
  61. package/dist/errors.d.ts +18 -0
  62. package/dist/errors.d.ts.map +1 -0
  63. package/dist/errors.js +22 -0
  64. package/dist/errors.js.map +1 -0
  65. package/dist/export-guest.d.ts +9 -0
  66. package/dist/export-guest.d.ts.map +1 -0
  67. package/dist/export-guest.js +225 -0
  68. package/dist/export-guest.js.map +1 -0
  69. package/dist/fetch-retry.d.ts +16 -0
  70. package/dist/fetch-retry.d.ts.map +1 -0
  71. package/dist/fetch-retry.js +90 -0
  72. package/dist/fetch-retry.js.map +1 -0
  73. package/dist/guest-link.d.ts +3 -0
  74. package/dist/guest-link.d.ts.map +1 -0
  75. package/dist/guest-link.js +13 -0
  76. package/dist/guest-link.js.map +1 -0
  77. package/dist/handles.d.ts +57 -0
  78. package/dist/handles.d.ts.map +1 -0
  79. package/dist/handles.js +1375 -0
  80. package/dist/handles.js.map +1 -0
  81. package/dist/hosted-runtime.d.ts +33 -0
  82. package/dist/hosted-runtime.d.ts.map +1 -0
  83. package/dist/hosted-runtime.js +99 -0
  84. package/dist/hosted-runtime.js.map +1 -0
  85. package/dist/hosted-ui.d.ts +84 -0
  86. package/dist/hosted-ui.d.ts.map +1 -0
  87. package/dist/hosted-ui.js +673 -0
  88. package/dist/hosted-ui.js.map +1 -0
  89. package/dist/importer.d.ts +22 -0
  90. package/dist/importer.d.ts.map +1 -0
  91. package/dist/importer.js +54 -0
  92. package/dist/importer.js.map +1 -0
  93. package/dist/index.d.ts +54 -0
  94. package/dist/index.d.ts.map +1 -0
  95. package/dist/index.js +132 -0
  96. package/dist/index.js.map +1 -0
  97. package/dist/init-keys.d.ts +3 -0
  98. package/dist/init-keys.d.ts.map +1 -0
  99. package/dist/init-keys.js +13 -0
  100. package/dist/init-keys.js.map +1 -0
  101. package/dist/internal.d.ts +6 -0
  102. package/dist/internal.d.ts.map +1 -0
  103. package/dist/internal.js +17 -0
  104. package/dist/internal.js.map +1 -0
  105. package/dist/jwt.d.ts +3 -0
  106. package/dist/jwt.d.ts.map +1 -0
  107. package/dist/jwt.js +22 -0
  108. package/dist/jwt.js.map +1 -0
  109. package/dist/launch-context.d.ts +4 -0
  110. package/dist/launch-context.d.ts.map +1 -0
  111. package/dist/launch-context.js +44 -0
  112. package/dist/launch-context.js.map +1 -0
  113. package/dist/login-hint.d.ts +4 -0
  114. package/dist/login-hint.d.ts.map +1 -0
  115. package/dist/login-hint.js +63 -0
  116. package/dist/login-hint.js.map +1 -0
  117. package/dist/mutate-batching.d.ts +14 -0
  118. package/dist/mutate-batching.d.ts.map +1 -0
  119. package/dist/mutate-batching.js +65 -0
  120. package/dist/mutate-batching.js.map +1 -0
  121. package/dist/open-document.d.ts +127 -0
  122. package/dist/open-document.d.ts.map +1 -0
  123. package/dist/open-document.js +2121 -0
  124. package/dist/open-document.js.map +1 -0
  125. package/dist/page-title.d.ts +3 -0
  126. package/dist/page-title.d.ts.map +1 -0
  127. package/dist/page-title.js +32 -0
  128. package/dist/page-title.js.map +1 -0
  129. package/dist/perf.d.ts +9 -0
  130. package/dist/perf.d.ts.map +1 -0
  131. package/dist/perf.js +39 -0
  132. package/dist/perf.js.map +1 -0
  133. package/dist/presence.d.ts +62 -0
  134. package/dist/presence.d.ts.map +1 -0
  135. package/dist/presence.js +331 -0
  136. package/dist/presence.js.map +1 -0
  137. package/dist/record-paging.d.ts +99 -0
  138. package/dist/record-paging.d.ts.map +1 -0
  139. package/dist/record-paging.js +220 -0
  140. package/dist/record-paging.js.map +1 -0
  141. package/dist/schema-conflict-dialog.d.ts +10 -0
  142. package/dist/schema-conflict-dialog.d.ts.map +1 -0
  143. package/dist/schema-conflict-dialog.js +164 -0
  144. package/dist/schema-conflict-dialog.js.map +1 -0
  145. package/dist/selection-persistence.d.ts +5 -0
  146. package/dist/selection-persistence.d.ts.map +1 -0
  147. package/dist/selection-persistence.js +90 -0
  148. package/dist/selection-persistence.js.map +1 -0
  149. package/dist/serializer.d.ts +3 -0
  150. package/dist/serializer.d.ts.map +1 -0
  151. package/dist/serializer.js +2 -0
  152. package/dist/serializer.js.map +1 -0
  153. package/dist/session-persistence.d.ts +4 -0
  154. package/dist/session-persistence.d.ts.map +1 -0
  155. package/dist/session-persistence.js +68 -0
  156. package/dist/session-persistence.js.map +1 -0
  157. package/dist/session-toolbar.d.ts +62 -0
  158. package/dist/session-toolbar.d.ts.map +1 -0
  159. package/dist/session-toolbar.js +1205 -0
  160. package/dist/session-toolbar.js.map +1 -0
  161. package/dist/session.d.ts +69 -0
  162. package/dist/session.d.ts.map +1 -0
  163. package/dist/session.js +926 -0
  164. package/dist/session.js.map +1 -0
  165. package/dist/tail-ops.d.ts +28 -0
  166. package/dist/tail-ops.d.ts.map +1 -0
  167. package/dist/tail-ops.js +46 -0
  168. package/dist/tail-ops.js.map +1 -0
  169. package/dist/topic-lifecycle.d.ts +41 -0
  170. package/dist/topic-lifecycle.d.ts.map +1 -0
  171. package/dist/topic-lifecycle.js +169 -0
  172. package/dist/topic-lifecycle.js.map +1 -0
  173. package/dist/types.d.ts +22 -0
  174. package/dist/types.d.ts.map +1 -0
  175. package/dist/types.js +2 -0
  176. package/dist/types.js.map +1 -0
  177. package/dist/undo.d.ts +18 -0
  178. package/dist/undo.d.ts.map +1 -0
  179. package/dist/undo.js +110 -0
  180. package/dist/undo.js.map +1 -0
  181. package/dist/version-bar.d.ts +22 -0
  182. package/dist/version-bar.d.ts.map +1 -0
  183. package/dist/version-bar.js +169 -0
  184. package/dist/version-bar.js.map +1 -0
  185. package/dist/version.d.ts +3 -0
  186. package/dist/version.d.ts.map +1 -0
  187. package/dist/version.js +8 -0
  188. package/dist/version.js.map +1 -0
  189. package/dist/vite.d.ts +15 -0
  190. package/dist/vite.d.ts.map +1 -0
  191. package/dist/vite.js +36 -0
  192. package/dist/vite.js.map +1 -0
  193. package/dist/ws-client.d.ts +53 -0
  194. package/dist/ws-client.d.ts.map +1 -0
  195. package/dist/ws-client.js +604 -0
  196. package/dist/ws-client.js.map +1 -0
  197. package/dist/ws-frame-limit.d.ts +21 -0
  198. package/dist/ws-frame-limit.d.ts.map +1 -0
  199. package/dist/ws-frame-limit.js +40 -0
  200. package/dist/ws-frame-limit.js.map +1 -0
  201. package/docs/app-manifest.md +65 -0
  202. package/docs/custom-chrome.md +147 -0
  203. package/docs/hosted-ui-advanced.md +77 -0
  204. package/docs/imported-documents.md +261 -0
  205. package/docs/presence.md +129 -0
  206. package/docs/schemas.md +135 -0
  207. package/docs/streams.md +248 -0
  208. package/package.json +60 -0
  209. package/scripts/prepare.mjs +50 -0
  210. package/src/api-fetch.ts +127 -0
  211. package/src/api-headers.ts +28 -0
  212. package/src/auth-flow.ts +125 -0
  213. package/src/client.ts +1457 -0
  214. package/src/doc-url-sync.ts +183 -0
  215. package/src/document-branches.ts +124 -0
  216. package/src/document-checkpoints.ts +135 -0
  217. package/src/document-commands.ts +651 -0
  218. package/src/document-signals.ts +234 -0
  219. package/src/document-streams.ts +132 -0
  220. package/src/document-thumbnail-capture.ts +191 -0
  221. package/src/documents-namespace.ts +516 -0
  222. package/src/documents.ts +2426 -0
  223. package/src/emitter.ts +129 -0
  224. package/src/errors.ts +45 -0
  225. package/src/export-guest.ts +282 -0
  226. package/src/fetch-retry.ts +119 -0
  227. package/src/guest-link.ts +14 -0
  228. package/src/handles.ts +1731 -0
  229. package/src/hosted-runtime.ts +109 -0
  230. package/src/hosted-ui.ts +1020 -0
  231. package/src/importer.ts +89 -0
  232. package/src/index.ts +267 -0
  233. package/src/init-keys.ts +15 -0
  234. package/src/internal.ts +23 -0
  235. package/src/jwt.ts +18 -0
  236. package/src/launch-context.ts +43 -0
  237. package/src/login-hint.ts +60 -0
  238. package/src/mutate-batching.ts +63 -0
  239. package/src/open-document.ts +2869 -0
  240. package/src/page-title.ts +33 -0
  241. package/src/perf.ts +46 -0
  242. package/src/presence.ts +471 -0
  243. package/src/record-paging.ts +270 -0
  244. package/src/schema-conflict-dialog.ts +176 -0
  245. package/src/selection-persistence.ts +98 -0
  246. package/src/serializer.ts +15 -0
  247. package/src/session-persistence.ts +69 -0
  248. package/src/session-toolbar.ts +1457 -0
  249. package/src/session.ts +1262 -0
  250. package/src/tail-ops.ts +63 -0
  251. package/src/topic-lifecycle.ts +217 -0
  252. package/src/types.ts +75 -0
  253. package/src/undo.ts +125 -0
  254. package/src/version-bar.ts +221 -0
  255. package/src/version.ts +8 -0
  256. package/src/vite.ts +49 -0
  257. package/src/ws-client.ts +678 -0
  258. package/src/ws-frame-limit.ts +52 -0
@@ -0,0 +1,221 @@
1
+ // The parent (SDK) half of the version-preview bar's iframe bridge.
2
+ //
3
+ // Unlike the hosted dialogs (`hosted-ui.ts`, a modal open -> result ->
4
+ // close), this mounts the platform-served `/embed/version-bar` page INLINE
5
+ // as a persistent strip and keeps a long-lived, bidirectional channel open
6
+ // for the whole preview. The platform owns the bar's UI and features
7
+ // (Prev / Next, browse, branch-from); the SDK stays a thin router of the
8
+ // embed's intents to the active Document's internal methods, so the bar can
9
+ // grow with no SDK or app change.
10
+ //
11
+ // Bridge protocol (shared envelope `__brass_embed: 1`):
12
+ // host -> iframe: init{surface,params} | version-changed{version}
13
+ // iframe -> host: ready | resize{height} | preview{version}
14
+ // | return-to-head | fork{fromVersion} | browse
15
+ // | error{code,message}
16
+
17
+ const ENVELOPE = '__brass_embed';
18
+ const PROTOCOL_VERSION = 1;
19
+ // Collapsed until the embed reports `ready`, so the load moment shows a
20
+ // themed placeholder strip rather than an empty white iframe (no flash, no
21
+ // layout jump: the placeholder reserves the strip's height).
22
+ const READY_HEIGHT = 44;
23
+ const MIN_HEIGHT = 32;
24
+ const MAX_HEIGHT = 200;
25
+
26
+ export interface VersionBarDeps {
27
+ // The resolved dashboard/embed origin (no trailing slash); the iframe
28
+ // loads `${dashboardBaseUrl}/embed/version-bar`.
29
+ dashboardBaseUrl: string;
30
+ // Pins the embed's light/dark theme (matches the other hosted surfaces).
31
+ theme?: 'light' | 'dark' | 'auto';
32
+ // The fallback platform-session pointer, handed to the embed so it can
33
+ // authenticate when its framed cookie is blocked (incognito / Safari ITP).
34
+ getSessionToken?: () => string | null | undefined;
35
+ // Intents from the embed, routed to the live active document.
36
+ checkoutVersion: (version: number) => void;
37
+ returnToHead: () => void;
38
+ fork: (fromVersion: number, name?: string) => void;
39
+ browse: () => void;
40
+ // Dismiss the bar. The bar stays open through the whole browsing session
41
+ // (including once returned to the live head), so it is closed only by the
42
+ // user's explicit "Close", never as a side effect of navigation.
43
+ close: () => void;
44
+ }
45
+
46
+ export interface VersionBarContext {
47
+ docId: string;
48
+ branch: string | undefined;
49
+ // The previewed version, or `null` when the bar is open at the live head
50
+ // (the browsing session has returned to latest but not been closed).
51
+ version: number | null;
52
+ // The active branch's display name when on a non-default branch, else
53
+ // undefined. The bar composes a branch-from-version's initial name from it.
54
+ branchName?: string | undefined;
55
+ }
56
+
57
+ export interface VersionBarFrame {
58
+ // Set or update the previewed context. A version change on the same
59
+ // document pushes `version-changed`; a document / branch change re-inits
60
+ // (the embed's `init` is one-shot, so the frame is recreated).
61
+ update(ctx: VersionBarContext): void;
62
+ destroy(): void;
63
+ }
64
+
65
+ function clampHeight(h: number): number {
66
+ if (!Number.isFinite(h)) return READY_HEIGHT;
67
+ return Math.max(MIN_HEIGHT, Math.min(MAX_HEIGHT, Math.round(h)));
68
+ }
69
+
70
+ export function createVersionBarFrame(
71
+ root: HTMLElement,
72
+ deps: VersionBarDeps,
73
+ ): VersionBarFrame {
74
+ const origin = new URL(deps.dashboardBaseUrl).origin;
75
+ const base = deps.dashboardBaseUrl.replace(/\/$/, '');
76
+ const theme = deps.theme ?? 'light';
77
+
78
+ // A themed placeholder strip shown until the embed is ready, so the bar
79
+ // occupies its height immediately (graceful load, no flash).
80
+ const placeholder = document.createElement('div');
81
+ placeholder.className = 'b-version-loading';
82
+ placeholder.textContent = 'Loading version controls...';
83
+
84
+ const iframe = document.createElement('iframe');
85
+ const url = new URL(`${base}/embed/version-bar`);
86
+ url.searchParams.set('theme', theme);
87
+ iframe.src = url.toString();
88
+ iframe.title = 'Document version';
89
+ Object.assign(iframe.style, {
90
+ display: 'block',
91
+ border: '0',
92
+ width: '100%',
93
+ height: '0',
94
+ colorScheme: theme === 'auto' ? 'light dark' : theme,
95
+ background: 'transparent',
96
+ } satisfies Partial<CSSStyleDeclaration>);
97
+
98
+ root.append(placeholder, iframe);
99
+
100
+ let ctx: VersionBarContext | null = null;
101
+ let ready = false;
102
+ // The version last delivered to the embed (via `init` or `version-changed`).
103
+ // The host re-renders on many events (a commit, a saving-count bump, ...),
104
+ // each calling `update`, but only an ACTUAL version change should reach the
105
+ // embed. Posting on every render would flood the bar with echoes and let a
106
+ // stale one clobber its optimistic state; `undefined` = nothing delivered yet.
107
+ let deliveredVersion: number | null | undefined = undefined;
108
+
109
+ function postInit(): void {
110
+ const sid = deps.getSessionToken?.();
111
+ if (!ctx) return;
112
+ iframe.contentWindow?.postMessage(
113
+ {
114
+ [ENVELOPE]: PROTOCOL_VERSION,
115
+ type: 'init',
116
+ surface: 'version-bar',
117
+ params: {
118
+ docId: ctx.docId,
119
+ ...(ctx.branch !== undefined ? { branch: ctx.branch } : {}),
120
+ version: ctx.version,
121
+ ...(ctx.branchName !== undefined ? { branchName: ctx.branchName } : {}),
122
+ ...(sid ? { sessionToken: sid } : {}),
123
+ },
124
+ },
125
+ origin,
126
+ );
127
+ deliveredVersion = ctx.version;
128
+ }
129
+
130
+ function onMessage(event: MessageEvent): void {
131
+ if (event.origin !== origin) return;
132
+ if (event.source !== iframe.contentWindow) return;
133
+ const data = event.data as Record<string, unknown> | null;
134
+ if (!data || data[ENVELOPE] !== PROTOCOL_VERSION) return;
135
+ switch (data['type']) {
136
+ case 'ready': {
137
+ ready = true;
138
+ placeholder.style.display = 'none';
139
+ iframe.style.height = `${READY_HEIGHT}px`;
140
+ postInit();
141
+ break;
142
+ }
143
+ case 'resize': {
144
+ const h = data['height'];
145
+ if (typeof h === 'number') iframe.style.height = `${clampHeight(h)}px`;
146
+ break;
147
+ }
148
+ case 'preview': {
149
+ const v = data['version'];
150
+ if (typeof v === 'number' && Number.isInteger(v) && v >= 0) {
151
+ deps.checkoutVersion(v);
152
+ }
153
+ break;
154
+ }
155
+ case 'return-to-head': {
156
+ deps.returnToHead();
157
+ break;
158
+ }
159
+ case 'fork': {
160
+ const v = data['fromVersion'];
161
+ const name = data['name'];
162
+ if (typeof v === 'number' && Number.isInteger(v) && v >= 0) {
163
+ deps.fork(v, typeof name === 'string' && name ? name : undefined);
164
+ }
165
+ break;
166
+ }
167
+ case 'browse': {
168
+ deps.browse();
169
+ break;
170
+ }
171
+ case 'close': {
172
+ deps.close();
173
+ break;
174
+ }
175
+ case 'error': {
176
+ // The embed could not render (e.g. not signed in in this context).
177
+ // Collapse rather than leave a dead strip; the app still gates its
178
+ // own editing on `doc.readOnly`.
179
+ placeholder.style.display = 'none';
180
+ iframe.style.height = '0';
181
+ break;
182
+ }
183
+ }
184
+ }
185
+
186
+ window.addEventListener('message', onMessage);
187
+
188
+ return {
189
+ update(next: VersionBarContext): void {
190
+ const prev = ctx;
191
+ ctx = next;
192
+ // A document / branch switch needs a fresh `init`, which the embed
193
+ // only honors once, so recreate on that; a same-doc version step
194
+ // just pushes the new version down.
195
+ if (prev && (prev.docId !== next.docId || prev.branch !== next.branch)) {
196
+ // Reload the iframe: reset ready, restore the placeholder, and the
197
+ // new page will `ready` -> we re-`init` with the new context.
198
+ ready = false;
199
+ deliveredVersion = undefined;
200
+ placeholder.style.display = '';
201
+ iframe.style.height = '0';
202
+ iframe.src = url.toString();
203
+ return;
204
+ }
205
+ // Only an actual version change reaches the embed (dedup), so a
206
+ // re-render that didn't move the version can't clobber the bar's state.
207
+ if (ready && next.version !== deliveredVersion) {
208
+ deliveredVersion = next.version;
209
+ iframe.contentWindow?.postMessage(
210
+ { [ENVELOPE]: PROTOCOL_VERSION, type: 'version-changed', version: next.version },
211
+ origin,
212
+ );
213
+ }
214
+ },
215
+ destroy(): void {
216
+ window.removeEventListener('message', onMessage);
217
+ iframe.remove();
218
+ placeholder.remove();
219
+ },
220
+ };
221
+ }
package/src/version.ts ADDED
@@ -0,0 +1,8 @@
1
+ // The package version the SDK reports to the backend (the `client`
2
+ // query param on /refresh and on the WS connect URL), so the platform
3
+ // can measure the version distribution of deployed apps and time
4
+ // compatibility windows against it. A unit test pins this to
5
+ // package.json's version; the release bump touches both together.
6
+ export const SDK_VERSION = '0.1.0';
7
+
8
+ export const SDK_CLIENT_ID = `sdk/${SDK_VERSION}`;
package/src/vite.ts ADDED
@@ -0,0 +1,49 @@
1
+ // Vite plugin encapsulating the bundler config the SDK's WASM runtime
2
+ // needs, so users never name the underlying WASM dep in their own
3
+ // `vite.config.ts`.
4
+ //
5
+ // Vite's dep-prebundling targets older browsers by default and fails on the
6
+ // WASM dep's top-level await (`Top-level await is not available in the
7
+ // configured target environment for loro-crdt/bundler/loro_wasm.js`). The
8
+ // plugin excludes the dep from prebundling (leaving it for the build-time
9
+ // WASM loaders) and bumps the prebundle target to es2022.
10
+ //
11
+ // `vite-plugin-wasm` and `vite-plugin-top-level-await` remain the caller's
12
+ // responsibility: they must land before `brassVite()` in the plugin list.
13
+
14
+ // Names of the WASM-shipping deps the SDK pulls in. Append rather
15
+ // than replace when adding a new WASM dep: a consumer who has both
16
+ // installed during a migration window needs both excluded.
17
+ const WASM_DEPS: readonly string[] = ['loro-crdt'];
18
+
19
+ interface ViteUserConfig {
20
+ optimizeDeps?: {
21
+ exclude?: string[];
22
+ esbuildOptions?: { target?: string };
23
+ };
24
+ }
25
+
26
+ interface VitePlugin {
27
+ name: string;
28
+ config(config: ViteUserConfig): ViteUserConfig;
29
+ }
30
+
31
+ export function brassVite(): VitePlugin {
32
+ return {
33
+ name: 'brass-build:vite',
34
+ config(config) {
35
+ const existingExclude = config.optimizeDeps?.exclude ?? [];
36
+ const exclude = Array.from(new Set([...existingExclude, ...WASM_DEPS]));
37
+ const existingTarget = config.optimizeDeps?.esbuildOptions?.target;
38
+ // Don't downgrade if a consumer has already pinned a newer
39
+ // target; only raise from the Vite default (which lacks TLA).
40
+ const target = existingTarget ?? 'es2022';
41
+ return {
42
+ optimizeDeps: {
43
+ exclude,
44
+ esbuildOptions: { target },
45
+ },
46
+ };
47
+ },
48
+ };
49
+ }