@braidlabs/gateway 0.3.0 → 0.5.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.
package/README.md CHANGED
@@ -45,8 +45,9 @@ to load, and the element to mount:
45
45
  createGateway({ registry, discovery: { appd: true } });
46
46
  ```
47
47
 
48
- Serves the same registry in FDC3 App Directory shape at `/__braid/registry/appd/v2/apps` (and
49
- `/appd/v2/apps/{appId}`). It is a **projection, not a second directory** — same manifests, same
48
+ Serves the same registry as an FDC3 2.2 App Directory: `/__braid/registry/appd/v2/apps` lists
49
+ `{ applications, message }`, and `/appd/v2/apps/{appId}` returns the bare `Application` record.
50
+ It is a **projection, not a second directory** — same manifests, same
50
51
  `access.list` rules — so a caller can never see through AppD a resolver that discovery would have
51
52
  hidden. `findIntent` becomes a registry query, and a user only sees resolvers they may use.
52
53
 
@@ -69,11 +70,17 @@ Two mapping decisions worth knowing:
69
70
  A fragment is *mounted into a page*, not opened as a window, so a Braid-aware agent reads
70
71
  `hostManifests.braid` and mounts a `<fragment-slot>`; one that does not falls back to the URL.
71
72
 
72
- An app the caller may not list 404s exactly as an unregistered one does — distinguishing them would
73
- let an unauthorized caller enumerate the registry one id at a time.
73
+ An app the caller may not list 404s (with AppD's `{ code, message }` error body) exactly as an
74
+ unregistered one does — distinguishing them would let an unauthorized caller enumerate the registry
75
+ one id at a time.
74
76
 
75
- Verify the record shape against the FDC3 AppD v2 spec before depending on it; the schema carries
76
- more optional members than this projects.
77
+ Records are validated in the test suite against FDC3 2.2's own App Directory schema. Relative icon
78
+ `src` values are resolved against the origin, since AppD requires absolute URLs, and a link that is
79
+ not http(s) is dropped rather than passed on. Optional members
80
+ Braid has no data for (`lang`, `screenshots`, `localizedVersions`, `interop.appChannels`) are not
81
+ produced. To serve the same directory from the governed registry instead of a gateway, see
82
+ `createRegistryApi({ appd })` in `@braidlabs/registry`; to give fragments `window.fdc3`, see
83
+ `@braidlabs/fdc3`.
77
84
 
78
85
  A relative `entry` is re-rooted into the fragment's namespace, so the module and its imports are
79
86
  fetched through the gateway rather than from the host's root. Such a fragment serves no document,
@@ -166,6 +173,13 @@ as a declarative shadow root, so the browser parses it into exactly the shape th
166
173
  would have built; the slot then adopts it instead of fetching. Shells with no matching slot get
167
174
  one created before `</body>`.
168
175
 
176
+ A shell can instead mark one `<fragment-slot outlet>`. It takes the page's routed (bound) fragment,
177
+ the first in registration order that no earlier named slot claimed, and is named after it. A shell
178
+ that composes many routes then needs one slot rather than one per fragment id. Unbound widgets
179
+ never fill an outlet. A named slot after the outlet is too late for a fragment the outlet already
180
+ took, so the gateway unnames it (`data-braid-in-outlet`) and warns, rather than let the client boot
181
+ a second copy. The outlet is filled on full page loads only.
182
+
169
183
  Fragment HTML is transformed on the way through: the doctype is stripped, `<html>/<head>/<body>`
170
184
  become `braid-html/braid-head/braid-body` (start *and* end tags), scripts are neutralized to
171
185
  `type="inert"`, and script preload links become `rel="inert-*"`. Fragment scripts are therefore
@@ -547,6 +561,11 @@ user against the shell. A fragment that needs to know who is asking should be gi
547
561
  scoped to it: a per-request assertion via `additionalHeaders`, or a token exchanged for the
548
562
  fragment's own audience. `forwardCredentials: true` restores the old behaviour, and is only
549
563
  appropriate when every endpoint in the registry sits inside the same trust boundary as the shell.
564
+ When only some do, pass a function instead, `forwardCredentials: (fragment) => …`, and the gateway
565
+ decides per fragment. A function that throws forwards nothing, and websocket upgrades follow the
566
+ same decision. `proxy-authorization` is stripped with them, and `credentialHeaders` adds any
567
+ identity header an auth proxy in front of the shell injects (`x-auth-request-access-token`,
568
+ `cf-access-jwt-assertion`, …).
550
569
 
551
570
  Not yet implemented from the architecture's security section: allow-listed manifest origins and
552
571
  signed manifests. Until those land, treat the registry as trusted configuration.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@braidlabs/gateway",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "Braid gateway — fetch-native origin-front middleware that routes fragment traffic by exact id under the reserved /__braid/frag/ namespace, loads fragment manifests, and passes everything else through to your existing app.",
5
5
  "keywords": [
6
6
  "micro-frontends",
package/src/appd.d.ts CHANGED
@@ -11,9 +11,9 @@ import type { ResolvedFragmentManifest } from './registry.js';
11
11
  * The payoff for FDC3 is direct: `findIntent` becomes a registry query, and because discovery
12
12
  * filters by the caller's principal, a user only ever sees resolvers they are permitted to use.
13
13
  *
14
- * **Verify the record shape against the FDC3 AppD v2 spec before relying on it.** The mapping below
15
- * is faithful to the standard as understood here, but the schema has more optional members than
16
- * this uses and is the kind of thing that is easy to be subtly wrong about.
14
+ * Records are checked against FDC3 2.2's own AppD schema in `appd.spec.ts` (vendored under
15
+ * `tools/fdc3/`). Optional members Braid has no data for — `lang`, `screenshots`,
16
+ * `localizedVersions`, `interop.appChannels` — are not produced.
17
17
  */
18
18
  /** The `fdc3` block a manifest may carry. A superset of what AppD needs; the rest is for the runtime. */
19
19
  export interface FragmentFdc3Metadata {
@@ -51,14 +51,14 @@ export interface FragmentAppdMetadata {
51
51
  type?: string;
52
52
  }[];
53
53
  }
54
+ /** An FDC3 AppD v2 `Application` record — the members Braid fills. */
54
55
  export interface AppdApplication {
55
56
  appId: string;
56
- name: string;
57
+ title: string;
57
58
  type: 'web';
58
59
  details: {
59
60
  url: string;
60
61
  };
61
- title?: string;
62
62
  description?: string;
63
63
  tooltip?: string;
64
64
  version?: string;
@@ -75,7 +75,6 @@ export interface AppdApplication {
75
75
  interop?: {
76
76
  intents?: {
77
77
  listensFor?: Record<string, {
78
- name: string;
79
78
  displayName?: string;
80
79
  contexts: string[];
81
80
  resultType?: string;
@@ -110,10 +109,29 @@ export interface AppdListResponse {
110
109
  applications: AppdApplication[];
111
110
  message: string;
112
111
  }
113
- export interface AppdAppResponse {
114
- application: AppdApplication;
112
+ /** AppD's error body, `ErrorDTO`. */
113
+ export interface AppdError {
114
+ code: number;
115
115
  message: string;
116
116
  }
117
+ /**
118
+ * The App Directory's two reads over a set of manifests the caller may already see: the listing,
119
+ * or one application by `appId`. `GET /v2/apps/{appId}` answers with the bare `Application`, not
120
+ * a wrapper. Headers are the caller's — what may be cached differs between the gateway, whose
121
+ * listing depends on who asked, and the registry.
122
+ */
123
+ export declare function appdResponse(options: {
124
+ manifests: readonly ResolvedFragmentManifest[];
125
+ origin: string;
126
+ /** Present for `/v2/apps/{appId}`, absent for the listing. */
127
+ appId?: string;
128
+ }): {
129
+ status: 200;
130
+ body: AppdListResponse | AppdApplication;
131
+ } | {
132
+ status: 404;
133
+ body: AppdError;
134
+ };
117
135
  /**
118
136
  * Projects one manifest into an AppD record.
119
137
  *
package/src/appd.js CHANGED
@@ -1,4 +1,31 @@
1
1
  import { BRAID_FRAGMENT_PREFIX } from './protocol.js';
2
+ /**
3
+ * The App Directory's two reads over a set of manifests the caller may already see: the listing,
4
+ * or one application by `appId`. `GET /v2/apps/{appId}` answers with the bare `Application`, not
5
+ * a wrapper. Headers are the caller's — what may be cached differs between the gateway, whose
6
+ * listing depends on who asked, and the registry.
7
+ */
8
+ export function appdResponse(options) {
9
+ const { manifests, origin, appId } = options;
10
+ if (appId === undefined) {
11
+ // one manifest the projection cannot read is left out, not allowed to fail everyone's listing
12
+ const applications = manifests.flatMap((manifest) => {
13
+ try {
14
+ return [toAppdApplication(manifest, origin)];
15
+ }
16
+ catch {
17
+ return [];
18
+ }
19
+ });
20
+ return { status: 200, body: { applications, message: 'OK' } };
21
+ }
22
+ const match = manifests.find((manifest) => manifest.id === appId);
23
+ // the same 404 for "not visible to you" as for "not registered" — distinguishing them would let
24
+ // an unauthorized caller enumerate the registry one id at a time
25
+ if (!match)
26
+ return { status: 404, body: { code: 404, message: `No application with appId "${appId}"` } };
27
+ return { status: 200, body: toAppdApplication(match, origin) };
28
+ }
2
29
  /**
3
30
  * Projects one manifest into an AppD record.
4
31
  *
@@ -15,12 +42,12 @@ import { BRAID_FRAGMENT_PREFIX } from './protocol.js';
15
42
  export function toAppdApplication(manifest, origin) {
16
43
  const mount = `${BRAID_FRAGMENT_PREFIX}${encodeURIComponent(manifest.id)}/`;
17
44
  const page = firstPiercePage(manifest.pierce);
45
+ // `name` is deprecated in AppD v2 in favour of `appId` and `title`, so it is not set.
18
46
  const application = {
19
47
  appId: manifest.id,
20
- name: manifest.id,
48
+ title: manifest.title ?? manifest.id,
21
49
  type: 'web',
22
50
  details: { url: new URL(page ?? mount, origin).href },
23
- title: manifest.title ?? manifest.id,
24
51
  hostManifests: {
25
52
  braid: { fragmentId: manifest.id, mount, adapter: manifest.adapter, standalonePage: page !== null },
26
53
  },
@@ -36,14 +63,20 @@ export function toAppdApplication(manifest, origin) {
36
63
  application.contactEmail = appd.contactEmail;
37
64
  if (appd?.supportEmail)
38
65
  application.supportEmail = appd.supportEmail;
39
- if (appd?.moreInfo)
40
- application.moreInfo = appd.moreInfo;
66
+ const moreInfo = appd?.moreInfo ? webUrl(appd.moreInfo, origin) : null;
67
+ if (moreInfo)
68
+ application.moreInfo = moreInfo;
41
69
  if (appd?.version)
42
70
  application.version = appd.version;
43
71
  if (appd?.tooltip)
44
72
  application.tooltip = appd.tooltip;
45
- if (appd?.icons?.length)
46
- application.icons = appd.icons.map((icon) => ({ ...icon }));
73
+ // AppD requires an absolute icon url; a manifest may name one relative to the shell
74
+ const icons = (appd?.icons ?? []).flatMap((icon) => {
75
+ const src = webUrl(icon.src, origin);
76
+ return src ? [{ ...icon, src }] : [];
77
+ });
78
+ if (icons.length)
79
+ application.icons = icons;
47
80
  const interop = toInterop(manifest.fdc3);
48
81
  if (interop)
49
82
  application.interop = interop;
@@ -53,10 +86,8 @@ function toInterop(fdc3) {
53
86
  if (!fdc3)
54
87
  return undefined;
55
88
  const listensFor = Object.entries(fdc3.listensFor ?? {}).reduce((accumulator, [intent, declaration]) => {
56
- // `name` is required on an AppD intent record and duplicates the key. Filling it from the key
57
- // rather than requiring it in the manifest keeps one source of truth for the intent's name.
89
+ // the key is the intent's name; AppD v2's intent record has no `name` member of its own
58
90
  accumulator[intent] = {
59
- name: intent,
60
91
  contexts: declaration.contexts ?? [],
61
92
  ...(declaration.displayName ? { displayName: declaration.displayName } : {}),
62
93
  ...(declaration.resultType ? { resultType: declaration.resultType } : {}),
@@ -73,6 +104,22 @@ function toInterop(fdc3) {
73
104
  };
74
105
  return Object.keys(interop).length > 0 ? interop : undefined;
75
106
  }
107
+ /**
108
+ * A manifest-supplied link, absolute on `origin`, or null when it is not an http(s) URL. Dropping
109
+ * a bad one keeps one manifest's typo from failing the whole listing, and keeps `javascript:` out
110
+ * of every launcher that renders the directory.
111
+ */
112
+ function webUrl(value, origin) {
113
+ if (typeof value !== 'string')
114
+ return null;
115
+ try {
116
+ const url = new URL(value, origin);
117
+ return url.protocol === 'https:' || url.protocol === 'http:' ? url.href : null;
118
+ }
119
+ catch {
120
+ return null;
121
+ }
122
+ }
76
123
  /**
77
124
  * The first pierce pattern reduced to a concrete page path.
78
125
  *
package/src/appd.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"appd.js","sourceRoot":"","sources":["../../../../libs/braid-gateway/src/appd.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"appd.js","sourceRoot":"","sources":["../../../../libs/braid-gateway/src/appd.ts"],"names":[],"mappings":"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"}
package/src/breaker.d.ts CHANGED
@@ -40,6 +40,8 @@ export interface Breaker {
40
40
  succeeded(fragmentId: string): void;
41
41
  failed(fragmentId: string): void;
42
42
  stateOf(fragmentId: string): BreakerState;
43
+ /** Drops a fragment's circuit — after a registry refresh removed it or changed its endpoint. */
44
+ forget(fragmentId: string): void;
43
45
  }
44
46
  /**
45
47
  * Creates a breaker.
package/src/breaker.js CHANGED
@@ -64,6 +64,9 @@ export function createBreaker(options = {}, onTransition, now = Date.now) {
64
64
  circuit.probing = true;
65
65
  return true;
66
66
  },
67
+ forget(fragmentId) {
68
+ circuits.delete(fragmentId);
69
+ },
67
70
  succeeded(fragmentId) {
68
71
  const circuit = circuitFor(fragmentId);
69
72
  circuit.failures = 0;
@@ -1 +1 @@
1
- {"version":3,"file":"breaker.js","sourceRoot":"","sources":["../../../../libs/braid-gateway/src/breaker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"breaker.js","sourceRoot":"","sources":["../../../../libs/braid-gateway/src/breaker.ts"],"names":[],"mappings":"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"}
package/src/discovery.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { BRAID_FRAGMENT_PREFIX, BRAID_PROTOCOL_VERSION } from './protocol.js';
2
- import { toAppdApplication } from './appd.js';
2
+ import { appdResponse } from './appd.js';
3
3
  import { canFetch, canList } from './registry.js';
4
4
  export const DEFAULT_DISCOVERY_PATH = '/__braid/registry';
5
5
  export const DEFAULT_DISCOVERY_PAGE_SIZE = 100;
@@ -41,22 +41,15 @@ export function createDiscoveryHandler(registry, options, mode, resolvePrincipal
41
41
  // so a caller can never see a resolver through AppD that discovery would have hidden.
42
42
  if (appdEnabled && url.pathname.startsWith(appdPath)) {
43
43
  const requested = url.pathname.slice(appdPath.length).replace(/^\//, '');
44
- if (!requested) {
45
- const body = {
46
- applications: visible.map((manifest) => toAppdApplication(manifest, url.origin)),
47
- message: 'OK',
48
- };
49
- return json(body, 200, { 'Cache-Control': 'no-store', Vary: 'cookie, authorization' });
50
- }
51
- const appId = decodeURIComponent(requested);
52
- const match = visible.find((manifest) => manifest.id === appId);
53
- if (!match) {
54
- // 404 for "not visible to you" as well as "not registered" — distinguishing them would
55
- // let an unauthorized caller enumerate the registry one id at a time.
56
- return json({ message: `No application with appId "${appId}"` }, 404, { 'Cache-Control': 'no-store' });
57
- }
58
- const body = { application: toAppdApplication(match, url.origin), message: 'OK' };
59
- return json(body, 200, { 'Cache-Control': 'no-store', Vary: 'cookie, authorization' });
44
+ const { status, body } = appdResponse({
45
+ manifests: visible,
46
+ origin: url.origin,
47
+ ...(requested ? { appId: safeDecode(requested) } : {}),
48
+ });
49
+ return json(body, status, {
50
+ 'Cache-Control': 'no-store',
51
+ ...(status === 200 ? { Vary: 'cookie, authorization' } : {}),
52
+ });
60
53
  }
61
54
  const pageSize = clampPageSize(url.searchParams.get('pageSize'), defaultPageSize, maxPageSize);
62
55
  const totalPages = Math.max(1, Math.ceil(visible.length / pageSize));
@@ -118,6 +111,15 @@ function clampPage(requested, totalPages) {
118
111
  return 1;
119
112
  return Math.min(parsed, totalPages);
120
113
  }
114
+ /** A malformed escape names no application, rather than throwing. */
115
+ function safeDecode(segment) {
116
+ try {
117
+ return decodeURIComponent(segment);
118
+ }
119
+ catch {
120
+ return segment;
121
+ }
122
+ }
121
123
  function json(body, status, headers = {}) {
122
124
  return new Response(JSON.stringify(body), {
123
125
  status,
@@ -1 +1 @@
1
- {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../../../libs/braid-gateway/src/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAA+C,MAAM,WAAW,CAAC;AAC3F,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAiD,MAAM,eAAe,CAAC;AAuFjG,MAAM,CAAC,MAAM,sBAAsB,GAAG,mBAAmB,CAAC;AAC1D,MAAM,CAAC,MAAM,2BAA2B,GAAG,GAAG,CAAC;AAE/C;;;;;;GAMG;AACH,MAAM,UAAU,sBAAsB,CACpC,QAAkB,EAClB,OAAqC,EACrC,IAAkC,EAClC,gBAAsE;IAEtE,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAE1B,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,sBAAsB,CAAC;IACpD,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,WAAW,IAAI,2BAA2B,CAAC,CAAC;IACpF,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,QAAQ,IAAI,2BAA2B,CAAC,EAAE,WAAW,CAAC,CAAC;IAC5G,MAAM,aAAa,GAAG,IAAI,KAAK,aAAa,CAAC;IAC7C,MAAM,gBAAgB,GAAG,aAAa,IAAI,CAAC,OAAO,CAAC,gBAAgB,IAAI,KAAK,CAAC,CAAC;IAE9E,IAAI,aAAa,EAAE,CAAC;QAClB,OAAO,CAAC,IAAI,CACV,6CAA6C,IAAI,oDAAoD;YACnG,sGAAsG,CACzG,CAAC;IACJ,CAAC;IAED,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,IAAI,KAAK,CAAC;IAC1C,MAAM,QAAQ,GAAG,GAAG,IAAI,eAAe,CAAC;IAExC,OAAO;QACL,IAAI;QACJ,mFAAmF;QACnF,IAAI,CAAC,QAAgB;YACnB,OAAO,QAAQ,KAAK,IAAI,IAAI,CAAC,WAAW,IAAI,CAAC,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC;QAC9G,CAAC;QAED,KAAK,CAAC,MAAM,CAAC,OAAgB,EAAE,GAAQ;YACrC,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;gBAC1D,OAAO,IAAI,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;YAC5E,CAAC;YAED,MAAM,SAAS,GAAG,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,gBAAgB,CAAC,OAAO,CAAC,CAAC;YAC9E,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,aAAa,EAAE,CAAC;YAC3C,MAAM,OAAO,GAAG,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC;YAE7F,2FAA2F;YAC3F,sFAAsF;YACtF,IAAI,WAAW,IAAI,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACrD,MAAM,SAAS,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;gBAEzE,IAAI,CAAC,SAAS,EAAE,CAAC;oBACf,MAAM,IAAI,GAAqB;wBAC7B,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,iBAAiB,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;wBAChF,OAAO,EAAE,IAAI;qBACd,CAAC;oBACF,OAAO,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,eAAe,EAAE,UAAU,EAAE,IAAI,EAAE,uBAAuB,EAAE,CAAC,CAAC;gBACzF,CAAC;gBAED,MAAM,KAAK,GAAG,kBAAkB,CAAC,SAAS,CAAC,CAAC;gBAC5C,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,KAAK,KAAK,CAAC,CAAC;gBAChE,IAAI,CAAC,KAAK,EAAE,CAAC;oBACX,uFAAuF;oBACvF,sEAAsE;oBACtE,OAAO,IAAI,CAAC,EAAE,OAAO,EAAE,8BAA8B,KAAK,GAAG,EAAE,EAAE,GAAG,EAAE,EAAE,eAAe,EAAE,UAAU,EAAE,CAAC,CAAC;gBACzG,CAAC;gBAED,MAAM,IAAI,GAAoB,EAAE,WAAW,EAAE,iBAAiB,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;gBACnG,OAAO,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,eAAe,EAAE,UAAU,EAAE,IAAI,EAAE,uBAAuB,EAAE,CAAC,CAAC;YACzF,CAAC;YAED,MAAM,QAAQ,GAAG,aAAa,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,eAAe,EAAE,WAAW,CAAC,CAAC;YAC/F,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC;YACrE,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC;YAEjE,MAAM,KAAK,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC;YACpC,MAAM,KAAK,GAAG,OAAO;iBAClB,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,QAAQ,CAAC;iBAC9B,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,gBAAgB,EAAE,aAAa,IAAI,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;YAE1G,MAAM,IAAI,GAAkB;gBAC1B,KAAK;gBACL,IAAI;gBACJ,QAAQ;gBACR,KAAK,EAAE,OAAO,CAAC,MAAM;gBACrB,UAAU;gBACV,OAAO,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM;gBAC9C,eAAe,EAAE,sBAAsB;gBACvC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC/C,CAAC;YAEF,4EAA4E;YAC5E,OAAO,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE;gBACrB,eAAe,EAAE,UAAU;gBAC3B,IAAI,EAAE,uBAAuB;aAC9B,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,OAAO,CACd,QAAkC,EAClC,gBAAyB,EACzB,QAAiB;IAEjB,MAAM,KAAK,GAAmB;QAC5B,EAAE,EAAE,QAAQ,CAAC,EAAE;QACf,KAAK,EAAE,QAAQ,CAAC,KAAK,IAAI,QAAQ,CAAC,EAAE;QACpC,OAAO,EAAE,QAAQ,CAAC,OAAO;QACzB,KAAK,EAAE,GAAG,qBAAqB,GAAG,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG;QACpE,QAAQ;QACR,KAAK,EAAE,QAAQ,CAAC,KAAK;KACtB,CAAC;IAEF,IAAI,QAAQ,CAAC,WAAW;QAAE,KAAK,CAAC,WAAW,GAAG,QAAQ,CAAC,WAAW,CAAC;IACnE,IAAI,QAAQ,CAAC,IAAI,EAAE,MAAM;QAAE,KAAK,CAAC,IAAI,GAAG,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC3D,IAAI,QAAQ,CAAC,eAAe;QAAE,KAAK,CAAC,eAAe,GAAG,QAAQ,CAAC,eAAe,CAAC;IAC/E,IAAI,QAAQ,CAAC,MAAM,EAAE,MAAM;QAAE,KAAK,CAAC,MAAM,GAAG,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;IACjE,IAAI,QAAQ,CAAC,GAAG;QAAE,KAAK,CAAC,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC;IAC3C,IAAI,gBAAgB,IAAI,OAAO,QAAQ,CAAC,QAAQ,KAAK,QAAQ;QAAE,KAAK,CAAC,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC;IAElG,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,aAAa,CAAC,SAAwB,EAAE,QAAgB,EAAE,GAAW;IAC5E,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,SAAS,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;IACpD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC5D,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAC/B,CAAC;AAED,SAAS,SAAS,CAAC,SAAwB,EAAE,UAAkB;IAC7D,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,SAAS,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;IACpD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC;QAAE,OAAO,CAAC,CAAC;IACrD,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AACtC,CAAC;AAED,SAAS,IAAI,CAAC,IAAa,EAAE,MAAc,EAAE,UAAkC,EAAE;IAC/E,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE;QACxC,MAAM;QACN,OAAO,EAAE,EAAE,cAAc,EAAE,gCAAgC,EAAE,GAAG,OAAO,EAAE;KAC1E,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../../../libs/braid-gateway/src/discovery.ts"],"names":[],"mappings":"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"}
package/src/gateway.d.ts CHANGED
@@ -1,10 +1,33 @@
1
- import { Principal, RegistrySource } from './registry.js';
1
+ import { Principal, RegistryRefresh, RegistrySource, FragmentManifest } from './registry.js';
2
2
  import { DiscoveryOptions } from './discovery.js';
3
3
  import { type BreakerOptions } from './breaker.js';
4
4
  import { type TelemetryOptions } from './telemetry.js';
5
5
  export interface GatewayOptions {
6
6
  /** The fragment registry: inline manifests, a JSON URL, or an async loader. */
7
7
  registry: RegistrySource;
8
+ /**
9
+ * Reload the registry source every this many milliseconds, and serve what it returns from then
10
+ * on — a re-pin goes live without a restart.
11
+ *
12
+ * Off by default, which keeps the snapshot model's "a re-pin is a deploy". With a source that
13
+ * follows a moving pointer (`snapshotRegistry` without `pinned`, a URL), this is hot re-pin; with
14
+ * a pinned source it is a cheap no-op. Each reload is all-or-nothing, and one that fails leaves
15
+ * the current registry serving and is reported as a `registry` telemetry event.
16
+ *
17
+ * Instances poll independently, so a fleet converges within one interval rather than at one
18
+ * instant. Not allowed with inline manifests, which cannot change.
19
+ */
20
+ registryRefreshMs?: number;
21
+ /**
22
+ * Supplies the page itself for a document request, in place of the shell app behind the gateway:
23
+ * return HTML, or null to let `next` (the app) answer as usual.
24
+ *
25
+ * Fragments are pierced into what this returns exactly as into an app's response, and a page it
26
+ * answers is served even when no fragment pierces it. This is how a shell defined as data — see
27
+ * `shellDocuments` in `@braidlabs/registry` — is served with no app and no rebuild. Consulted only
28
+ * for document requests (GET, `Sec-Fetch-Dest: document` or an HTML `Accept`).
29
+ */
30
+ documents?: (request: Request, context: DocumentsContext) => Response | null | Promise<Response | null>;
8
31
  /** 'development' enables verbose error bodies; defaults to 'development'. */
9
32
  mode?: 'production' | 'development';
10
33
  /**
@@ -28,8 +51,31 @@ export interface GatewayOptions {
28
51
  * assertion minted per request via {@link GatewayOptions.additionalHeaders}, or a token
29
52
  * exchanged for the fragment's own audience. Turn this on only when every endpoint in the
30
53
  * registry is inside the same trust boundary as the shell.
54
+ *
55
+ * Or decide per fragment, when only some of them are — the usual case once a gateway composes
56
+ * other teams' gateways:
57
+ *
58
+ * ```ts
59
+ * forwardCredentials: (fragment) => typeof fragment.endpoint === 'string' &&
60
+ * fragment.endpoint.startsWith('https://orders.internal/'),
61
+ * ```
62
+ *
63
+ * The function is the host's, never the manifest's: a fragment that could declare its own
64
+ * entitlement to the user's cookies would not be behind a boundary at all. A function that
65
+ * throws forwards nothing. The same decision applies to websocket upgrades.
31
66
  */
32
- forwardCredentials?: boolean;
67
+ forwardCredentials?: boolean | ((fragment: FragmentManifest) => boolean);
68
+ /**
69
+ * More request headers that carry the caller's identity, stripped alongside `cookie`,
70
+ * `authorization` and `proxy-authorization` whenever {@link GatewayOptions.forwardCredentials}
71
+ * does not allow a fragment.
72
+ *
73
+ * An auth proxy in front of the shell often adds its own: `x-auth-request-access-token`
74
+ * (oauth2-proxy), `cf-access-jwt-assertion` (Cloudflare Access), `x-amzn-oidc-data` (an ALB).
75
+ * The gateway cannot know them, and each one is the user's identity handed to every fragment
76
+ * endpoint unless it is listed here.
77
+ */
78
+ credentialHeaders?: readonly string[];
33
79
  /**
34
80
  * Publishes a paginated listing of the fragments this gateway serves, for shells that build
35
81
  * their UI from the registry instead of hard-coding slot names.
@@ -206,6 +252,25 @@ export interface RoutingEvent {
206
252
  fragmentIds: string[];
207
253
  at: number;
208
254
  }
255
+ /** Where a fragment websocket upgrade goes, and what may travel with it. See `resolveUpgrade`. */
256
+ export interface UpgradeTarget {
257
+ fragmentId: string;
258
+ target: URL;
259
+ forwardCredentials: boolean;
260
+ /** Headers that carry the caller's identity: stripped unless `forwardCredentials`. */
261
+ credentialHeaders: readonly string[];
262
+ /** The `x-braid-via` value for the upstream request, this gateway's hop included. */
263
+ via: string;
264
+ }
265
+ /** What the gateway tells a `documents` hook about the registry it is serving right now. */
266
+ export interface DocumentsContext {
267
+ /**
268
+ * The manifests the gateway is serving — exactly the array its registry source last returned and
269
+ * it accepted. A hook that renders from the same snapshot (`shellDocuments`) keys on this, so a
270
+ * page's shell can never come from a snapshot the gateway refused to load.
271
+ */
272
+ manifests: readonly FragmentManifest[];
273
+ }
209
274
  export interface BraidGateway {
210
275
  /**
211
276
  * Handles a request if it belongs to Braid: a fragment-namespace request, or a document
@@ -223,13 +288,24 @@ export interface BraidGateway {
223
288
  * addressed through the fragment namespace, so the gateway has to say where they go — the
224
289
  * socket plumbing itself belongs to the platform binding.
225
290
  *
226
- * @returns the endpoint URL to dial, or null when the request is not a fragment upgrade, the
227
- * fragment is unknown, or the caller may not load it.
291
+ * A binding other than `toNodeUpgradeHandler` **must** remove `credentialHeaders` from the
292
+ * upstream request when `forwardCredentials` is false, and set `x-braid-via` to `via` — the
293
+ * socket otherwise carries the user's identity past the boundary every fetch respects.
294
+ *
295
+ * @returns the endpoint URL to dial, whether the caller's credentials may go with it (the same
296
+ * {@link GatewayOptions.forwardCredentials} rule as a fetch) and which headers carry
297
+ * them, and the hop header to send — or null when the request is not a fragment
298
+ * upgrade, the fragment is unknown, the caller may not load it, or it has already
299
+ * crossed too many gateways.
300
+ */
301
+ resolveUpgrade(request: Request): Promise<UpgradeTarget | null>;
302
+ /**
303
+ * Reloads the registry source now and swaps in what it returns. Resolves once the new registry
304
+ * is serving; rejects, leaving the current one serving, when the source fails.
228
305
  */
229
- resolveUpgrade(request: Request): Promise<{
230
- fragmentId: string;
231
- target: URL;
232
- } | null>;
306
+ refreshRegistry(): Promise<RegistryRefresh>;
307
+ /** Stops the `registryRefreshMs` timer. Nothing else holds resources between requests. */
308
+ close(): void;
233
309
  }
234
310
  export declare function createGateway(options: GatewayOptions): BraidGateway;
235
311
  /**