@braidlabs/core 0.7.0 → 0.8.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 (52) hide show
  1. package/package.json +1 -1
  2. package/src/adapters/compat-adapter.js +51 -4
  3. package/src/adapters/compat-adapter.js.map +1 -1
  4. package/src/compat/database-partition.d.ts +43 -0
  5. package/src/compat/database-partition.js +165 -0
  6. package/src/compat/database-partition.js.map +1 -0
  7. package/src/compat/fragment-boundary.js +133 -25
  8. package/src/compat/fragment-boundary.js.map +1 -1
  9. package/src/compat/html-policy.js +10 -5
  10. package/src/compat/html-policy.js.map +1 -1
  11. package/src/compat/script-execution.js +5 -4
  12. package/src/compat/script-execution.js.map +1 -1
  13. package/src/compat/shared-globals.d.ts +1 -1
  14. package/src/compat/shared-globals.js +2 -2
  15. package/src/compat/shared-globals.js.map +1 -1
  16. package/src/config.d.ts +13 -2
  17. package/src/config.js.map +1 -1
  18. package/src/elements/fragment-slot.d.ts +41 -15
  19. package/src/elements/fragment-slot.js +195 -9
  20. package/src/elements/fragment-slot.js.map +1 -1
  21. package/src/elements/leave-guard.d.ts +49 -0
  22. package/src/elements/leave-guard.js +122 -0
  23. package/src/elements/leave-guard.js.map +1 -0
  24. package/src/elements/overlay-layer.d.ts +45 -0
  25. package/src/elements/overlay-layer.js +112 -0
  26. package/src/elements/overlay-layer.js.map +1 -0
  27. package/src/env/create-env.js +2 -1
  28. package/src/env/create-env.js.map +1 -1
  29. package/src/env/fragment-env.d.ts +6 -0
  30. package/src/index.d.ts +3 -0
  31. package/src/index.js +14 -0
  32. package/src/index.js.map +1 -1
  33. package/src/realm/realm-manager.js +2 -1
  34. package/src/realm/realm-manager.js.map +1 -1
  35. package/src/realm/sandbox-realm.d.ts +5 -7
  36. package/src/realm/sandbox-realm.js +104 -39
  37. package/src/realm/sandbox-realm.js.map +1 -1
  38. package/src/trusted-types.d.ts +28 -0
  39. package/src/trusted-types.js +58 -0
  40. package/src/trusted-types.js.map +1 -0
  41. package/src/weave/capabilities.d.ts +10 -3
  42. package/src/weave/capabilities.js +19 -3
  43. package/src/weave/capabilities.js.map +1 -1
  44. package/src/weave/context-bridge.d.ts +2 -0
  45. package/src/weave/context-bridge.js +1 -1
  46. package/src/weave/context-bridge.js.map +1 -1
  47. package/src/weave/guest.d.ts +2 -0
  48. package/src/weave/guest.js +10 -5
  49. package/src/weave/guest.js.map +1 -1
  50. package/src/weave/messages.d.ts +24 -0
  51. package/src/weave/messages.js +22 -0
  52. package/src/weave/messages.js.map +1 -1
@@ -16,7 +16,7 @@ import { BraidError } from '../errors.js';
16
16
  * | --- | --- | --- |
17
17
  * | isolation | namespace, not security | browser-enforced |
18
18
  * | DOM | projected into the host document | stays in its own document |
19
- * | cookies/storage | the host's | its own, partitioned |
19
+ * | cookies/storage | the host's | none: an opaque origin has no cookies, Web Storage or IndexedDB |
20
20
  * | composition | gateway namespaces, piercing, compat facade | none of it applies |
21
21
  *
22
22
  * **Why this is not a `RealmHandle`.** That interface exposes `window`, `document`, `evaluate()`
@@ -45,7 +45,51 @@ export const DEFAULT_SANDBOX_TOKENS = ['allow-scripts', 'allow-forms'];
45
45
  * grant if you need it, and it must be granted deliberately rather than inherited from a broad
46
46
  * "let this fragment navigate" instinct.
47
47
  */
48
- const REFUSED_SANDBOX_TOKENS = new Set(['allow-top-navigation']);
48
+ const TOP_NAVIGATION_HINT = 'use "allow-top-navigation-by-user-activation" if the fragment genuinely needs to navigate the page';
49
+ const REFUSED_SANDBOX_TOKENS = new Map([
50
+ ['allow-top-navigation', TOP_NAVIGATION_HINT],
51
+ ['allow-top-navigation-to-custom-protocols', TOP_NAVIGATION_HINT],
52
+ /**
53
+ * The same navigation by another door: a popup that escapes the sandbox can set
54
+ * `window.opener.top.location` and swap the host page for a lookalike.
55
+ */
56
+ [
57
+ 'allow-popups-to-escape-sandbox',
58
+ '"allow-popups" alone lets the fragment open windows; they stay sandboxed, which is the point',
59
+ ],
60
+ /**
61
+ * The token that turns the sandbox off. With it the frame keeps a real origin: a `javascript:`
62
+ * src, or a navigation to a URL on the host's origin, then runs with the host's own authority.
63
+ * The handshake works without it, so nothing on this tier needs it.
64
+ */
65
+ [
66
+ 'allow-same-origin',
67
+ 'leave it out: the untrusted tier connects from an opaque origin, which is what keeps it isolated',
68
+ ],
69
+ ]);
70
+ /**
71
+ * Every token the HTML standard defines. Anything else is refused rather than passed through: the
72
+ * browser ignores a token it does not know, so a typo would silently grant less than intended — or,
73
+ * as browsers add tokens, silently grant something nobody reviewed.
74
+ */
75
+ const KNOWN_SANDBOX_TOKENS = new Set([
76
+ 'allow-downloads',
77
+ 'allow-forms',
78
+ 'allow-modals',
79
+ 'allow-orientation-lock',
80
+ 'allow-pointer-lock',
81
+ 'allow-popups',
82
+ 'allow-popups-to-escape-sandbox',
83
+ 'allow-presentation',
84
+ 'allow-same-origin',
85
+ 'allow-scripts',
86
+ 'allow-storage-access-by-user-activation',
87
+ 'allow-top-navigation',
88
+ 'allow-top-navigation-by-user-activation',
89
+ 'allow-top-navigation-to-custom-protocols',
90
+ ]);
91
+ /** Loopback hosts, where plain `http:` is how local development serves a second origin. */
92
+ const LOOPBACK_HOSTS = new Set(['localhost', '127.0.0.1', '[::1]']);
49
93
  const LOAD_TIMEOUT_MS = 15_000;
