@braidlabs/console 0.2.0 → 0.4.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 (60) hide show
  1. package/README.md +34 -10
  2. package/package.json +10 -4
  3. package/src/app/auth.d.ts +46 -0
  4. package/src/app/auth.js +80 -0
  5. package/src/app/auth.js.map +1 -0
  6. package/src/app/console-app.d.ts +8 -6
  7. package/src/app/console-app.js +91 -20
  8. package/src/app/console-app.js.map +1 -1
  9. package/src/app/main.js +25 -2
  10. package/src/app/main.js.map +1 -1
  11. package/src/app/routes.d.ts +14 -0
  12. package/src/app/routes.js +23 -0
  13. package/src/app/routes.js.map +1 -0
  14. package/src/index.d.ts +15 -2
  15. package/src/index.js +10 -2
  16. package/src/index.js.map +1 -1
  17. package/src/lib/client.d.ts +52 -1
  18. package/src/lib/client.js +48 -0
  19. package/src/lib/client.js.map +1 -1
  20. package/src/lib/draft.d.ts +1 -1
  21. package/src/lib/draft.js +2 -2
  22. package/src/lib/draft.js.map +1 -1
  23. package/src/lib/empty-state.d.ts +15 -0
  24. package/src/lib/empty-state.js +38 -0
  25. package/src/lib/empty-state.js.map +1 -0
  26. package/src/lib/history-panel.d.ts +19 -0
  27. package/src/lib/history-panel.js +85 -0
  28. package/src/lib/history-panel.js.map +1 -0
  29. package/src/lib/ownership.d.ts +15 -0
  30. package/src/lib/ownership.js +21 -0
  31. package/src/lib/ownership.js.map +1 -0
  32. package/src/lib/query.d.ts +47 -0
  33. package/src/lib/query.js +121 -0
  34. package/src/lib/query.js.map +1 -0
  35. package/src/lib/registry-console.d.ts +13 -2
  36. package/src/lib/registry-console.js +15 -11
  37. package/src/lib/registry-console.js.map +1 -1
  38. package/src/lib/registry-editor.js +20 -7
  39. package/src/lib/registry-editor.js.map +1 -1
  40. package/src/lib/shell-codegen.d.ts +28 -0
  41. package/src/lib/shell-codegen.js +316 -0
  42. package/src/lib/shell-codegen.js.map +1 -0
  43. package/src/lib/shells-panel.d.ts +43 -0
  44. package/src/lib/shells-panel.js +307 -0
  45. package/src/lib/shells-panel.js.map +1 -0
  46. package/src/lib/styles.d.ts +1 -1
  47. package/src/lib/styles.js +72 -4
  48. package/src/lib/styles.js.map +1 -1
  49. package/src/lib/tag-chip.d.ts +8 -0
  50. package/src/lib/tag-chip.js +12 -0
  51. package/src/lib/tag-chip.js.map +1 -0
  52. package/src/lib/tags.d.ts +10 -0
  53. package/src/lib/tags.js +53 -0
  54. package/src/lib/tags.js.map +1 -0
  55. package/src/lib/topology-graph.d.ts +5 -2
  56. package/src/lib/topology-graph.js +17 -8
  57. package/src/lib/topology-graph.js.map +1 -1
  58. package/src/lib/topology.d.ts +18 -3
  59. package/src/lib/topology.js +42 -3
  60. package/src/lib/topology.js.map +1 -1
package/README.md CHANGED
@@ -1,11 +1,15 @@
1
1
  # @braidlabs/console
2
2
 
3
- A read-only console for a [Braid](../braid-gateway) gateway's fragment registry. One package, two
4
- shapes: a mountable React component, and a standalone deployable app.
3
+ A console for a [Braid](../braid-gateway) gateway's registry: fragments, the composition map,
4
+ **shells** designed as data, and snapshot history with rollback. One package, two shapes: mountable
5
+ React components, and a standalone deployable app with optional OIDC (Okta) sign-in.
5
6
 
6
- **It needs nothing deployed.** It reads the `/__braid/registry` discovery endpoint the gateway
7
- already serves, so it works against a gateway whose manifests are defined in code — which is every
8
- gateway today. No snapshot store, no write API.
7
+ **Viewing needs nothing deployed.** The fragment list and map read the `/__braid/registry`
8
+ discovery endpoint the gateway already serves. Shells, history and editing need the registry write
9
+ API from [`@braidlabs/registry`](../braid-registry); without it those views say what to mount.
10
+
11
+ The full guide — the layout designer, query syntax, Okta setup, and how an enterprise runs it — is
12
+ [docs/packages/console.md](../../docs/packages/console.md).
9
13
 
10
14
  ## As a library
11
15
 
@@ -67,7 +71,7 @@ directions, because an admin shell may be dark inside a light OS.
67
71
  viewport's. In a 420px sidebar it stacks — on a 1280px screen.
68
72
 
69
73
  **Slim is a number.** 140 kB gzipped for the app bundle including React and the inlined
70
- stylesheet, enforced by `nx size braid-console`. Currently 61 kB. React is a peer dependency in
74
+ stylesheet, enforced by `nx size braid-console`. Currently 105 kB, with the OIDC client in a separate chunk loaded only when sign-in is configured. React is a peer dependency in
71
75
  library form, so a host never ships two copies.
72
76
 
73
77
  ## Editing
@@ -123,9 +127,29 @@ but not load is a legitimate state — a launcher should render it, not hide it.
123
127
  is in development mode the listing skips access filtering entirely, which the console says out
124
128
  loud rather than letting you mistake a dev listing for a production one.
125
129
 
130
+ ## Shells, search, and sign-in
131
+
132
+ ```tsx
133
+ import { ShellsPanel, HistoryPanel } from '@braidlabs/console';
134
+
135
+ <ShellsPanel api={api} selected={shellId} onSelect={setShellId} />
136
+ <HistoryPanel api={api} />
137
+ ```
138
+
139
+ - **`ShellsPanel`** lists shells and opens a designer: routes, a layout typed as ASCII art that *is*
140
+ CSS `grid-template-areas` with a live grid preview, a fragment per area, the document head as
141
+ data (never loaded into this page), and generated host code for React, Angular, Angular SSR and
142
+ plain HTML. Publishing sends `baseId`, so a stale draft is refused rather than overwriting.
143
+ - **`HistoryPanel`** lists snapshots with their server-recorded publisher. Rollback is pinning one.
144
+ - **Query syntax** in every filter: `tag:` `type:` `framework:` `route:` `adapter:` `is:gated`
145
+ `is:unrouted`, `-` to negate, quotes for spaces. Tags are colored from their text, the same
146
+ everywhere.
147
+ - **Sign-in** is the standalone app's alone: add `"auth": { "issuer", "clientId" }` to the page
148
+ config and it signs in with Authorization Code + PKCE, loading the OIDC client only then. The
149
+ library still never logs in; `GET /permissions` only decides which buttons to draw.
150
+
126
151
  ## Related
