@braidlabs/core 0.1.1

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 (80) hide show
  1. package/README.md +123 -0
  2. package/package.json +37 -0
  3. package/src/adapters/adapter.d.ts +75 -0
  4. package/src/adapters/adapter.js +35 -0
  5. package/src/adapters/adapter.js.map +1 -0
  6. package/src/adapters/compat-adapter.d.ts +27 -0
  7. package/src/adapters/compat-adapter.js +113 -0
  8. package/src/adapters/compat-adapter.js.map +1 -0
  9. package/src/adapters/custom-element-adapter.d.ts +21 -0
  10. package/src/adapters/custom-element-adapter.js +91 -0
  11. package/src/adapters/custom-element-adapter.js.map +1 -0
  12. package/src/compat/born-inert-scripts.d.ts +30 -0
  13. package/src/compat/born-inert-scripts.js +85 -0
  14. package/src/compat/born-inert-scripts.js.map +1 -0
  15. package/src/compat/document-facade.d.ts +44 -0
  16. package/src/compat/document-facade.js +104 -0
  17. package/src/compat/document-facade.js.map +1 -0
  18. package/src/compat/document-member-classification.d.ts +30 -0
  19. package/src/compat/document-member-classification.js +64 -0
  20. package/src/compat/document-member-classification.js.map +1 -0
  21. package/src/compat/document-overrides.d.ts +44 -0
  22. package/src/compat/document-overrides.js +225 -0
  23. package/src/compat/document-overrides.js.map +1 -0
  24. package/src/compat/document-surface.generated.d.ts +21 -0
  25. package/src/compat/document-surface.generated.js +292 -0
  26. package/src/compat/document-surface.generated.js.map +1 -0
  27. package/src/compat/fragment-boundary.d.ts +14 -0
  28. package/src/compat/fragment-boundary.js +335 -0
  29. package/src/compat/fragment-boundary.js.map +1 -0
  30. package/src/compat/metadata.d.ts +15 -0
  31. package/src/compat/metadata.js +21 -0
  32. package/src/compat/metadata.js.map +1 -0
  33. package/src/compat/navigation-bus.d.ts +29 -0
  34. package/src/compat/navigation-bus.js +92 -0
  35. package/src/compat/navigation-bus.js.map +1 -0
  36. package/src/compat/realm-patches.d.ts +21 -0
  37. package/src/compat/realm-patches.js +573 -0
  38. package/src/compat/realm-patches.js.map +1 -0
  39. package/src/compat/register-worker.d.ts +45 -0
  40. package/src/compat/register-worker.js +57 -0
  41. package/src/compat/register-worker.js.map +1 -0
  42. package/src/compat/script-execution.d.ts +65 -0
  43. package/src/compat/script-execution.js +361 -0
  44. package/src/compat/script-execution.js.map +1 -0
  45. package/src/compat/service-worker.d.ts +22 -0
  46. package/src/compat/service-worker.js +104 -0
  47. package/src/compat/service-worker.js.map +1 -0
  48. package/src/config.d.ts +37 -0
  49. package/src/config.js +26 -0
  50. package/src/config.js.map +1 -0
  51. package/src/context/context-bus.d.ts +67 -0
  52. package/src/context/context-bus.js +117 -0
  53. package/src/context/context-bus.js.map +1 -0
  54. package/src/elements/fragment-slot.d.ts +39 -0
  55. package/src/elements/fragment-slot.js +281 -0
  56. package/src/elements/fragment-slot.js.map +1 -0
  57. package/src/env/create-env.d.ts +31 -0
  58. package/src/env/create-env.js +91 -0
  59. package/src/env/create-env.js.map +1 -0
  60. package/src/env/fragment-env.d.ts +56 -0
  61. package/src/env/fragment-env.js +14 -0
  62. package/src/env/fragment-env.js.map +1 -0
  63. package/src/errors.d.ts +21 -0
  64. package/src/errors.js +21 -0
  65. package/src/errors.js.map +1 -0
  66. package/src/index.d.ts +36 -0
  67. package/src/index.js +40 -0
  68. package/src/index.js.map +1 -0
  69. package/src/protocol.d.ts +38 -0
  70. package/src/protocol.js +45 -0
  71. package/src/protocol.js.map +1 -0
  72. package/src/realm/realm-manager.d.ts +60 -0
  73. package/src/realm/realm-manager.js +296 -0
  74. package/src/realm/realm-manager.js.map +1 -0
  75. package/src/utils/assert.d.ts +7 -0
  76. package/src/utils/assert.js +10 -0
  77. package/src/utils/assert.js.map +1 -0
  78. package/src/utils/selector-helpers.d.ts +10 -0
  79. package/src/utils/selector-helpers.js +13 -0
  80. package/src/utils/selector-helpers.js.map +1 -0