50
94
  /**
51
95
  * Refuses a same-origin URL for the untrusted tier.
@@ -69,6 +113,20 @@ export function assertCrossOrigin(src, fragmentId) {
69
113
  fixHint: 'untrusted fragments are addressed by absolute url, e.g. src="https://vendor.example.com/widget"',
70
114
  });
71
115
  }
116
+ /**
117
+ * Only a network scheme can name another origin. `javascript:`, `data:` and `blob:` have an
118
+ * opaque origin, which never equals the host's, so the comparison below would wave them through
119
+ * — and a `javascript:` src in a frame granted `allow-same-origin` runs in the host's origin.
120
+ */
121
+ const secure = url.protocol === 'https:';
122
+ const loopback = url.protocol === 'http:' && LOOPBACK_HOSTS.has(url.hostname);
123
+ if (!secure && !loopback) {
124
+ throw new BraidError(`the untrusted tier loads fragments over https, and "${src}" is not an https url`, {
125
+ fragmentId,
126
+ stage: 'slot-config',
127
+ fixHint: 'serve the fragment from its own https origin; plain http is accepted only on localhost',
128
+ });
129
+ }
72
130
  if (url.origin === location.origin) {
73
131
  throw new BraidError(`the untrusted tier requires a cross-origin url, and "${url.origin}" is this host's origin`, {
74
132
  fragmentId,
@@ -82,12 +140,23 @@ export function assertCrossOrigin(src, fragmentId) {
82
140
  /** Resolves the sandbox token list, refusing the ones that would undo the sandbox. */
83
141
  export function resolveSandboxTokens(requested = [], fragmentId) {
84
142
  const tokens = new Set(DEFAULT_SANDBOX_TOKENS);
85
- for (const token of requested) {
86
- if (REFUSED_SANDBOX_TOKENS.has(token)) {
143
+ // The browser splits the attribute on whitespace and matches tokens case-insensitively, so this
144
+ // must too — or "ALLOW-TOP-NAVIGATION" and "allow-popups allow-top-navigation" slip past.
145
+ const normalized = requested.flatMap((entry) => String(entry).toLowerCase().split(/\s+/).filter(Boolean));
146
+ for (const token of normalized) {
147
+ if (!KNOWN_SANDBOX_TOKENS.has(token)) {
148
+ throw new BraidError(`"${token}" is not a sandbox token`, {
149
+ fragmentId,
150
+ stage: 'slot-config',
151
+ fixHint: 'sandbox tokens are the allow-* keywords the HTML standard defines, e.g. "allow-popups"',
152
+ });
153
+ }
154
+ const refusal = REFUSED_SANDBOX_TOKENS.get(token);
155
+ if (refusal !== undefined) {
87
156
  throw new BraidError(`the sandbox token "${token}" is never granted to an untrusted fragment`, {
88
157
  fragmentId,
89
158
  stage: 'slot-config',
90
- fixHint: `use "${token}-by-user-activation" if the fragment genuinely needs to navigate the page`,
159
+ fixHint: refusal,
91
160
  });
92
161
  }
93
162
  tokens.add(token);
@@ -97,11 +166,9 @@ export function resolveSandboxTokens(requested = [], fragmentId) {
97
166
  /**
98
167
  * Creates the frame, waits for it to load, and establishes the message channel.
99
168
  *
100
- * The connect handshake is deliberately tolerant of ordering. The frame's `load` event and the
101
- * guest's own script registering its listener race, and which wins depends on cache state — so the
102
- * host posts on load *and* answers a guest that announces itself, and the guest announces itself
103
- * whether or not it has already been posted to. Either order converges; neither has to be the fast
104
- * one.
169
+ * The guest announces itself and the host answers that window with the port. The host listens
170
+ * before the frame is attached, so there is no ordering to race: however fast the guest's script
171
+ * runs, its announcement finds a listener.
105
172
  */
106
173
  export async function createSandboxRealm(init) {
107
174
  const { fragmentId, src, container, signal } = init;
@@ -109,7 +176,9 @@ export async function createSandboxRealm(init) {
109
176
  const tokens = resolveSandboxTokens(init.sandboxTokens, fragmentId);
110
177
  const instance = `${fragmentId}:${Date.now().toString(36)}`;
111
178
  const frame = document.createElement('iframe');
112
- frame.src = src;
179
+ // The absolute URL that was checked, not the string: `src` would resolve against
180
+ // `document.baseURI`, which a `<base>` element can point somewhere `location.href` does not.
181
+ frame.src = new URL(src, location.href).href;
113
182
  frame.setAttribute('sandbox', tokens.join(' '));
114
183
  frame.setAttribute('part', 'frame');
115
184
  frame.style.cssText = 'display:block;border:0;width:100%;height:100%';
@@ -125,53 +194,50 @@ export async function createSandboxRealm(init) {
125
194
  if ('credentialless' in HTMLIFrameElement.prototype) {
126
195
  frame.setAttribute('credentialless', '');
127
196
  }
128
- container.append(frame);
129
197
  const channel = new MessageChannel();
130
198
  const dispose = () => {
131
199
  channel.port1.close();
132
200
  frame.remove();
133
201
  };
134
202
  signal.addEventListener('abort', dispose, { once: true });
135
- const post = () => {
136
- const message = { braid: SANDBOX_CONNECT, v: 1, fragmentId, instance };
137
- /**
138
- * The target origin is the fragment's exact origin, never `'*'`.
139
- *
140
- * With `'*'` the port would be delivered to whatever document happens to occupy the frame — and
141
- * an untrusted fragment that navigated itself elsewhere between load and this call would hand a
142
- * live channel into the host to a document nobody vetted.
143
- */
144
- frame.contentWindow?.postMessage(message, origin, [channel.port2]);
145
- };
146
203
  const { promise, resolve, reject } = Promise.withResolvers();
147
204
  let connected = false;
205
+ /**
206
+ * The guest speaks first, and the host answers that window and no other.
207
+ *
208
+ * A sandboxed frame without `allow-same-origin` has an opaque origin. A message targeted at the
209
+ * fragment's origin is never delivered to it, and its own messages arrive with origin `"null"`.
210
+ * The origin cannot identify it, so the window does: `event.source` is set by the browser, and
211
+ * only this frame's window can be `frame.contentWindow`. The reply goes to that window with `'*'`,
212
+ * the only target an opaque origin accepts. It reaches whichever document the frame holds when it
213
+ * arrives, which is the one that asked unless the frame navigated in between. Only the frame
214
+ * itself can navigate it, so any document it lands on is the vendor's choice and as trusted as the
215
+ * vendor.
216
+ */
148
217
  const onWindowMessage = (event) => {
149
- // Origin-pinned inbound as well as outbound: a `braid:ready` from any other origin is some
150
- // other page on the tab talking, and must not cause the host to hand out a port.
151
- if (event.origin !== origin)
218
+ if (event.source === null || event.source !== frame.contentWindow)
219
+ return;
220
+ if (event.origin !== 'null')
152
221
  return;
153
222
  if (event.data?.braid !== SANDBOX_READY)
154
223
  return;
155
224
  if (connected)
156
225
  return;
157
226
  connected = true;
158
- post();
227
+ const message = { braid: SANDBOX_CONNECT, v: 1, fragmentId, instance };
228
+ event.source.postMessage(message, '*', [channel.port2]);
159
229
  resolve();
160
230
  };
231
+ // Listening before the frame exists, so a guest that announces itself at once is not missed.
161
232
  window.addEventListener('message', onWindowMessage);
162
- const onLoad = () => {
163
- if (connected)
164
- return;
165
- connected = true;
166
- post();
167
- resolve();
168
- };
169
- frame.addEventListener('load', onLoad, { once: true });
233
+ container.append(frame);
170
234
  const timeout = setTimeout(() => {
171
- reject(new BraidError(`the untrusted fragment at "${src}" did not load within ${init.loadTimeoutMs ?? LOAD_TIMEOUT_MS}ms`, {
235
+ reject(new BraidError(`the untrusted fragment at "${src}" did not connect within ${init.loadTimeoutMs ?? LOAD_TIMEOUT_MS}ms`, {
172
236
  fragmentId,
173
- stage: 'realm-boot',
174
- fixHint: 'check the url, and that the fragment origin does not refuse framing via X-Frame-Options or CSP frame-ancestors',
237
+ stage: 'handshake',
238
+ fixHint: `the fragment must call connectToBraidHost({ hostOrigin: '${location.origin}' }). Its frame runs in an opaque ` +
239
+ 'origin, so its module scripts need Access-Control-Allow-Origin. Also check that its origin does not refuse ' +
240
+ 'framing via X-Frame-Options or CSP frame-ancestors',
175
241
  }));
176
242
  }, init.loadTimeoutMs ?? LOAD_TIMEOUT_MS);
177
243
  try {
@@ -180,7 +246,6 @@ export async function createSandboxRealm(init) {
180
246
  finally {
181
247
  clearTimeout(timeout);
182
248
  window.removeEventListener('message', onWindowMessage);
183
- frame.removeEventListener('load', onLoad);
184
249
  }
185
250
  return {
186
251
  kind: 'sandbox',
@@ -1 +1 @@
1
- {"version":3,"file":"sandbox-realm.js","sourceRoot":"","sources":["../../../../../libs/core/src/realm/sandbox-realm.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sandbox-realm.js","sourceRoot":"","sources":["../../../../../libs/core/src/realm/sandbox-realm.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,4EAA4E;AAC5E,MAAM,CAAC,MAAM,eAAe,GAAG,eAAe,CAAC;AAC/C,oFAAoF;AACpF,MAAM,CAAC,MAAM,aAAa,GAAG,aAAa,CAAC;AAc3C;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,eAAe,EAAE,aAAa,CAAU,CAAC;AAEhF;;;;;;;GAOG;AACH,MAAM,mBAAmB,GACvB,oGAAoG,CAAC;AACvG,MAAM,sBAAsB,GAAG,IAAI,GAAG,CAAC;IACrC,CAAC,sBAAsB,EAAE,mBAAmB,CAAC;IAC7C,CAAC,0CAA0C,EAAE,mBAAmB,CAAC;IACjE;;;OAGG;IACH;QACE,gCAAgC;QAChC,8FAA8F;KAC/F;IACD;;;;OAIG;IACH;QACE,mBAAmB;QACnB,kGAAkG;KACnG;CACF,CAAC,CAAC;AAEH;;;;GAIG;AACH,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC;IACnC,iBAAiB;IACjB,aAAa;IACb,cAAc;IACd,wBAAwB;IACxB,oBAAoB;IACpB,cAAc;IACd,gCAAgC;IAChC,oBAAoB;IACpB,mBAAmB;IACnB,eAAe;IACf,yCAAyC;IACzC,sBAAsB;IACtB,yCAAyC;IACzC,0CAA0C;CAC3C,CAAC,CAAC;AAEH,2FAA2F;AAC3F,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC;AA6BpE,MAAM,eAAe,GAAG,MAAM,CAAC;AAE/B;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAW,EAAE,UAAkB;IAC/D,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,UAAU,CAAC,IAAI,GAAG,gDAAgD,EAAE;YAC5E,UAAU;YACV,KAAK,EAAE,aAAa;YACpB,KAAK;YACL,OAAO,EAAE,iGAAiG;SAC3G,CAAC,CAAC;IACL,CAAC;IAED;;;;OAIG;IACH,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC;IACzC,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC9E,IAAI,CAAC,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;QACzB,MAAM,IAAI,UAAU,CAAC,uDAAuD,GAAG,uBAAuB,EAAE;YACtG,UAAU;YACV,KAAK,EAAE,aAAa;YACpB,OAAO,EAAE,wFAAwF;SAClG,CAAC,CAAC;IACL,CAAC;IAED,IAAI,GAAG,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,EAAE,CAAC;QACnC,MAAM,IAAI,UAAU,CAAC,wDAAwD,GAAG,CAAC,MAAM,yBAAyB,EAAE;YAChH,UAAU;YACV,KAAK,EAAE,aAAa;YACpB,OAAO,EACL,uFAAuF;gBACvF,8FAA8F;SACjG,CAAC,CAAC;IACL,CAAC;IAED,OAAO,GAAG,CAAC,MAAM,CAAC;AACpB,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,oBAAoB,CAAC,YAA+B,EAAE,EAAE,UAAkB;IACxF,MAAM,MAAM,GAAG,IAAI,GAAG,CAAS,sBAAsB,CAAC,CAAC;IAEvD,gGAAgG;IAChG,0FAA0F;IAC1F,MAAM,UAAU,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IAE1G,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;QAC/B,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YACrC,MAAM,IAAI,UAAU,CAAC,IAAI,KAAK,0BAA0B,EAAE;gBACxD,UAAU;gBACV,KAAK,EAAE,aAAa;gBACpB,OAAO,EAAE,wFAAwF;aAClG,CAAC,CAAC;QACL,CAAC;QACD,MAAM,OAAO,GAAG,sBAAsB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAClD,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,MAAM,IAAI,UAAU,CAAC,sBAAsB,KAAK,6CAA6C,EAAE;gBAC7F,UAAU;gBACV,KAAK,EAAE,aAAa;gBACpB,OAAO,EAAE,OAAO;aACjB,CAAC,CAAC;QACL,CAAC;QACD,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACpB,CAAC;IAED,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC;AACrB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,IAAsB;IAC7D,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAEpD,MAAM,MAAM,GAAG,iBAAiB,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,oBAAoB,CAAC,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;IACpE,MAAM,QAAQ,GAAG,GAAG,UAAU,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;IAE5D,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;IAC/C,iFAAiF;IACjF,6FAA6F;IAC7F,KAAK,CAAC,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC;IAC7C,KAAK,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAChD,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,KAAK,CAAC,KAAK,CAAC,OAAO,GAAG,+CAA+C,CAAC;IAEtE;;;;;OAKG;IACH,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAEjE,iGAAiG;IACjG,2FAA2F;IAC3F,IAAI,gBAAgB,IAAI,iBAAiB,CAAC,SAAS,EAAE,CAAC;QACpD,KAAK,CAAC,YAAY,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC;IAC3C,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,cAAc,EAAE,CAAC;IAErC,MAAM,OAAO,GAAG,GAAG,EAAE;QACnB,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACtB,KAAK,CAAC,MAAM,EAAE,CAAC;IACjB,CAAC,CAAC;IACF,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAE1D,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,aAAa,EAAQ,CAAC;IACnE,IAAI,SAAS,GAAG,KAAK,CAAC;IAEtB;;;;;;;;;;;OAWG;IACH,MAAM,eAAe,GAAG,CAAC,KAAmB,EAAE,EAAE;QAC9C,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,aAAa;YAAE,OAAO;QAC1E,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM;YAAE,OAAO;QACpC,IAAK,KAAK,CAAC,IAAwC,EAAE,KAAK,KAAK,aAAa;YAAE,OAAO;QACrF,IAAI,SAAS;YAAE,OAAO;QACtB,SAAS,GAAG,IAAI,CAAC;QACjB,MAAM,OAAO,GAA0B,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC,EAAE,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC;QAC7F,KAAK,CAAC,MAAiB,CAAC,WAAW,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;QACpE,OAAO,EAAE,CAAC;IACZ,CAAC,CAAC;IAEF,6FAA6F;IAC7F,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;IACpD,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAExB,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;QAC9B,MAAM,CACJ,IAAI,UAAU,CAAC,8BAA8B,GAAG,4BAA4B,IAAI,CAAC,aAAa,IAAI,eAAe,IAAI,EAAE;YACrH,UAAU;YACV,KAAK,EAAE,WAAW;YAClB,OAAO,EACL,4DAA4D,QAAQ,CAAC,MAAM,oCAAoC;gBAC/G,6GAA6G;gBAC7G,oDAAoD;SACvD,CAAC,CACH,CAAC;IACJ,CAAC,EAAE,IAAI,CAAC,aAAa,IAAI,eAAe,CAAC,CAAC;IAE1C,IAAI,CAAC;QACH,MAAM,OAAO,CAAC;IAChB,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,OAAO,CAAC,CAAC;QACtB,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;IACzD,CAAC;IAED,OAAO;QACL,IAAI,EAAE,SAAS;QACf,UAAU;QACV,KAAK;QACL,MAAM;QACN,IAAI,EAAE,OAAO,CAAC,KAAK;QACnB,OAAO;KACR,CAAC;AACJ,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Braid's own writes into the sinks Trusted Types guards, for a host page that enforces them
3
+ * (`require-trusted-types-for 'script'`).
4
+ *
5
+ * The runtime writes to a handful of sinks itself: it parses the markup the gateway prepared, it
6
+ * marks a script as already started by giving it a line of text, and the opt-in HTML policy
7
+ * parses a fragment's write into an inert document before cleaning it. Under enforcement each of
8
+ * those needs a trusted value, so they go through one policy, named `braid`, which a host lists in
9
+ * its `trusted-types` directive.
10
+ *
11
+ * The policy passes values through unchanged, which is why it is never exported: only these call
12
+ * sites can reach it, and each one either writes something Braid authored or parses into a
13
+ * document where nothing runs. Everything a fragment writes itself still meets the host's own
14
+ * enforcement — which is the point of turning it on.
15
+ *
16
+ * Created on first use, in whichever realm the write happens: a realm document inherits the host's
17
+ * policy, and a trusted value is checked against the realm that writes it.
18
+ */
19
+ /** Markup Braid parses: the gateway's prepared document, or a write it is about to clean. */
20
+ export declare function trustedHTML(markup: string, realm?: object): string;
21
+ /** Script text Braid writes itself. */
22
+ export declare function trustedScript(source: string, realm?: object): string;
23
+ /**
24
+ * Creates the host's policy now, if the page has Trusted Types. Called by `initBraid`, before any
25
+ * fragment code runs: what the host's directive grants is the name `braid`, so it must be Braid's
26
+ * before anything else on the page can create it.
27
+ */
28
+ export declare function claimBraidPolicy(): void;
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Braid's own writes into the sinks Trusted Types guards, for a host page that enforces them
3
+ * (`require-trusted-types-for 'script'`).
4
+ *
5
+ * The runtime writes to a handful of sinks itself: it parses the markup the gateway prepared, it
6
+ * marks a script as already started by giving it a line of text, and the opt-in HTML policy
7
+ * parses a fragment's write into an inert document before cleaning it. Under enforcement each of
8
+ * those needs a trusted value, so they go through one policy, named `braid`, which a host lists in
9
+ * its `trusted-types` directive.
10
+ *
11
+ * The policy passes values through unchanged, which is why it is never exported: only these call
12
+ * sites can reach it, and each one either writes something Braid authored or parses into a
13
+ * document where nothing runs. Everything a fragment writes itself still meets the host's own
14
+ * enforcement — which is the point of turning it on.
15
+ *
16
+ * Created on first use, in whichever realm the write happens: a realm document inherits the host's
17
+ * policy, and a trusted value is checked against the realm that writes it.
18
+ */
19
+ const POLICY_NAME = 'braid';
20
+ const policies = new WeakMap();
21
+ function policyFor(realm) {
22
+ if (policies.has(realm))
23
+ return policies.get(realm) ?? null;
24
+ const factory = realm.trustedTypes;
25
+ let policy = null;
26
+ if (factory) {
27
+ try {
28
+ const same = (input) => input;
29
+ policy = factory.createPolicy(POLICY_NAME, { createHTML: same, createScript: same });
30
+ }
31
+ catch (error) {
32
+ // Not listed in the host's `trusted-types` directive, or the name already taken — by a second
33
+ // copy of the runtime, or by script that ran first. Writes go as plain strings and enforcement
34
+ // reports them; the warning says which.
35
+ console.warn(`[braid] could not create the "${POLICY_NAME}" Trusted Types policy: ${error?.message ?? error}`);
36
+ policy = null;
37
+ }
38
+ }
39
+ policies.set(realm, policy);
40
+ return policy;
41
+ }
42
+ /** Markup Braid parses: the gateway's prepared document, or a write it is about to clean. */
43
+ export function trustedHTML(markup, realm = globalThis) {
44
+ return policyFor(realm)?.createHTML(markup) ?? markup;
45
+ }
46
+ /** Script text Braid writes itself. */
47
+ export function trustedScript(source, realm = globalThis) {
48
+ return policyFor(realm)?.createScript(source) ?? source;
49
+ }
50
+ /**
51
+ * Creates the host's policy now, if the page has Trusted Types. Called by `initBraid`, before any
52
+ * fragment code runs: what the host's directive grants is the name `braid`, so it must be Braid's
53
+ * before anything else on the page can create it.
54
+ */
55
+ export function claimBraidPolicy() {
56
+ policyFor(globalThis);
57
+ }
58
+ //# sourceMappingURL=trusted-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trusted-types.js","sourceRoot":"","sources":["../../../../libs/core/src/trusted-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAWH,MAAM,WAAW,GAAG,OAAO,CAAC;AAC5B,MAAM,QAAQ,GAAG,IAAI,OAAO,EAAoC,CAAC;AAEjE,SAAS,SAAS,CAAC,KAAa;IAC9B,IAAI,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;QAAE,OAAO,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC;IAC5D,MAAM,OAAO,GAAI,KAA4B,CAAC,YAAY,CAAC;IAC3D,IAAI,MAAM,GAA6B,IAAI,CAAC;IAC5C,IAAI,OAAO,EAAE,CAAC;QACZ,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,KAAK,CAAC;YACtC,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,WAAW,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QACvF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,8FAA8F;YAC9F,+FAA+F;YAC/F,wCAAwC;YACxC,OAAO,CAAC,IAAI,CAAC,iCAAiC,WAAW,2BAA4B,KAAe,EAAE,OAAO,IAAI,KAAK,EAAE,CAAC,CAAC;YAC1H,MAAM,GAAG,IAAI,CAAC;QAChB,CAAC;IACH,CAAC;IACD,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC5B,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,6FAA6F;AAC7F,MAAM,UAAU,WAAW,CAAC,MAAc,EAAE,QAAgB,UAAU;IACpE,OAAQ,SAAS,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,MAAM,CAAwB,IAAI,MAAM,CAAC;AAChF,CAAC;AAED,uCAAuC;AACvC,MAAM,UAAU,aAAa,CAAC,MAAc,EAAE,QAAgB,UAAU;IACtE,OAAQ,SAAS,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC,MAAM,CAAwB,IAAI,MAAM,CAAC;AAClF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB;IAC9B,SAAS,CAAC,UAAU,CAAC,CAAC;AACxB,CAAC"}
@@ -48,7 +48,9 @@ export interface FragmentCapabilities {
48
48
  * Whose Web Storage the fragment sees. `'shared'` (the default) is the host origin's, as for any
49
49
  * same-origin frame. `'partitioned'` gives it a store of its own, keyed by fragment id;
50
50
  * `{ partition }` names a store several fragments share. See `compat/storage-partition.ts`.
51
- * Compat fragments only; ignored elsewhere.
51
+ * `{ databases: true }` (with or without `partition`) also gives the partition its own
52
+ * IndexedDB and Cache Storage — a Storage Bucket where the browser has them, prefixed names
53
+ * elsewhere. See `compat/database-partition.ts`. Compat fragments only; ignored elsewhere.
52
54
  */
53
55
  storage?: StorageGrant;
54
56
  /**
@@ -75,7 +77,9 @@ export interface FragmentCapabilities {
75
77
  * whoever is wondering why `user` is undefined, so the *host's* console names the missing grant —
76
78
  * host-side, because the host is where the grant is written.
77
79
  */
78
- export declare function createContextGate(capabilities: FragmentCapabilities | undefined, fragmentId: string): (key: string) => boolean;
80
+ export declare function createContextGate(capabilities: FragmentCapabilities | undefined, fragmentId: string, options?: {
81
+ untrusted?: boolean;
82
+ }): (key: string) => boolean;
79
83
  /**
80
84
  * Resolves capabilities from the three places a host can write them, most authoritative first:
81
85
  *
@@ -100,7 +104,8 @@ export declare function resolveCapabilities(sources: Array<FragmentCapabilities
100
104
  export declare function resolveSharedGlobals(capabilities: FragmentCapabilities | undefined): readonly string[];
101
105
  /** A fragment's Web Storage grant. */
102
106
  export type StorageGrant = 'shared' | 'partitioned' | {
103
- partition: string;
107
+ partition?: string;
108
+ databases?: boolean;
104
109
  };
105
110
  /**
106
111
  * The storage partition a fragment writes into, or `null` for the shared, host-origin store.
@@ -109,5 +114,7 @@ export type StorageGrant = 'shared' | 'partitioned' | {
109
114
  * two partitioned forms is the shared default — a typo must not quietly move a fragment's data.
110
115
  */
111
116
  export declare function resolveStoragePartition(capabilities: FragmentCapabilities | undefined, fragmentId: string): string | null;
117
+ /** The partition whose IndexedDB and Cache Storage a fragment gets, or `null` for the origin's. */
118
+ export declare function resolveDatabasePartition(capabilities: FragmentCapabilities | undefined, fragmentId: string): string | null;
112
119
  /** Reads a capabilities block off a realm stub's adapter options, or off `initBraid` config. */
113
120
  export declare function readCapabilities(source: unknown): FragmentCapabilities | undefined;
@@ -11,8 +11,14 @@ import { getBraidConfig, isDevMode } from '../config.js';
11
11
  * whoever is wondering why `user` is undefined, so the *host's* console names the missing grant —
12
12
  * host-side, because the host is where the grant is written.
13
13
  */
14
- export function createContextGate(capabilities, fragmentId) {
15
- const read = capabilities?.context?.read;
14
+ export function createContextGate(capabilities, fragmentId, options = {}) {
15
+ /**
16
+ * No grant means everything for a trusted fragment, which already holds the user's session, so
17
+ * that adding capabilities to one fragment does not starve the rest. An untrusted fragment is the
18
+ * opposite case: forgetting its grant must not hand a third party the user, the tenant and every
19
+ * token the host publishes, so it gets nothing until a grant names what it may read.
20
+ */
21
+ const read = capabilities?.context?.read ?? (options.untrusted ? [] : undefined);
16
22
  if (!read)
17
23
  return () => true;
18
24
  const granted = new Set(read);
@@ -75,12 +81,22 @@ export function resolveStoragePartition(capabilities, fragmentId) {
75
81
  if (grant === 'partitioned')
76
82
  return fragmentId;
77
83
  if (grant && typeof grant === 'object') {
78
- const partition = grant.partition;
84
+ const { partition, databases } = grant;
79
85
  if (typeof partition === 'string' && partition !== '')
80
86
  return partition;
87
+ // databases of its own imply a partition of its own, named for the fragment as 'partitioned' is
88
+ if (databases === true && partition === undefined)
89
+ return fragmentId;
81
90
  }
82
91
  return null;
83
92
  }
93
+ /** The partition whose IndexedDB and Cache Storage a fragment gets, or `null` for the origin's. */
94
+ export function resolveDatabasePartition(capabilities, fragmentId) {
95
+ const grant = capabilities?.storage;
96
+ if (!grant || typeof grant !== 'object' || grant.databases !== true)
97
+ return null;
98
+ return resolveStoragePartition(capabilities, fragmentId);
99
+ }
84
100
  /** Reads a capabilities block off a realm stub's adapter options, or off `initBraid` config. */
85
101
  export function readCapabilities(source) {
86
102
  if (!source || typeof source !== 'object')
@@ -1 +1 @@
1
- {"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../../../../../libs/core/src/weave/capabilities.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../../../../../libs/core/src/weave/capabilities.ts"],"names":[],"mappings":"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"}
@@ -59,6 +59,8 @@ export interface AttachContextRouterOptions {
59
59
  * subscription that never fires.
60
60
  */
61
61
  capabilities?: FragmentCapabilities;
62
+ /** An untrusted fragment with no `context.read` grant reads nothing, not everything. */
63
+ untrusted?: boolean;
62
64
  signal: AbortSignal;
63
65
  }
64
66
  /**
@@ -31,7 +31,7 @@ export const CTX_CHANGED = 'ctx/changed';
31
31
  */
32
32
  export function attachContextRouter(options) {
33
33
  const { bus, channel, fragmentId, contextVersions, signal } = options;
34
- const mayRead = createContextGate(options.capabilities, fragmentId);
34
+ const mayRead = createContextGate(options.capabilities, fragmentId, { untrusted: options.untrusted === true });
35
35
  const readFor = (key) => {
36
36
  const as = contextVersions[key];
37
37
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"context-bridge.js","sourceRoot":"","sources":["../../../../../libs/core/src/weave/context-bridge.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"context-bridge.js","sourceRoot":"","sources":["../../../../../libs/core/src/weave/context-bridge.ts"],"names":[],"mappings":"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"}
@@ -32,6 +32,8 @@ export interface GuestSession {
32
32
  onPropsChanged(listener: (props: Readonly<Record<string, unknown>>) => void): () => void;
33
33
  /** Fragment → host. Surfaced on the slot element as `braid:event`. */
34
34
  emit(type: string, detail?: unknown): void;
35
+ /** Reports the fragment's first content as settled; see `FragmentEnv.settled`. */
36
+ settled(): void;
35
37
  onClosing: ClosingCoordinator['onClosing'];
36
38
  setDirty: ClosingCoordinator['setDirty'];
37
39
  /** Aborts when the host closes the session. */
@@ -6,7 +6,7 @@ import { createContextMirror } from './context-bridge.js';
6
6
  import { createClosingCoordinator } from './closing.js';
7
7
  import { answerHandshake } from './handshake.js';
8
8
  import { startFragmentBeats } from './liveness.js';
9
- import { FRAGMENT_EVENT, PROPS_CHANGED } from './messages.js';
9
+ import { FRAGMENT_EVENT, PROPS_CHANGED, SETTLED } from './messages.js';
10
10
  const CONNECT_TIMEOUT_MS = 15_000;
11
11
  /** Waits for a host to offer a port, then completes the Weave handshake over it. */
12
12
  export async function connectToBraidHost(options) {
@@ -70,6 +70,7 @@ export async function connectToBraidHost(options) {
70
70
  return () => void propsListeners.delete(listener);
71
71
  },
72
72
  emit: (type, detail) => channel.send(FRAGMENT_EVENT, { type, detail }),
73
+ settled: () => channel.send(SETTLED),
73
74
  onClosing: closing.onClosing,
74
75
  setDirty: closing.setDirty,
75
76
  signal: controller.signal,
@@ -84,6 +85,10 @@ function acceptConnection(hostOrigin, timeoutMs) {
84
85
  // the sender, which is what makes it worth checking and `event.data` worth distrusting.
85
86
  if (event.origin !== hostOrigin)
86
87
  return;
88
+ // And from the page that framed this one: another window on the host's origin, such as a
89
+ // trusted fragment's realm or a popup, must not be able to hand this fragment a channel.
90
+ if (event.source !== window.parent)
91
+ return;
87
92
  const data = event.data;
88
93
  if (data?.braid !== SANDBOX_CONNECT)
89
94
  return;
@@ -107,11 +112,11 @@ function acceptConnection(hostOrigin, timeoutMs) {
107
112
  }
108
113
  window.addEventListener('message', onMessage);
109
114
  /**
110
- * Announced *after* the listener is attached, so the two orderings converge.
115
+ * Announced *after* the listener is attached, because the host answers at once.
111
116
  *
112
- * The host posts on the frame's `load` event, which may fire before this module has even been
113
- * evaluated. Announcing tells a host that already gave up waiting to post again; attaching first
114
- * means a host that posted immediately is not missed either.
117
+ * The announcement is what connects: this frame runs in an opaque origin, which the host cannot
118
+ * address by name, so it replies to the window that announced itself. The target origin still
119
+ * pins the host — a page that framed this one from any other origin never receives it.
115
120
  */
116
121
  const ready = { braid: SANDBOX_READY, v: 1 };
117
122
  window.parent?.postMessage(ready, hostOrigin);
@@ -1 +1 @@
1
- {"version":3,"file":"guest.js","sourceRoot":"","sources":["../../../../../libs/core/src/weave/guest.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"guest.js","sourceRoot":"","sources":["../../../../../libs/core/src/weave/guest.ts"],"names":[],"mappings":"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"}
@@ -25,3 +25,27 @@ export interface FragmentEventPayload {
25
25
  type: string;
26
26
  detail?: unknown;
27
27
  }
28
+ /**
29
+ * Fragment → host. The fragment's first content has settled: its own loading is done, not just its
30
+ * mount. Surfaced on the slot as the `settled` attribute and a `braid:settled` event.
31
+ *
32
+ * Separate from liveness on purpose. `healthy` proves the realm's event loop is turning, which is
33
+ * true from the first beat — while the application inside may still be showing its own spinner. Only
34
+ * the fragment knows when it has something worth looking at, so this is the fragment's to say, once.
35
+ */
36
+ export declare const SETTLED = "frag/settled";
37
+ /**
38
+ * Where a compat fragment finds its reporter: on its realm's global, under a registered symbol.
39
+ *
40
+ * A compat fragment is an unmodified app that never receives an env, so the one thing it may want
41
+ * to say has to be reachable from a global. A registered symbol rather than a name: it collides with
42
+ * nothing the app defines, and every copy of `@braidlabs/core` — the host's, and any bundled into
43
+ * the fragment — resolves the same one.
44
+ */
45
+ export declare const BRAID_FRAGMENT_REPORTER: unique symbol;
46
+ export interface BraidFragmentReporter {
47
+ /** Reports the fragment's first content as settled. Later calls do nothing. */
48
+ settled(): void;
49
+ }
50
+ /** The reporter the realm this code runs in was given, or undefined outside a Braid realm. */
51
+ export declare function braidFragmentReporter(): BraidFragmentReporter | undefined;
@@ -10,4 +10,26 @@
10
10
  export const PROPS_CHANGED = 'props/changed';
11
11
  /** Fragment → host. Surfaced on the slot element as `braid:event`. */
12
12
  export const FRAGMENT_EVENT = 'frag/event';
13
+ /**
14
+ * Fragment → host. The fragment's first content has settled: its own loading is done, not just its
15
+ * mount. Surfaced on the slot as the `settled` attribute and a `braid:settled` event.
16
+ *
17
+ * Separate from liveness on purpose. `healthy` proves the realm's event loop is turning, which is
18
+ * true from the first beat — while the application inside may still be showing its own spinner. Only
19
+ * the fragment knows when it has something worth looking at, so this is the fragment's to say, once.
20
+ */
21
+ export const SETTLED = 'frag/settled';
22
+ /**
23
+ * Where a compat fragment finds its reporter: on its realm's global, under a registered symbol.
24
+ *
25
+ * A compat fragment is an unmodified app that never receives an env, so the one thing it may want
26
+ * to say has to be reachable from a global. A registered symbol rather than a name: it collides with
27
+ * nothing the app defines, and every copy of `@braidlabs/core` — the host's, and any bundled into
28
+ * the fragment — resolves the same one.
29
+ */
30
+ export const BRAID_FRAGMENT_REPORTER = Symbol.for('braid.fragment');
31
+ /** The reporter the realm this code runs in was given, or undefined outside a Braid realm. */
32
+ export function braidFragmentReporter() {
33
+ return globalThis[BRAID_FRAGMENT_REPORTER];
34
+ }
13
35
  //# sourceMappingURL=messages.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"messages.js","sourceRoot":"","sources":["../../../../../libs/core/src/weave/messages.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,qFAAqF;AACrF,MAAM,CAAC,MAAM,aAAa,GAAG,eAAe,CAAC;AAE7C,sEAAsE;AACtE,MAAM,CAAC,MAAM,cAAc,GAAG,YAAY,CAAC"}
1
+ {"version":3,"file":"messages.js","sourceRoot":"","sources":["../../../../../libs/core/src/weave/messages.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,qFAAqF;AACrF,MAAM,CAAC,MAAM,aAAa,GAAG,eAAe,CAAC;AAE7C,sEAAsE;AACtE,MAAM,CAAC,MAAM,cAAc,GAAG,YAAY,CAAC;AAmB3C;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,cAAc,CAAC;AAEtC;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;AAOpE,8FAA8F;AAC9F,MAAM,UAAU,qBAAqB;IACnC,OAAQ,UAAgE,CAAC,uBAAuB,CAAC,CAAC;AACpG,CAAC"}