127
152
 
128
- - [`@braidlabs/registry`](../braid-registry) — snapshots and analysis, for when the registry
129
- becomes editable
130
- - [the plan](../../docs/plans/braid-registry-console-plan.md) — including why the console is
131
- deliberately optional, and the line it must not cross
153
+ - [`@braidlabs/registry`](../braid-registry) — snapshots, shells, analysis, the write API, and
154
+ `@braidlabs/registry/oidc`
155
+ - [the guide](../../docs/packages/console.md) — including how an enterprise deploys and governs it
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@braidlabs/console",
3
- "version": "0.2.0",
4
- "description": "A read-only console for a Braid gateway's fragment registry. Mountable React library, or a standalone deployable app.",
3
+ "version": "0.4.0",
4
+ "description": "A console for a Braid gateway: fragments, shells as data, a composition map, and snapshot history. Mountable React components, or a standalone app with OIDC sign-in.",
5
5
  "keywords": [
6
6
  "braid",
7
7
  "micro-frontends",
@@ -22,10 +22,11 @@
22
22
  "./package.json": "./package.json"
23
23
  },
24
24
  "peerDependencies": {
25
- "@braidlabs/gateway": "^0.2.0",
25
+ "@braidlabs/gateway": "^0.4.0",
26
26
  "react": "^18.0.0 || ^19.0.0",
27
27
  "react-dom": "^18.0.0 || ^19.0.0",
28
- "@braidlabs/registry": "^0.2.0"
28
+ "@braidlabs/registry": "^0.4.0",
29
+ "oidc-client-ts": "^3.5.0"
29
30
  },
30
31
  "publishConfig": {
31
32
  "access": "public"
@@ -39,5 +40,10 @@
39
40
  "bugs": {
40
41
  "url": "https://github.com/braidjs/braid/issues"
41
42
  },
43
+ "peerDependenciesMeta": {
44
+ "oidc-client-ts": {
45
+ "optional": true
46
+ }
47
+ },
42
48
  "module": "./src/index.js"
43
49
  }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Sign-in for the standalone console: OIDC Authorization Code with PKCE — Okta, or any issuer.