@@ -0,0 +1,91 @@
1
+ import { braidContext } from '../context/context-bus.js';
2
+ function parseEnvLocation(routeUrl) {
3
+ const url = new URL(routeUrl, document.baseURI);
4
+ return {
5
+ href: url.href,
6
+ pathname: url.pathname,
7
+ search: url.search,
8
+ hash: url.hash,
9
+ basePath: url.pathname,
10
+ };
11
+ }
12
+ /**
13
+ * Builds the FragmentEnv for a fragment instance.
14
+ *
15
+ * Compat fragments never consume the env — the compat adapter installs the full illusion
16
+ * instead — but the runtime constructs one uniformly so the adapter interface is the same
17
+ * for every adapter, and contract adapters can land later without touching the slot.
18
+ */
19
+ export function createFragmentEnv(options) {
20
+ const { contentRoot, shadowRoot, routeUrl, signal } = options;
21
+ let location = parseEnvLocation(routeUrl);
22
+ const historyListeners = new Set();
23
+ /** The version this fragment declared for a key, and the name to blame if it is unreachable. */
24
+ const contextOptions = (key) => ({
25
+ ...(options.contextVersions?.[key] === undefined ? {} : { as: options.contextVersions[key] }),
26
+ ...(options.fragmentId === undefined ? {} : { fragmentId: options.fragmentId }),
27
+ });
28
+ const applyNavigation = (url, state, replace) => {
29
+ const target = new URL(url, location.href);
30
+ if (replace) {
31
+ window.history.replaceState(state ?? null, '', target.href);
32
+ }
33
+ else {
34
+ window.history.pushState(state ?? null, '', target.href);
35
+ }
36
+ location = parseEnvLocation(target.href);
37
+ historyListeners.forEach((listener) => listener(location));
38
+ };
39
+ return {
40
+ contractVersion: '1.0',
41
+ root: contentRoot,
42
+ document: {
43
+ get title() {
44
+ return contentRoot.querySelector('title')?.textContent ?? '';
45
+ },
46
+ set title(value) {
47
+ const titleElement = contentRoot.querySelector('title');
48
+ if (titleElement) {
49
+ titleElement.textContent = value;
50
+ }
51
+ },
52
+ appendToHead(element) {
53
+ (contentRoot.querySelector('braid-head') ?? contentRoot).appendChild(element);
54
+ },
55
+ get activeElement() {
56
+ return shadowRoot.activeElement;
57
+ },
58
+ get adoptedStyleSheets() {
59
+ return shadowRoot.adoptedStyleSheets;
60
+ },
61
+ },
62
+ get location() {
63
+ return location;
64
+ },
65
+ history: {
66
+ push: (url, state) => applyNavigation(url, state, false),
67
+ replace: (url, state) => applyNavigation(url, state, true),
68
+ back: () => window.history.back(),
69
+ onChange(listener) {
70
+ historyListeners.add(listener);
71
+ const unsubscribe = () => historyListeners.delete(listener);
72
+ signal.addEventListener('abort', unsubscribe, { once: true });
73
+ return unsubscribe;
74
+ },
75
+ },
76
+ context: {
77
+ get: (key) => braidContext.get(key, contextOptions(key)),
78
+ subscribe: (key, listener, subscribeOptions) => braidContext.subscribe(key, listener, {
79
+ ...contextOptions(key),
80
+ signal: subscribeOptions?.signal ?? signal,
81
+ }),
82
+ },
83
+ get props() {
84
+ return options.getProps();
85
+ },
86
+ onPropsChanged: options.onPropsChanged,
87
+ emit: options.emit,
88
+ signal,
89
+ };
90
+ }
91
+ //# sourceMappingURL=create-env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-env.js","sourceRoot":"","sources":["../../../../../libs/core/src/env/create-env.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * `FragmentEnv` — the contract object graph a fragment sees instead of patched globals.
3
+ *
4
+ * Contract-mode fragments receive this env through their adapter's `mount(env, entry)` call and
5
+ * never touch realm globals. Compat-mode fragments (the only adapter shipped in this build) do
6
+ * not consume the env — the compat adapter installs the full document/window illusion instead —
7
+ * but the contract is defined here because it is the heart of the project and the adapter
8
+ * interface is written against it.
9
+ *
10
+ * Design rules: every member is a real object with a stable identity (no getters that change
11
+ * shape), every mutation path is explicit, and nothing on `FragmentEnv` requires the realm.
12
+ */
13
+ export interface EnvDocument {
14
+ /** Sets or reads the fragment's logical document title. Bound fragments propagate it to the host. */
15
+ title: string;
16
+ /** Appends a stylesheet or other head-scoped element to the fragment's head region. */
17
+ appendToHead(element: HTMLElement): void;
18
+ readonly activeElement: Element | null;
19
+ readonly adoptedStyleSheets: CSSStyleSheet[];
20
+ }
21
+ export interface EnvLocation {
22
+ readonly href: string;
23
+ readonly pathname: string;
24
+ readonly search: string;
25
+ readonly hash: string;
26
+ /** The base path the fragment is mounted under; adapters feed this into router configuration. */
27
+ readonly basePath: string;
28
+ }
29
+ export interface EnvHistory {
30
+ push(url: string, state?: unknown): void;
31
+ replace(url: string, state?: unknown): void;
32
+ back(): void;
33
+ /** Subscribes to location changes; automatically unsubscribed when `env.signal` aborts. */
34
+ onChange(listener: (location: EnvLocation) => void): () => void;
35
+ }
36
+ export interface EnvContext {
37
+ get(key: string): unknown;
38
+ subscribe(key: string, listener: (value: unknown) => void, options?: {
39
+ signal?: AbortSignal;
40
+ }): () => void;
41
+ }
42
+ export interface FragmentEnv {
43
+ readonly contractVersion: '1.0';
44
+ /** Mount point inside the fragment's shadow root. */
45
+ readonly root: HTMLElement;
46
+ readonly document: EnvDocument;
47
+ readonly location: EnvLocation;
48
+ readonly history: EnvHistory;
49
+ readonly context: EnvContext;
50
+ readonly props: Readonly<Record<string, unknown>>;
51
+ onPropsChanged(listener: (props: Readonly<Record<string, unknown>>) => void): () => void;
52
+ /** Fragment → host event channel, surfaced as `braid:event` on the slot element. */
53
+ emit(type: string, detail?: unknown): void;
54
+ /** Fires on unmount — wire everything to it. */
55
+ readonly signal: AbortSignal;
56
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * `FragmentEnv` — the contract object graph a fragment sees instead of patched globals.
3
+ *
4
+ * Contract-mode fragments receive this env through their adapter's `mount(env, entry)` call and
5
+ * never touch realm globals. Compat-mode fragments (the only adapter shipped in this build) do
6
+ * not consume the env — the compat adapter installs the full document/window illusion instead —
7
+ * but the contract is defined here because it is the heart of the project and the adapter
8
+ * interface is written against it.
9
+ *
10
+ * Design rules: every member is a real object with a stable identity (no getters that change
11
+ * shape), every mutation path is explicit, and nothing on `FragmentEnv` requires the realm.
12
+ */
13
+ export {};
14
+ //# sourceMappingURL=fragment-env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fragment-env.js","sourceRoot":"","sources":["../../../../../libs/core/src/env/fragment-env.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * The Braid error standard: every thrown or reported runtime error names the fragment,
3
+ * the failing stage, and — where we know it — the likely fix.
4
+ */
5
+ /** The lifecycle stage in which an error occurred. */
6
+ export type BraidErrorStage = 'slot-config' | 'fragment-fetch' | 'realm-boot' | 'adapter-resolution' | 'adapter-mount' | 'context-version';
7
+ export interface BraidErrorInit {
8
+ fragmentId: string;
9
+ stage: BraidErrorStage;
10
+ cause?: unknown;
11
+ /** The likely fix, phrased as an instruction to the developer. */
12
+ fixHint?: string;
13
+ docsUrl?: string;
14
+ }
15
+ export declare class BraidError extends Error {
16
+ readonly fragmentId: string;
17
+ readonly stage: BraidErrorStage;
18
+ readonly fixHint?: string;
19
+ readonly docsUrl?: string;
20
+ constructor(message: string, init: BraidErrorInit);
21
+ }
package/src/errors.js ADDED
@@ -0,0 +1,21 @@
1
+ /**
2
+ * The Braid error standard: every thrown or reported runtime error names the fragment,
3
+ * the failing stage, and — where we know it — the likely fix.
4
+ */
5
+ export class BraidError extends Error {
6
+ fragmentId;
7
+ stage;
8
+ fixHint;
9
+ docsUrl;
10
+ constructor(message, init) {
11
+ const hint = init.fixHint ? `\nLikely fix: ${init.fixHint}` : '';
12
+ const docs = init.docsUrl ? `\nDocs: ${init.docsUrl}` : '';
13
+ super(`[braid:${init.fragmentId}] ${init.stage}: ${message}${hint}${docs}`, { cause: init.cause });
14
+ this.name = 'BraidError';
15
+ this.fragmentId = init.fragmentId;
16
+ this.stage = init.stage;
17
+ this.fixHint = init.fixHint;
18
+ this.docsUrl = init.docsUrl;
19
+ }
20
+ }
21
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../../libs/core/src/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAoBH,MAAM,OAAO,UAAW,SAAQ,KAAK;IAC1B,UAAU,CAAS;IACnB,KAAK,CAAkB;IACvB,OAAO,CAAU;IACjB,OAAO,CAAU;IAE1B,YAAY,OAAe,EAAE,IAAoB;QAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,iBAAiB,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjE,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3D,KAAK,CAAC,UAAU,IAAI,CAAC,UAAU,KAAK,IAAI,CAAC,KAAK,KAAK,OAAO,GAAG,IAAI,GAAG,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QACnG,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;QACzB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;QAClC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACxB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC5B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;IAC9B,CAAC;CACF"}
package/src/index.d.ts ADDED
@@ -0,0 +1,36 @@
1
+ /**
2
+ * @braidlabs/core — the Braid client runtime.
3
+ *
4
+ * This build ships the compat adapter as the only — and default — adapter: legacy apps
5
+ * compose as fragments with zero app-code changes, config only.
6
+ *
7
+ * ```ts
8
+ * import { initBraid } from '@braidlabs/core';
9
+ * initBraid();
10
+ * ```
11
+ * ```html
12
+ * <fragment-slot name="checkout"></fragment-slot>
13
+ * ```
14
+ */
15
+ import { BraidOptions } from './config.js';
16
+ export { BraidError } from './errors.js';
17
+ export type { BraidErrorStage } from './errors.js';
18
+ export type { BraidOptions } from './config.js';
19
+ export type { FragmentEnv, EnvDocument, EnvLocation, EnvHistory, EnvContext } from './env/fragment-env.js';
20
+ export type { BraidAdapter } from './adapters/adapter.js';
21
+ export { DEFAULT_ADAPTER } from './adapters/adapter.js';
22
+ export { customElementAdapter } from './adapters/custom-element-adapter.js';
23
+ export { FragmentSlot } from './elements/fragment-slot.js';
24
+ export type { FragmentSlotState } from './elements/fragment-slot.js';
25
+ export { braidContext } from './context/context-bus.js';
26
+ export { registerBraidServiceWorker } from './compat/register-worker.js';
27
+ export type { RegisterBraidServiceWorkerOptions } from './compat/register-worker.js';
28
+ export type { ContextSubscribeOptions, ContextReadOptions } from './context/context-bus.js';
29
+ export { createRealm } from './realm/realm-manager.js';
30
+ export type { RealmKind, RealmHandle, RealmInit, RealmImportMap } from './realm/realm-manager.js';
31
+ export { BRAID_FRAGMENT_PREFIX, BRAID_REALM_PREFIX, BRAID_DOCUMENT_PREFIX, BRAID_PROTOCOL_VERSION, } from './protocol.js';
32
+ /**
33
+ * Initializes the Braid client: applies configuration, installs the default compat adapter,
34
+ * and registers the `<fragment-slot>` element. Call once, before any slot connects.
35
+ */
36
+ export declare function initBraid(options?: BraidOptions): void;
package/src/index.js ADDED
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @braidlabs/core — the Braid client runtime.
3
+ *
4
+ * This build ships the compat adapter as the only — and default — adapter: legacy apps
5
+ * compose as fragments with zero app-code changes, config only.
6
+ *
7
+ * ```ts
8
+ * import { initBraid } from '@braidlabs/core';
9
+ * initBraid();
10
+ * ```
11
+ * ```html
12
+ * <fragment-slot name="checkout"></fragment-slot>
13
+ * ```
14
+ */
15
+ import { setBraidConfig } from './config.js';
16
+ import { installAdapter } from './adapters/adapter.js';
17
+ import { compatAdapter } from './adapters/compat-adapter.js';
18
+ import { customElementAdapter } from './adapters/custom-element-adapter.js';
19
+ import { FragmentSlot } from './elements/fragment-slot.js';
20
+ export { BraidError } from './errors.js';
21
+ export { DEFAULT_ADAPTER } from './adapters/adapter.js';
22
+ export { customElementAdapter } from './adapters/custom-element-adapter.js';
23
+ export { FragmentSlot } from './elements/fragment-slot.js';
24
+ export { braidContext } from './context/context-bus.js';
25
+ export { registerBraidServiceWorker } from './compat/register-worker.js';
26
+ export { createRealm } from './realm/realm-manager.js';
27
+ export { BRAID_FRAGMENT_PREFIX, BRAID_REALM_PREFIX, BRAID_DOCUMENT_PREFIX, BRAID_PROTOCOL_VERSION, } from './protocol.js';
28
+ /**
29
+ * Initializes the Braid client: applies configuration, installs the default compat adapter,
30
+ * and registers the `<fragment-slot>` element. Call once, before any slot connects.
31
+ */
32
+ export function initBraid(options = {}) {
33
+ setBraidConfig(options);
34
+ installAdapter(compatAdapter);
35
+ installAdapter(customElementAdapter);
36
+ if (!customElements.get('fragment-slot')) {
37
+ customElements.define('fragment-slot', FragmentSlot);
38
+ }
39
+ }
40
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/core/src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAgB,cAAc,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAE3D,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAKzC,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAE3D,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAC;AAGzE,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,eAAe,CAAC;AAEvB;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,UAAwB,EAAE;IAClD,cAAc,CAAC,OAAO,CAAC,CAAC;IACxB,cAAc,CAAC,aAAa,CAAC,CAAC;IAC9B,cAAc,CAAC,oBAAoB,CAAC,CAAC;IAErC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC;QACzC,cAAc,CAAC,MAAM,CAAC,eAAe,EAAE,YAAY,CAAC,CAAC;IACvD,CAAC;AACH,CAAC"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Client side of the Braid composition protocol.
3
+ *
4
+ * These constants are deliberately duplicated in `@braidlabs/gateway/src/protocol.ts`:
5
+ * the client and gateway bundles do not share modules, but always ship in the same package
6
+ * version, and the protocol version below is how a mismatch is detected and reported as a
7
+ * named error instead of a silent misbehavior.
8
+ */
9
+ /**
10
+ * The three reserved namespaces, one per kind of thing the gateway serves.
11
+ *
12
+ * They are separate paths rather than one path distinguished by request headers, so that
13
+ * `/__braid/frag/*` — the fragment's own assets, which is nearly all the traffic — has no
14
+ * request-header variance and caches on URL alone.
15
+ */
16
+ export declare const BRAID_FRAGMENT_PREFIX = "/__braid/frag/";
17
+ export declare const BRAID_REALM_PREFIX = "/__braid/realm/";
18
+ export declare const BRAID_DOCUMENT_PREFIX = "/__braid/doc/";
19
+ /**
20
+ * Version of the client ↔ gateway composition protocol. The gateway stamps its version onto the
21
+ * realm stub document; the client verifies it at realm boot and fails with a named error on
22
+ * mismatch. v2 split the single fragment namespace into frag/realm/doc.
23
+ */
24
+ export declare const BRAID_PROTOCOL_VERSION = "2";
25
+ /** Name of the `<meta>` element carrying the protocol version in the realm stub document. */
26
+ export declare const BRAID_PROTOCOL_META = "braid-protocol";
27
+ /** Name of the `<meta>` element carrying the fragment's manifest-declared adapter in the realm stub. */
28
+ export declare const BRAID_ADAPTER_META = "braid-adapter";
29
+ /** Name of the `<meta>` carrying adapter-specific options as JSON (see the gateway's copy). */
30
+ export declare const BRAID_ADAPTER_OPTIONS_META = "braid-adapter-options";
31
+ /** Response/request header carrying a fragment id for diagnostics. */
32
+ export declare const BRAID_FRAGMENT_ID_HEADER = "x-braid-fragment-id";
33
+ /** The fragment's asset namespace: what its own relative URLs resolve into. */
34
+ export declare function braidFragmentUrl(fragmentId: string, pathname: string, search?: string): string;
35
+ /** The realm stub document a fragment's hidden iframe boots from. */
36
+ export declare function braidRealmUrl(fragmentId: string, pathname: string, search?: string): string;
37
+ /** The fragment's document, prepared by the gateway for life inside the host page's DOM. */
38
+ export declare function braidDocumentUrl(fragmentId: string, pathname: string, search?: string): string;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Client side of the Braid composition protocol.
3
+ *
4
+ * These constants are deliberately duplicated in `@braidlabs/gateway/src/protocol.ts`:
5
+ * the client and gateway bundles do not share modules, but always ship in the same package
6
+ * version, and the protocol version below is how a mismatch is detected and reported as a
7
+ * named error instead of a silent misbehavior.
8
+ */
9
+ /**
10
+ * The three reserved namespaces, one per kind of thing the gateway serves.
11
+ *
12
+ * They are separate paths rather than one path distinguished by request headers, so that
13
+ * `/__braid/frag/*` — the fragment's own assets, which is nearly all the traffic — has no
14
+ * request-header variance and caches on URL alone.
15
+ */
16
+ export const BRAID_FRAGMENT_PREFIX = '/__braid/frag/';
17
+ export const BRAID_REALM_PREFIX = '/__braid/realm/';
18
+ export const BRAID_DOCUMENT_PREFIX = '/__braid/doc/';
19
+ /**
20
+ * Version of the client ↔ gateway composition protocol. The gateway stamps its version onto the
21
+ * realm stub document; the client verifies it at realm boot and fails with a named error on
22
+ * mismatch. v2 split the single fragment namespace into frag/realm/doc.
23
+ */
24
+ export const BRAID_PROTOCOL_VERSION = '2';
25
+ /** Name of the `<meta>` element carrying the protocol version in the realm stub document. */
26
+ export const BRAID_PROTOCOL_META = 'braid-protocol';
27
+ /** Name of the `<meta>` element carrying the fragment's manifest-declared adapter in the realm stub. */
28
+ export const BRAID_ADAPTER_META = 'braid-adapter';
29
+ /** Name of the `<meta>` carrying adapter-specific options as JSON (see the gateway's copy). */
30
+ export const BRAID_ADAPTER_OPTIONS_META = 'braid-adapter-options';
31
+ /** Response/request header carrying a fragment id for diagnostics. */
32
+ export const BRAID_FRAGMENT_ID_HEADER = 'x-braid-fragment-id';
33
+ /** The fragment's asset namespace: what its own relative URLs resolve into. */
34
+ export function braidFragmentUrl(fragmentId, pathname, search = '') {
35
+ return `${BRAID_FRAGMENT_PREFIX}${encodeURIComponent(fragmentId)}${pathname}${search}`;
36
+ }
37
+ /** The realm stub document a fragment's hidden iframe boots from. */
38
+ export function braidRealmUrl(fragmentId, pathname, search = '') {
39
+ return `${BRAID_REALM_PREFIX}${encodeURIComponent(fragmentId)}${pathname}${search}`;
40
+ }
41
+ /** The fragment's document, prepared by the gateway for life inside the host page's DOM. */
42
+ export function braidDocumentUrl(fragmentId, pathname, search = '') {
43
+ return `${BRAID_DOCUMENT_PREFIX}${encodeURIComponent(fragmentId)}${pathname}${search}`;
44
+ }
45
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../../../libs/core/src/protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,gBAAgB,CAAC;AACtD,MAAM,CAAC,MAAM,kBAAkB,GAAG,iBAAiB,CAAC;AACpD,MAAM,CAAC,MAAM,qBAAqB,GAAG,eAAe,CAAC;AAErD;;;;GAIG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,CAAC;AAE1C,6FAA6F;AAC7F,MAAM,CAAC,MAAM,mBAAmB,GAAG,gBAAgB,CAAC;AAEpD,wGAAwG;AACxG,MAAM,CAAC,MAAM,kBAAkB,GAAG,eAAe,CAAC;AAElD,+FAA+F;AAC/F,MAAM,CAAC,MAAM,0BAA0B,GAAG,uBAAuB,CAAC;AAElE,sEAAsE;AACtE,MAAM,CAAC,MAAM,wBAAwB,GAAG,qBAAqB,CAAC;AAE9D,+EAA+E;AAC/E,MAAM,UAAU,gBAAgB,CAAC,UAAkB,EAAE,QAAgB,EAAE,MAAM,GAAG,EAAE;IAChF,OAAO,GAAG,qBAAqB,GAAG,kBAAkB,CAAC,UAAU,CAAC,GAAG,QAAQ,GAAG,MAAM,EAAE,CAAC;AACzF,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,aAAa,CAAC,UAAkB,EAAE,QAAgB,EAAE,MAAM,GAAG,EAAE;IAC7E,OAAO,GAAG,kBAAkB,GAAG,kBAAkB,CAAC,UAAU,CAAC,GAAG,QAAQ,GAAG,MAAM,EAAE,CAAC;AACtF,CAAC;AAED,4FAA4F;AAC5F,MAAM,UAAU,gBAAgB,CAAC,UAAkB,EAAE,QAAgB,EAAE,MAAM,GAAG,EAAE;IAChF,OAAO,GAAG,qBAAqB,GAAG,kBAAkB,CAAC,UAAU,CAAC,GAAG,QAAQ,GAAG,MAAM,EAAE,CAAC;AACzF,CAAC"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Realm manager. A realm is the isolated JS context a fragment executes in — a hidden
3
+ * same-origin iframe, the only browser primitive providing a synchronous, DOM-capable second
4
+ * JavaScript context.
5
+ *
6
+ * Realm kinds:
7
+ * - `compat-http` — boots from a real `http:` URL inside the gateway namespace
8
+ * (`/__braid/frag/:id/…`), because only a real URL can make the global `location`/`history`
9
+ * illusion truthful (`history.replaceState` cannot rewrite a `blob:` document to an `http:`
10
+ * URL). The stub's `<base>` keeps relative subresource requests inside the namespace; the
11
+ * fragment's route-url illusion is restored via `replaceState` once the iframe loads.
12
+ * - `contract-blob` — boots from a runtime-authored `blob:` URL; zero interaction with the
13
+ * joint session history. Not shipped in this build (compat-only).
14
+ * - `sandbox` — a real sandboxed cross-origin iframe for the untrusted tier. Not shipped in
15
+ * this build.
16
+ */
17
+ export type RealmKind = 'contract-blob' | 'compat-http' | 'sandbox';
18
+ /** An import map, scoped to a single realm's document. */
19
+ export interface RealmImportMap {
20
+ imports?: Record<string, string>;
21
+ scopes?: Record<string, Record<string, string>>;
22
+ }
23
+ export interface RealmInit {
24
+ fragmentId: string;
25
+ /** The fragment's logical route URL (pathname + search) restored after boot. */
26
+ routeUrl: string;
27
+ /** Whether the fragment's navigation is bound to the host window's navigation. */
28
+ bound: boolean;
29
+ /** Abort signal owned by the fragment instance; disposal is wired to it. */
30
+ signal: AbortSignal;
31
+ /**
32
+ * The fragment's own import map (contract-blob realms only). Because every fragment gets its
33
+ * own realm document, each gets its own import map for free — which is how two fragments can
34
+ * ship different majors of the same dependency without a shared resolution namespace.
35
+ */
36
+ importMap?: RealmImportMap;
37
+ }
38
+ export interface RealmHandle {
39
+ readonly kind: RealmKind;
40
+ /** The fragment this realm belongs to. */
41
+ readonly fragmentId: string;
42
+ readonly window: Window & typeof globalThis;
43
+ readonly document: Document;
44
+ /**
45
+ * The adapter name the gateway stamped onto the realm stub from the fragment's manifest.
46
+ * Null for realms the runtime authors itself (there is no stub to read it from).
47
+ */
48
+ readonly manifestAdapter: string | null;
49
+ /**
50
+ * Adapter-specific options the gateway stamped onto the realm stub from the manifest — which
51
+ * custom element to mount, which entry module to evaluate. Empty for realms with no stub.
52
+ */
53
+ readonly adapterOptions: Readonly<Record<string, unknown>>;
54
+ /** Loads and evaluates a module by URL inside the realm. */
55
+ evaluate(entryUrl: string): Promise<void>;
56
+ /** Evaluates module source inside the realm. Resolves once the module has run. */
57
+ evaluateModule(source: string): Promise<boolean>;
58
+ dispose(): void;
59
+ }
60
+ export declare function createRealm(kind: RealmKind, init: RealmInit): Promise<RealmHandle>;