3
+ *
4
+ * This lives in `app/`, not `lib/`, for the same reason the URL does: the *library* never performs
5
+ * a login. Mounted inside a portal it inherits that portal's session through `headers()`; only the
6
+ * deployable app owns a session, and only when its config names an issuer.
7
+ *
8
+ * This module is itself loaded only when `auth` is configured, so a console deployed without it
9
+ * downloads none of `oidc-client-ts`. Tokens are kept in `sessionStorage` (the library's default): per tab, gone when it closes.
10
+ * Anything script-readable is exposed to XSS on this origin, which is why the console never
11
+ * renders a shell's own scripts or styles and why the deployment docs ask for a strict CSP.
12
+ *
13
+ * The identity shown here is the ID token's. What the server *decides* with is the access token,
14
+ * verified on every request; see `createOidcAuthorizer` in `@braidlabs/registry/oidc`.
15
+ */
16
+ export interface AuthConfig {
17
+ /** e.g. `https://example.okta.com/oauth2/default` — a custom authorization server for Okta. */
18
+ issuer: string;
19
+ /** The console's SPA application id. */
20
+ clientId: string;
21
+ /**
22
+ * Defaults to `openid profile email offline_access`. `offline_access` asks for a refresh token,
23
+ * which is how the session renews without a hidden iframe; enable the Refresh Token grant on the
24
+ * Okta app. Okta needs `groups` here only if the claim is scope-gated.
25
+ */
26
+ scopes?: string;
27
+ /** Sent as `audience` for issuers that select the API by it (Auth0); Okta sets it per server. */
28
+ audience?: string;
29
+ }
30
+ export interface Session {
31
+ headers: () => Promise<Record<string, string>>;
32
+ /** Email, else preferred_username, else subject. */
33
+ user: string;
34
+ signOut: () => Promise<void>;
35
+ /**
36
+ * For a token the server would not accept although it has not expired (the issuer rotated its
37
+ * keys; the API expects another audience). Signs in again, at most once a minute, so a
38
+ * misconfiguration produces a message rather than a redirect loop. Returns false when it held back.
39
+ */
40
+ signInAgain: () => boolean;
41
+ }
42
+ /**
43
+ * Resolves to a signed-in session, or never resolves because the page is navigating to the
44
+ * issuer. Call once, before rendering anything that makes requests.
45
+ */
46
+ export declare function signIn(config: AuthConfig): Promise<Session>;
@@ -0,0 +1,80 @@
1
+ import { UserManager, WebStorageStateStore } from 'oidc-client-ts';
2
+ const RETRY_KEY = 'braid-console:sign-in-again';
3
+ const RETRY_WINDOW_MS = 60_000;
4
+ /**
5
+ * Resolves to a signed-in session, or never resolves because the page is navigating to the
6
+ * issuer. Call once, before rendering anything that makes requests.
7
+ */
8
+ export async function signIn(config) {
9
+ // The callback lands on the console's own URL without its hash, so the view a user was on is
10
+ // carried through the round trip in the request state and restored afterwards.
11
+ const here = `${location.origin}${location.pathname}`;
12
+ const manager = new UserManager({
13
+ authority: config.issuer,
14
+ client_id: config.clientId,
15
+ redirect_uri: here,
16
+ post_logout_redirect_uri: here,
17
+ response_type: 'code',
18
+ scope: config.scopes ?? 'openid profile email offline_access',
19
+ automaticSilentRenew: true,
20
+ userStore: new WebStorageStateStore({ store: sessionStorage }),
21
+ ...(config.audience ? { extraQueryParams: { audience: config.audience } } : {}),
22
+ });
23
+ const params = new URLSearchParams(location.search);
24
+ let user = null;
25
+ if (params.has('code') && params.has('state')) {
26
+ user = await manager.signinRedirectCallback();
27
+ const hash = typeof user.state === 'object' && user.state && 'hash' in user.state ? String(user.state.hash) : '';
28
+ // Strip `code` and `state` so a reload or a copied link does not replay a spent grant.
29
+ history.replaceState(null, '', `${location.pathname}${hash}`);
30
+ }
31
+ else if (params.has('error')) {
32
+ // The issuer refused (a user not assigned to the app, say). Retrying would loop, so stop and
33
+ // say so — by error code only: the description is free text anyone can put in a link.
34
+ const code = (params.get('error') ?? '').replace(/[^a-z_]/gi, '').slice(0, 40);
35
+ throw new Error(`the identity provider refused sign-in (${code || 'unknown error'})`);
36
+ }
37
+ else {
38
+ user = await manager.getUser();
39
+ }
40
+ if (!user || user.expired) {
41
+ await manager.signinRedirect({ state: { hash: location.hash } });
42
+ return new Promise(() => undefined);
43
+ }
44
+ const profile = user.profile;
45
+ return {
46
+ user: String(profile.email ?? profile.preferred_username ?? profile.sub),
47
+ headers: async () => {
48
+ let current = await manager.getUser();
49
+ if (!current || current.expired) {
50
+ // Background renewal missed (a sleeping laptop, an issuer that issued no refresh token).
51
+ // Try once more quietly; failing that, sign in again and come back to this view.
52
+ current = await manager.signinSilent().catch(() => null);
53
+ if (!current) {
54
+ await manager.signinRedirect({ state: { hash: location.hash } });
55
+ return new Promise(() => undefined);
56
+ }
57
+ }
58
+ return { authorization: `Bearer ${current.access_token}` };
59
+ },
60
+ signInAgain: () => {
61
+ const last = Number(sessionStorage.getItem(RETRY_KEY) ?? 0);
62
+ if (Date.now() - last < RETRY_WINDOW_MS)
63
+ return false;
64
+ sessionStorage.setItem(RETRY_KEY, String(Date.now()));
65
+ void manager.removeUser().then(() => manager.signinRedirect({ state: { hash: location.hash } }));
66
+ return true;
67
+ },
68
+ signOut: async () => {
69
+ try {
70
+ await manager.signoutRedirect();
71
+ }
72
+ catch {
73
+ // No end_session_endpoint: forget the tokens locally and start over.
74
+ await manager.removeUser();
75
+ location.reload();
76
+ }
77
+ },
78
+ };
79
+ }
80
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../../../libs/braid-console/src/app/auth.ts"],"names":[],"mappings":"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"}
@@ -1,17 +1,19 @@
1
- import type { ConsoleApi } from '../lib/client.js';
1
+ import { type ConsoleApi } from '../lib/client.js';
2
+ import type { Session } from './auth.js';
2
3
  /**
3
4
  * The standalone deployment's shell.
4
5
  *
5
- * This lives in `app/`, not `lib/`, on purpose: it owns a page — a title, a tab strip, and the
6
- * URL — and every one of those is something the library must *not* own when it mounts inside
7
- * someone else's admin app. Keeping the page-level concerns here is what lets `RegistryConsole`
8
- * stay embeddable.
6
+ * This lives in `app/`, not `lib/`, on purpose: it owns a page — a title, a tab strip, the URL, and
7
+ * when configured a sign-in — and every one of those is something the library must *not* own when
8
+ * it mounts inside someone else's admin app. Keeping the page-level concerns here is what lets the
9
+ * panels stay embeddable.
9
10
  *
10
11
  * The view is in the URL hash rather than in state alone, so a topology someone is looking at is
11
12
  * a link they can paste into a ticket. That is the difference between a console an operator uses
12
13
  * and one they screenshot.
13
14
  */
14
- export declare function ConsoleApp({ api, edit }: {
15
+ export declare function ConsoleApp({ api, edit, session }: {
15
16
  api: ConsoleApi;
16
17
  edit: boolean;
18
+ session?: Session;
17
19
  }): import("react").JSX.Element;
@@ -1,48 +1,119 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useEffect, useState } from 'react';
2
+ import { lazy, Suspense, useEffect, useState } from 'react';
3
3
  import { RegistryConsole } from '../lib/registry-console.js';
4
- import { RegistryEditor } from '../lib/registry-editor.js';
5
4
  import { ensureStyles } from '../lib/styles.js';
5
+ import { fetchHead, fetchPermissions, RegistryApiError } from '../lib/client.js';
6
+ import { readRoute, routeHash } from './routes.js';
7
+ // Loaded when first opened: most visits are the fragment list, and these are most of the bundle.
8
+ const RegistryEditor = lazy(() => import('../lib/registry-editor.js').then((m) => ({ default: m.RegistryEditor })));
9
+ const ShellsPanel = lazy(() => import('../lib/shells-panel.js').then((m) => ({ default: m.ShellsPanel })));
10
+ const HistoryPanel = lazy(() => import('../lib/history-panel.js').then((m) => ({ default: m.HistoryPanel })));
6
11
  /**
7
12
  * The standalone deployment's shell.
8
13
  *
9
- * This lives in `app/`, not `lib/`, on purpose: it owns a page — a title, a tab strip, and the
10
- * URL — and every one of those is something the library must *not* own when it mounts inside
11
- * someone else's admin app. Keeping the page-level concerns here is what lets `RegistryConsole`
12
- * stay embeddable.
14
+ * This lives in `app/`, not `lib/`, on purpose: it owns a page — a title, a tab strip, the URL, and
15
+ * when configured a sign-in — and every one of those is something the library must *not* own when
16
+ * it mounts inside someone else's admin app. Keeping the page-level concerns here is what lets the
17
+ * panels stay embeddable.
13
18
  *
14
19
  * The view is in the URL hash rather than in state alone, so a topology someone is looking at is
15
20
  * a link they can paste into a ticket. That is the difference between a console an operator uses
16
21
  * and one they screenshot.
17
22
  */
18
- export function ConsoleApp({ api, edit }) {
19
- const [view, setView] = useState(() => readView(edit));
23
+ export function ConsoleApp({ api, edit, session }) {
24
+ const [route, setRoute] = useState(() => readRoute(window.location.hash, edit));
25
+ const [permissions, setPermissions] = useState(null);
26
+ const [shells, setShells] = useState(undefined);
27
+ const [pinToken, setPinToken] = useState(0);
28
+ // Bumped by a rollback in History only: the Shells panel reloads on it, but not on its own
29
+ // publishes, which it already reflects.
30
+ const [rollbackToken, setRollbackToken] = useState(0);
31
+ // Views with a draft stay mounted once opened, hidden when not shown, so switching tabs or going
32
+ // Back never throws away unpublished edits.
33
+ const [visited, setVisited] = useState(() => new Set([route.view]));
34
+ const [shellsDirty, setShellsDirty] = useState(false);
35
+ // The Shells tab returns to the shell that was open, the way the panel kept its draft.
36
+ const [lastShell, setLastShell] = useState(route.shell);
20
37
  useEffect(() => {
21
38
  ensureStyles();
22
39
  }, []);
23
40
  // Back and forward should move between views, since the tabs put entries in history.
24
41
  useEffect(() => {
25
- const onHashChange = () => setView(readView(edit));
42
+ const onHashChange = () => {
43
+ const next = readRoute(window.location.hash, edit);
44
+ setRoute(next);
45
+ if (next.view === 'shells')
46
+ setLastShell(next.shell);
47
+ };
26
48
  window.addEventListener('hashchange', onHashChange);
27
49
  return () => window.removeEventListener('hashchange', onHashChange);
28
50
  }, [edit]);
51
+ // Both are advisory and optional: a gateway without the write API has neither, and the console
52
+ // still lists fragments. Failures are therefore silent here; the panels that need the API say
53
+ // why when they are opened.
54
+ useEffect(() => {
55
+ let current = true;
56
+ fetchPermissions(api).then((result) => current && setPermissions(result), () => current && setPermissions(null));
57
+ fetchHead(api).then((head) => current && setShells(head.snapshot?.shells ?? []), (error) => {
58
+ if (!current)
59
+ return;
60
+ // Signed in here, yet the server refused the token outright (a 401, not a 403 for a
61
+ // known user who lacks a role): sign in again rather than show a console that cannot read.
62
+ if (session && error instanceof RegistryApiError && error.status === 401 && session.signInAgain())
63
+ return;
64
+ setShells(undefined);
65
+ });
66
+ return () => {
67
+ current = false;
68
+ };
69
+ // `api` and `session` are built once by main.tsx; pinToken refreshes after a rollback.
70
+ }, [api, session, pinToken]);
71
+ useEffect(() => {
72
+ setVisited((current) => (current.has(route.view) ? current : new Set([...current, route.view])));
73
+ }, [route.view]);
74
+ // A reload or a closed tab is the one way left to lose a draft; the browser asks first.
75
+ useEffect(() => {
76
+ if (!shellsDirty)
77
+ return;
78
+ const warn = (event) => event.preventDefault();
79
+ window.addEventListener('beforeunload', warn);
80
+ return () => window.removeEventListener('beforeunload', warn);
81
+ }, [shellsDirty]);
29
82
  function go(next) {
30
- window.location.hash = next;
31
- setView(next);
83
+ // Renaming the open shell rewrites its link in place, rather than leaving one history entry
84
+ // per keystroke for Back to step through.
85
+ const rename = next.view === 'shells' && route.view === 'shells' && Boolean(next.shell && route.shell);
86
+ if (rename)
87
+ history.replaceState(null, '', `#${routeHash(next)}`);
88
+ else
89
+ window.location.hash = routeHash(next);
90
+ setRoute(next);
91
+ if (next.view === 'shells')
92
+ setLastShell(next.shell);
32
93
  }
94
+ // Edit is offered only to a caller who could save. The server enforces that regardless; hiding
95
+ // the tab avoids an editor whose every publish fails.
96
+ // Unknown until /permissions answers, and unknown means hidden: a read-only user should not see
97
+ // an editor flash up and vanish.
98
+ const canEdit = edit && permissions?.publish === true;
33
99
  const tabs = [
34
100
  { id: 'fragments', label: 'Fragments' },
35
101
  { id: 'topology', label: 'Topology' },
36
- ...(edit ? [{ id: 'edit', label: 'Edit registry' }] : []),
102
+ { id: 'shells', label: 'Shells' },
103
+ { id: 'history', label: 'History' },
104
+ ...(canEdit ? [{ id: 'edit', label: 'Edit fragments' }] : []),
37
105
  ];
38
- return (_jsxs("div", { className: "braid-console", children: [_jsxs("div", { className: "braid-console__shell", children: [_jsxs("div", { className: "braid-console__titlebar", children: [_jsx("h1", { className: "braid-console__producttitle", children: "Braid gateway" }), _jsxs("span", { className: "braid-console__breadcrumb", children: [_jsx("span", { "aria-hidden": "true", children: "\u00B7" }), _jsx("code", { children: api.baseUrl || window.location.host })] })] }), _jsx("div", { className: "braid-console__commandbar", children: _jsx("div", { className: "braid-console__tabs", role: "tablist", "aria-label": "Console views", children: tabs.map((entry) => (_jsx("button", { type: "button", role: "tab", className: "braid-console__tab", "aria-selected": view === entry.id, onClick: () => go(entry.id), children: entry.label }, entry.id))) }) })] }), view === 'edit' ? (_jsx(RegistryEditor, { api: api })) : (_jsx(RegistryConsole, { api: api, chrome: false, view: view }))] }));
106
+ const view = route.view === 'edit' && !canEdit ? 'fragments' : route.view;
107
+ return (_jsxs("div", { className: "braid-console", children: [_jsxs("div", { className: "braid-console__shell", children: [_jsxs("div", { className: "braid-console__titlebar", children: [_jsx("h1", { className: "braid-console__producttitle", children: "Braid gateway" }), _jsxs("span", { className: "braid-console__breadcrumb", children: [_jsx("span", { "aria-hidden": "true", children: "\u00B7" }), _jsx("code", { children: api.baseUrl || window.location.host })] }), _jsx("span", { className: "braid-console__spacer" }), session && (_jsxs("span", { className: "braid-console__identity", children: [_jsx("span", { children: session.user }), permissions && _jsx("span", { className: "braid-console__rolebadge", children: roleLabel(permissions) }), _jsx("button", { type: "button", className: "braid-console__ghost", onClick: () => void session.signOut(), children: "Sign out" })] }))] }), _jsx("div", { className: "braid-console__commandbar", children: _jsx("div", { className: "braid-console__tabs", role: "tablist", "aria-label": "Console views", children: tabs.map((entry) => (_jsx("button", { type: "button", role: "tab", className: "braid-console__tab", "aria-selected": view === entry.id, onClick: () => go(entry.id === 'shells' && lastShell ? { view: 'shells', shell: lastShell } : { view: entry.id }), children: entry.label }, entry.id))) }) })] }), _jsxs(Suspense, { fallback: _jsx("p", { className: "braid-console__empty", children: "Loading\u2026" }), children: [view === 'edit' && _jsx(RegistryEditor, { api: api }), visited.has('shells') && (_jsx("div", { hidden: view !== 'shells', children: _jsx(ShellsPanel, { api: api, selected: route.shell ?? null, onSelect: (id) => go(id ? { view: 'shells', shell: id } : { view: 'shells' }), onPublished: (outcome) => outcome.pinned && setPinToken((token) => token + 1), onDirtyChange: setShellsDirty, refreshKey: rollbackToken }) })), view === 'history' && (_jsx(HistoryPanel, { api: api, onPinned: () => {
108
+ setPinToken((token) => token + 1);
109
+ setRollbackToken((token) => token + 1);
110
+ } }))] }), (view === 'fragments' || view === 'topology') && (_jsx(RegistryConsole, { api: api, chrome: false, view: view, ...(shells ? { shells } : {}) }))] }));
39
111
  }
40
- function readView(edit) {
41
- const hash = window.location.hash.replace('#', '');
42
- if (hash === 'topology')
43
- return 'topology';
44
- if (hash === 'edit' && edit)
45
- return 'edit';
46
- return 'fragments';
112
+ function roleLabel({ publish, pin }) {
113
+ if (publish && pin)
114
+ return 'can publish';
115
+ if (publish)
116
+ return 'can publish candidates';
117
+ return 'read-only';
47
118
  }
48
119
  //# sourceMappingURL=console-app.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"console-app.js","sourceRoot":"","sources":["../../../../../libs/braid-console/src/app/console-app.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGhD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,UAAU,CAAC,EAAE,GAAG,EAAE,IAAI,EAAsC;IAC1E,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAO,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;IAE7D,SAAS,CAAC,GAAG,EAAE;QACb,YAAY,EAAE,CAAC;IACjB,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,qFAAqF;IACrF,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,YAAY,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;QACnD,MAAM,CAAC,gBAAgB,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;QACpD,OAAO,GAAG,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;IACtE,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAEX,SAAS,EAAE,CAAC,IAAU;QACpB,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAC;QAC5B,OAAO,CAAC,IAAI,CAAC,CAAC;IAChB,CAAC;IAED,MAAM,IAAI,GAAkC;QAC1C,EAAE,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE;QACvC,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE;QACrC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAE,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,EAAE,CAAW,CAAC,CAAC,CAAC,EAAE,CAAC;KACrE,CAAC;IAEF,OAAO,CACL,eAAK,SAAS,EAAC,eAAe,aAC5B,eAAK,SAAS,EAAC,sBAAsB,aACnC,eAAK,SAAS,EAAC,yBAAyB,aACtC,aAAI,SAAS,EAAC,6BAA6B,8BAAmB,EAC9D,gBAAM,SAAS,EAAC,2BAA2B,aACzC,8BAAkB,MAAM,uBAAS,EACjC,yBAAO,GAAG,CAAC,OAAO,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAQ,IAC7C,IACH,EAEN,cAAK,SAAS,EAAC,2BAA2B,YACxC,cAAK,SAAS,EAAC,qBAAqB,EAAC,IAAI,EAAC,SAAS,gBAAY,eAAe,YAC3E,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CACnB,iBAEE,IAAI,EAAC,QAAQ,EACb,IAAI,EAAC,KAAK,EACV,SAAS,EAAC,oBAAoB,mBACf,IAAI,KAAK,KAAK,CAAC,EAAE,EAChC,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,YAE1B,KAAK,CAAC,KAAK,IAPP,KAAK,CAAC,EAAE,CAQN,CACV,CAAC,GACE,GACF,IACF,EAEL,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,CACjB,KAAC,cAAc,IAAC,GAAG,EAAE,GAAG,GAAI,CAC7B,CAAC,CAAC,CAAC,CAGF,KAAC,eAAe,IAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,GAAI,CACzD,IACG,CACP,CAAC;AACJ,CAAC;AAID,SAAS,QAAQ,CAAC,IAAa;IAC7B,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACnD,IAAI,IAAI,KAAK,UAAU;QAAE,OAAO,UAAU,CAAC;IAC3C,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI;QAAE,OAAO,MAAM,CAAC;IAC3C,OAAO,WAAW,CAAC;AACrB,CAAC"}
1
+ {"version":3,"file":"console-app.js","sourceRoot":"","sources":["../../../../../libs/braid-console/src/app/console-app.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE5D,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,gBAAgB,EAAmB,MAAM,kBAAkB,CAAC;AAClG,OAAO,EAAE,SAAS,EAAE,SAAS,EAAyB,MAAM,aAAa,CAAC;AAG1E,iGAAiG;AACjG,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,2BAA2B,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,CAAC;AACpH,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,wBAAwB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC;AAC3G,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,yBAAyB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC;AAE9G;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,UAAU,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAyD;IACtG,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAQ,GAAG,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IACvF,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAA6B,IAAI,CAAC,CAAC;IACjF,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAA8B,SAAS,CAAC,CAAC;IAC7E,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC5C,2FAA2F;IAC3F,wCAAwC;IACxC,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IACtD,iGAAiG;IACjG,4CAA4C;IAC5C,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAY,GAAG,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC/E,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACtD,uFAAuF;IACvF,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAqB,KAAK,CAAC,KAAK,CAAC,CAAC;IAE5E,SAAS,CAAC,GAAG,EAAE;QACb,YAAY,EAAE,CAAC;IACjB,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,qFAAqF;IACrF,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,YAAY,GAAG,GAAG,EAAE;YACxB,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YACnD,QAAQ,CAAC,IAAI,CAAC,CAAC;YACf,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ;gBAAE,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvD,CAAC,CAAC;QACF,MAAM,CAAC,gBAAgB,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;QACpD,OAAO,GAAG,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;IACtE,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAEX,+FAA+F;IAC/F,8FAA8F;IAC9F,4BAA4B;IAC5B,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,OAAO,GAAG,IAAI,CAAC;QACnB,gBAAgB,CAAC,GAAG,CAAC,CAAC,IAAI,CACxB,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,IAAI,cAAc,CAAC,MAAM,CAAC,EAC7C,GAAG,EAAE,CAAC,OAAO,IAAI,cAAc,CAAC,IAAI,CAAC,CACtC,CAAC;QACF,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,CACjB,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,IAAI,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,CAAC,EAC3D,CAAC,KAAc,EAAE,EAAE;YACjB,IAAI,CAAC,OAAO;gBAAE,OAAO;YACrB,oFAAoF;YACpF,2FAA2F;YAC3F,IAAI,OAAO,IAAI,KAAK,YAAY,gBAAgB,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG,IAAI,OAAO,CAAC,WAAW,EAAE;gBAAE,OAAO;YAC1G,SAAS,CAAC,SAAS,CAAC,CAAC;QACvB,CAAC,CACF,CAAC;QACF,OAAO,GAAG,EAAE;YACV,OAAO,GAAG,KAAK,CAAC;QAClB,CAAC,CAAC;QACF,uFAAuF;IACzF,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;IAE7B,SAAS,CAAC,GAAG,EAAE;QACb,UAAU,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACnG,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IAEjB,wFAAwF;IACxF,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,WAAW;YAAE,OAAO;QACzB,MAAM,IAAI,GAAG,CAAC,KAAwB,EAAE,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC;QAClE,MAAM,CAAC,gBAAgB,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC;QAC9C,OAAO,GAAG,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC;IAChE,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;IAElB,SAAS,EAAE,CAAC,IAAW;QACrB,4FAA4F;QAC5F,0CAA0C;QAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC;QACvG,IAAI,MAAM;YAAE,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,EAAE,EAAE,IAAI,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;;YAC7D,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QAC5C,QAAQ,CAAC,IAAI,CAAC,CAAC;QACf,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ;YAAE,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACvD,CAAC;IAED,+FAA+F;IAC/F,sDAAsD;IACtD,gGAAgG;IAChG,iCAAiC;IACjC,MAAM,OAAO,GAAG,IAAI,IAAI,WAAW,EAAE,OAAO,KAAK,IAAI,CAAC;IACtD,MAAM,IAAI,GAAkC;QAC1C,EAAE,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE;QACvC,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE;QACrC,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE;QACjC,EAAE,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE;QACnC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAE,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAW,CAAC,CAAC,CAAC,EAAE,CAAC;KACzE,CAAC;IACF,MAAM,IAAI,GAAS,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;IAEhF,OAAO,CACL,eAAK,SAAS,EAAC,eAAe,aAC5B,eAAK,SAAS,EAAC,sBAAsB,aACnC,eAAK,SAAS,EAAC,yBAAyB,aACtC,aAAI,SAAS,EAAC,6BAA6B,8BAAmB,EAC9D,gBAAM,SAAS,EAAC,2BAA2B,aACzC,8BAAkB,MAAM,uBAAS,EACjC,yBAAO,GAAG,CAAC,OAAO,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAQ,IAC7C,EACP,eAAM,SAAS,EAAC,uBAAuB,GAAG,EACzC,OAAO,IAAI,CACV,gBAAM,SAAS,EAAC,yBAAyB,aACvC,yBAAO,OAAO,CAAC,IAAI,GAAQ,EAC1B,WAAW,IAAI,eAAM,SAAS,EAAC,0BAA0B,YAAE,SAAS,CAAC,WAAW,CAAC,GAAQ,EAC1F,iBAAQ,IAAI,EAAC,QAAQ,EAAC,SAAS,EAAC,sBAAsB,EAAC,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,OAAO,CAAC,OAAO,EAAE,yBAEnF,IACJ,CACR,IACG,EAEN,cAAK,SAAS,EAAC,2BAA2B,YACxC,cAAK,SAAS,EAAC,qBAAqB,EAAC,IAAI,EAAC,SAAS,gBAAY,eAAe,YAC3E,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CACnB,iBAEE,IAAI,EAAC,QAAQ,EACb,IAAI,EAAC,KAAK,EACV,SAAS,EAAC,oBAAoB,mBACf,IAAI,KAAK,KAAK,CAAC,EAAE,EAChC,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,QAAQ,IAAI,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,YAEhH,KAAK,CAAC,KAAK,IAPP,KAAK,CAAC,EAAE,CAQN,CACV,CAAC,GACE,GACF,IACF,EAEN,MAAC,QAAQ,IAAC,QAAQ,EAAE,YAAG,SAAS,EAAC,sBAAsB,8BAAa,aAGjE,IAAI,KAAK,MAAM,IAAI,KAAC,cAAc,IAAC,GAAG,EAAE,GAAG,GAAI,EAC/C,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CACxB,cAAK,MAAM,EAAE,IAAI,KAAK,QAAQ,YAC5B,KAAC,WAAW,IACV,GAAG,EAAE,GAAG,EACR,QAAQ,EAAE,KAAK,CAAC,KAAK,IAAI,IAAI,EAC7B,QAAQ,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,EAC7E,WAAW,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,IAAI,WAAW,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC,EAC7E,aAAa,EAAE,cAAc,EAC7B,UAAU,EAAE,aAAa,GACzB,GACE,CACP,EACA,IAAI,KAAK,SAAS,IAAI,CACrB,KAAC,YAAY,IACX,GAAG,EAAE,GAAG,EACR,QAAQ,EAAE,GAAG,EAAE;4BACb,WAAW,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;4BAClC,gBAAgB,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;wBACzC,CAAC,GACD,CACH,IACQ,EACV,CAAC,IAAI,KAAK,WAAW,IAAI,IAAI,KAAK,UAAU,CAAC,IAAI,CAGhD,KAAC,eAAe,IAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,KAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAAI,CACzF,IACG,CACP,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAAC,EAAE,OAAO,EAAE,GAAG,EAAuB;IACtD,IAAI,OAAO,IAAI,GAAG;QAAE,OAAO,aAAa,CAAC;IACzC,IAAI,OAAO;QAAE,OAAO,wBAAwB,CAAC;IAC7C,OAAO,WAAW,CAAC;AACrB,CAAC"}
package/src/app/main.js CHANGED
@@ -1,6 +1,7 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { createRoot } from 'react-dom/client';
3
3
  import { ConsoleApp } from './console-app.js';
4
+ import { ensureStyles } from '../lib/styles.js';
4
5
  /**
5
6
  * Standalone entry — the deployable form.
6
7
  *
@@ -13,10 +14,32 @@ const mount = document.getElementById('root');
13
14
  if (!mount)
14
15
  throw new Error('braid-console: no #root element to mount into');
15
16
  const config = readConfig();
17
+ const root = createRoot(mount);
18
+ const { auth, edit, ...api } = config;
16
19
  // Read-only unless the deployment says otherwise. Editing needs a write API the gateway may not
17
20
  // have mounted, and defaulting to an editor that cannot save is a worse first impression than a
18
21
  // listing that works — so `edit` adds a tab rather than replacing the console with one.
19
- createRoot(mount).render(_jsx(ConsoleApp, { api: config, edit: config.edit === true }));
22
+ //
23
+ // With `auth`, nothing renders until there is a session: every request would otherwise go out
24
+ // anonymous and come back 401, which is noise, not information. The sign-in code is loaded only
25
+ // in this branch.
26
+ if (auth) {
27
+ // Something to see while the sign-in code loads and the issuer answers, instead of a blank page.
28
+ ensureStyles();
29
+ root.render(_jsx("div", { className: "braid-console", children: _jsx("p", { className: "braid-console__empty", role: "status", children: "Signing in\u2026" }) }));
30
+ import('./auth.js')
31
+ .then(({ signIn }) => signIn(auth))
32
+ .then((session) => root.render(_jsx(ConsoleApp, { api: { ...api, headers: session.headers }, edit: edit === true, session: session })), (error) => {
33
+ ensureStyles();
34
+ root.render(_jsx(SignInFailed, { error: error }));
35
+ });
36
+ }
37
+ else {
38
+ root.render(_jsx(ConsoleApp, { api: api, edit: edit === true }));
39
+ }
40
+ function SignInFailed({ error }) {
41
+ return (_jsx("div", { className: "braid-console", children: _jsxs("div", { className: "braid-console__error", role: "alert", children: [_jsx("h3", { children: "Could not sign in" }), _jsx("p", { children: error instanceof Error ? error.message : String(error) }), _jsx("button", { className: "braid-console__retry", type: "button", onClick: () => location.assign(location.pathname), children: "Try again" })] }) }));
42
+ }
20
43
  function readConfig() {
21
44
  const element = document.getElementById('braid-console-config');
22
45
  if (!element?.textContent)
@@ -1 +1 @@
1
- {"version":3,"file":"main.js","sourceRoot":"","sources":["../../../../../libs/braid-console/src/app/main.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG9C;;;;;;;GAOG;AACH,MAAM,KAAK,GAAG,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;AAC9C,IAAI,CAAC,KAAK;IAAE,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;AAE7E,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;AAE5B,gGAAgG;AAChG,gGAAgG;AAChG,wFAAwF;AACxF,UAAU,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAC,UAAU,IAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,KAAK,IAAI,GAAI,CAAC,CAAC;AAElF,SAAS,UAAU;IACjB,MAAM,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,sBAAsB,CAAC,CAAC;IAChE,IAAI,CAAC,OAAO,EAAE,WAAW;QAAE,OAAO,EAAE,CAAC;IACrC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAoC,CAAC;IAC5E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,IAAI,CAAC,wEAAwE,CAAC,CAAC;QACvF,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../../../../../libs/braid-console/src/app/main.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG9C,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD;;;;;;;GAOG;AACH,MAAM,KAAK,GAAG,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;AAC9C,IAAI,CAAC,KAAK;IAAE,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;AAE7E,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;AAE5B,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;AAC/B,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,GAAG,EAAE,GAAG,MAAM,CAAC;AAEtC,gGAAgG;AAChG,gGAAgG;AAChG,wFAAwF;AACxF,EAAE;AACF,8FAA8F;AAC9F,gGAAgG;AAChG,kBAAkB;AAClB,IAAI,IAAI,EAAE,CAAC;IACT,iGAAiG;IACjG,YAAY,EAAE,CAAC;IACf,IAAI,CAAC,MAAM,CACT,cAAK,SAAS,EAAC,eAAe,YAC5B,YAAG,SAAS,EAAC,sBAAsB,EAAC,IAAI,EAAC,QAAQ,iCAE7C,GACA,CACP,CAAC;IACF,MAAM,CAAC,WAAW,CAAC;SAChB,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;SAClC,IAAI,CACH,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAC,UAAU,IAAC,GAAG,EAAE,EAAE,GAAG,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,EAAE,OAAO,EAAE,OAAO,GAAI,CAAC,EAC1H,CAAC,KAAc,EAAE,EAAE;QACjB,YAAY,EAAE,CAAC;QACf,IAAI,CAAC,MAAM,CAAC,KAAC,YAAY,IAAC,KAAK,EAAE,KAAK,GAAI,CAAC,CAAC;IAC9C,CAAC,CACF,CAAC;AACN,CAAC;KAAM,CAAC;IACN,IAAI,CAAC,MAAM,CAAC,KAAC,UAAU,IAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,GAAI,CAAC,CAAC;AAC7D,CAAC;AAED,SAAS,YAAY,CAAC,EAAE,KAAK,EAAsB;IACjD,OAAO,CACL,cAAK,SAAS,EAAC,eAAe,YAC5B,eAAK,SAAS,EAAC,sBAAsB,EAAC,IAAI,EAAC,OAAO,aAChD,6CAA0B,EAC1B,sBAAI,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAAK,EAC/D,iBAAQ,SAAS,EAAC,sBAAsB,EAAC,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,0BAE/F,IACL,GACF,CACP,CAAC;AACJ,CAAC;AAID,SAAS,UAAU;IACjB,MAAM,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,sBAAsB,CAAC,CAAC;IAChE,IAAI,CAAC,OAAO,EAAE,WAAW;QAAE,OAAO,EAAE,CAAC;IACrC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAW,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,IAAI,CAAC,wEAAwE,CAAC,CAAC;QACvF,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * The standalone app's views, in the URL hash so a view is a link someone can paste into a ticket.
3
+ *
4
+ * Old links keep working: `#fragments`, `#topology` and `#edit` mean what they always did, and
5
+ * anything unrecognized lands on the fragment list rather than a blank page.
6
+ */
7
+ export type View = 'fragments' | 'topology' | 'shells' | 'history' | 'edit';
8
+ export interface Route {
9
+ view: View;
10
+ /** `#shells/<id>`: the shell open in the designer. */
11
+ shell?: string;
12
+ }
13
+ export declare function readRoute(hash: string, edit: boolean): Route;
14
+ export declare function routeHash(route: Route): string;
@@ -0,0 +1,23 @@
1
+ export function readRoute(hash, edit) {
2
+ const [view = '', ...rest] = hash.replace(/^#\/?/, '').split('/');
3
+ if (view === 'topology' || view === 'history')
4
+ return { view };
5
+ if (view === 'edit' && edit)
6
+ return { view };
7
+ if (view === 'shells') {
8
+ const id = rest.join('/');
9
+ if (!id)
10
+ return { view };
11
+ try {
12
+ return { view, shell: decodeURIComponent(id) };
13
+ }
14
+ catch {
15
+ return { view };
16
+ }
17
+ }
18
+ return { view: 'fragments' };
19
+ }
20
+ export function routeHash(route) {
21
+ return route.view === 'shells' && route.shell ? `shells/${encodeURIComponent(route.shell)}` : route.view;
22
+ }
23
+ //# sourceMappingURL=routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../../../libs/braid-console/src/app/routes.ts"],"names":[],"mappings":"AAcA,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,IAAa;IACnD,MAAM,CAAC,IAAI,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAClE,IAAI,IAAI,KAAK,UAAU,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC/D,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI;QAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC7C,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC1B,IAAI,CAAC,EAAE;YAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,kBAAkB,CAAC,EAAE,CAAC,EAAE,CAAC;QACjD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,IAAI,EAAE,CAAC;QAClB,CAAC;IACH,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAY;IACpC,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,kBAAkB,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;AAC3G,CAAC"}
package/src/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @braidlabs/console — a read-only view of a Braid gateway's fragment registry.
2
+ * @braidlabs/console — a console for a Braid gateway's registry: fragments, shells, and history.
3
3
  *
4
4
  * Two ways to use it, from one package:
5
5
  *
@@ -33,6 +33,19 @@ export { AccessPanel } from './lib/access-panel.js';
33
33
  export type { AccessPanelProps } from './lib/access-panel.js';
34
34
  export { createDraft, draftStatus, addFragment, removeFragment, updateFragment, resetDraft, parseList, formatList, } from './lib/draft.js';
35
35
  export type { Draft, DraftStatus } from './lib/draft.js';
36
- export { fetchRegistry, fetchHead, listSnapshots, publishSnapshot, pinSnapshot, RegistryFetchError, RegistryApiError, DEFAULT_DISCOVERY_PATH, DEFAULT_API_PATH, } from './lib/client.js';
36
+ export { fetchRegistry, fetchHead, listSnapshots, publishSnapshot, pinSnapshot, fetchPermissions, RegistryFetchError, RegistryApiError, DEFAULT_DISCOVERY_PATH, DEFAULT_API_PATH, } from './lib/client.js';
37
37
  export type { ConsoleApi, RegistryListing, HeadState, PublishOutcome } from './lib/client.js';
38
38
  export { CONSOLE_STYLES, ensureStyles } from './lib/styles.js';
39
+ export { ShellsPanel, newShell } from './lib/shells-panel.js';
40
+ export type { ShellsPanelProps } from './lib/shells-panel.js';
41
+ export { HistoryPanel } from './lib/history-panel.js';
42
+ export type { HistoryPanelProps } from './lib/history-panel.js';
43
+ export { EmptyState, emptyKindOf } from './lib/empty-state.js';
44
+ export type { EmptyKind } from './lib/empty-state.js';
45
+ export { shellCode, SHELL_TARGETS, angularPath } from './lib/shell-codegen.js';
46
+ export type { GeneratedFile } from './lib/shell-codegen.js';
47
+ export { parseQuery, matchQuery, filterBy, fragmentItem, shellItem, QUERY_KEYS } from './lib/query.js';
48
+ export type { ParsedQuery, QueryTerm, QueryKey, SearchItem } from './lib/query.js';
49
+ export { tagColor, tagClass, TAG_COLOR_COUNT } from './lib/tags.js';
50
+ export { TagChip } from './lib/tag-chip.js';
51
+ export { tagQuery } from './lib/registry-console.js';
package/src/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @braidlabs/console — a read-only view of a Braid gateway's fragment registry.
2
+ * @braidlabs/console — a console for a Braid gateway's registry: fragments, shells, and history.
3
3
  *
4
4
  * Two ways to use it, from one package:
5
5
  *
@@ -25,6 +25,14 @@ export { buildTopology, neighborhood, coTenants, edgeKey } from './lib/topology.
25
25
  export { RegistryEditor } from './lib/registry-editor.js';
26
26
  export { AccessPanel } from './lib/access-panel.js';
27
27
  export { createDraft, draftStatus, addFragment, removeFragment, updateFragment, resetDraft, parseList, formatList, } from './lib/draft.js';
28
- export { fetchRegistry, fetchHead, listSnapshots, publishSnapshot, pinSnapshot, RegistryFetchError, RegistryApiError, DEFAULT_DISCOVERY_PATH, DEFAULT_API_PATH, } from './lib/client.js';
28
+ export { fetchRegistry, fetchHead, listSnapshots, publishSnapshot, pinSnapshot, fetchPermissions, RegistryFetchError, RegistryApiError, DEFAULT_DISCOVERY_PATH, DEFAULT_API_PATH, } from './lib/client.js';
29
29
  export { CONSOLE_STYLES, ensureStyles } from './lib/styles.js';
30
+ export { ShellsPanel, newShell } from './lib/shells-panel.js';
31
+ export { HistoryPanel } from './lib/history-panel.js';
32
+ export { EmptyState, emptyKindOf } from './lib/empty-state.js';
33
+ export { shellCode, SHELL_TARGETS, angularPath } from './lib/shell-codegen.js';
34
+ export { parseQuery, matchQuery, filterBy, fragmentItem, shellItem, QUERY_KEYS } from './lib/query.js';
35
+ export { tagColor, tagClass, TAG_COLOR_COUNT } from './lib/tags.js';
36
+ export { TagChip } from './lib/tag-chip.js';
37
+ export { tagQuery } from './lib/registry-console.js';
30
38
  //# sourceMappingURL=index.js.map
package/src/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/braid-console/src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC3E,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAE9D,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAG5H,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAGpF,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD,OAAO,EACL,WAAW,EACX,WAAW,EACX,WAAW,EACX,cAAc,EACd,cAAc,EACd,UAAU,EACV,SAAS,EACT,UAAU,GACX,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,aAAa,EACb,SAAS,EACT,aAAa,EACb,eAAe,EACf,WAAW,EACX,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,EACtB,gBAAgB,GACjB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/braid-console/src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC3E,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAE9D,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAG5H,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAGpF,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD,OAAO,EACL,WAAW,EACX,WAAW,EACX,WAAW,EACX,cAAc,EACd,cAAc,EACd,UAAU,EACV,SAAS,EACT,UAAU,GACX,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,aAAa,EACb,SAAS,EACT,aAAa,EACb,eAAe,EACf,WAAW,EACX,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,EACtB,gBAAgB,GACjB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAE9D,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAEtD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAE/D,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAE/E,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEvG,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC"}