@zackbart/connecta 0.32.0 → 0.34.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/CHANGELOG.md +98 -0
- package/README.md +95 -116
- package/SECURITY.md +1 -1
- package/bin/connecta.mjs +24 -6
- package/bin/version.mjs +1 -1
- package/dist/access-tokens.d.ts +167 -23
- package/dist/access-tokens.js +676 -140
- package/dist/activity.d.ts +3 -0
- package/dist/agent-identity.js +47 -0
- package/dist/auth/cloudflare-access.js +13 -5
- package/dist/branding.d.ts +7 -0
- package/dist/branding.js +76 -9
- package/dist/call-admission-context.js +15 -0
- package/dist/call-admission.js +30 -43
- package/dist/call-recovery.js +6 -2
- package/dist/catalog-service.js +15 -1
- package/dist/config-value-sources.js +16 -9
- package/dist/config.d.ts +48 -75
- package/dist/config.js +144 -36
- package/dist/connector-access.d.ts +4 -34
- package/dist/connector-access.js +15 -99
- package/dist/connector-caller.d.ts +7 -1
- package/dist/connector-caller.js +4 -2
- package/dist/connectors/api-connector.d.ts +27 -4
- package/dist/connectors/api-connector.js +2 -0
- package/dist/connectors/remote-mcp.js +2 -0
- package/dist/describe-config.d.ts +31 -7
- package/dist/describe-config.js +8 -17
- package/dist/execute.js +1 -11
- package/dist/fix-prompt.js +2 -2
- package/dist/index.d.ts +4 -3
- package/dist/index.js +30 -10
- package/dist/invocation.js +5 -3
- package/dist/membership.d.ts +53 -0
- package/dist/membership.js +121 -0
- package/dist/module-contracts.d.ts +23 -6
- package/dist/oauth-callback-outcome.js +2 -2
- package/dist/operator-record.d.ts +2 -2
- package/dist/operator-record.js +2 -4
- package/dist/operator-ui/agents.d.ts +74 -0
- package/dist/operator-ui/agents.js +104 -0
- package/dist/operator-ui/config-summary.js +562 -0
- package/dist/operator-ui/connection-map.js +375 -0
- package/dist/operator-ui/contract.d.ts +149 -28
- package/dist/operator-ui/endpoints.js +221 -0
- package/dist/operator-ui/fix-prompts.js +5 -5
- package/dist/operator-ui/generated.js +5 -4
- package/dist/operator-ui/member-page.js +97 -0
- package/dist/operator-ui/model.d.ts +14 -6
- package/dist/operator-ui/overview.js +134 -0
- package/dist/operator-ui/view.d.ts +107 -37
- package/dist/operator-ui/view.js +163 -86
- package/dist/page-styles.js +5 -3
- package/dist/provider.d.ts +61 -8
- package/dist/provider.js +46 -7
- package/dist/providers/_shared/google/workspace.d.ts +56 -17
- package/dist/providers/_shared/google/workspace.js +34 -8
- package/dist/providers/_shared/rest/tools.js +2 -2
- package/dist/providers/_shared/rest/value-safety.d.ts +50 -0
- package/dist/providers/_shared/rest/value-safety.js +699 -7
- package/dist/providers/ccb/index.js +2 -2
- package/dist/providers/cloudflare/index.js +3 -3
- package/dist/providers/cloudflare/rest.js +25 -3
- package/dist/providers/cloudflare/skill.generated.js +1 -1
- package/dist/providers/cloudflare/value-safety.js +32 -0
- package/dist/providers/docs/index.js +4 -4
- package/dist/providers/docs/skill.generated.js +2 -2
- package/dist/providers/drive/index.js +4 -4
- package/dist/providers/drive/skill.generated.js +2 -2
- package/dist/providers/forms/index.js +4 -4
- package/dist/providers/forms/skill.generated.js +2 -2
- package/dist/providers/gmail/index.js +11 -9
- package/dist/providers/gmail/skill.generated.js +2 -2
- package/dist/providers/mixpanel/index.js +1 -1
- package/dist/providers/mixpanel/skill.generated.js +3 -3
- package/dist/providers/notion/index.d.ts +7 -0
- package/dist/providers/notion/index.js +100 -11
- package/dist/providers/notion/rest.js +45 -5
- package/dist/providers/notion/skill.generated.js +2 -2
- package/dist/providers/notion/value-safety.js +30 -5
- package/dist/providers/overflow/index.js +2 -2
- package/dist/providers/overflow/skill.generated.js +2 -2
- package/dist/providers/planning-center/index.js +2 -2
- package/dist/providers/planning-center/skill.generated.js +4 -4
- package/dist/providers/revenuecat/skill.generated.js +2 -2
- package/dist/providers/sheets/index.d.ts +3 -0
- package/dist/providers/sheets/index.js +7 -4
- package/dist/providers/sheets/skill.generated.js +2 -2
- package/dist/providers/slides/index.js +4 -4
- package/dist/providers/slides/skill.generated.js +2 -2
- package/dist/providers/stripe/rest.js +9 -2
- package/dist/providers/stripe/skill.generated.js +1 -1
- package/dist/providers/stripe/value-safety.js +22 -0
- package/dist/providers/tithely/index.js +1 -1
- package/dist/providers/vercel/index.js +1 -1
- package/dist/providers/vercel/rest.js +20 -2
- package/dist/providers/vercel/skill.generated.js +2 -2
- package/dist/providers/vercel/value-safety.js +22 -0
- package/dist/registry.d.ts +2 -3
- package/dist/registry.js +23 -9
- package/dist/routes/access-tokens.js +82 -75
- package/dist/routes/activity-disclosure.js +17 -18
- package/dist/routes/activity.js +34 -54
- package/dist/routes/actor-labels.js +33 -4
- package/dist/routes/agent-path.js +43 -0
- package/dist/routes/connect.js +16 -12
- package/dist/routes/credentials.js +16 -40
- package/dist/routes/mcp.js +161 -104
- package/dist/routes/oauth-management.js +11 -5
- package/dist/routes/oauth.js +5 -11
- package/dist/routes/operator.js +24 -23
- package/dist/routes/shared.d.ts +60 -20
- package/dist/routes/shared.js +187 -96
- package/dist/routes/ui-config.js +437 -97
- package/dist/routes/ui-data.js +2 -2
- package/dist/routes/ui.js +9 -16
- package/dist/runtime/call-admission.js +9 -0
- package/dist/server.js +5 -0
- package/dist/skills.js +10 -0
- package/dist/storage/keys.js +9 -1
- package/dist/storage/sql.js +5 -1
- package/dist/types.d.ts +29 -7
- package/dist/ui.d.ts +1 -1
- package/dist/ui.js +23 -16
- package/dist/usage-guide.js +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/workspace-address.js +9 -0
- package/dist/workspace-subject.js +23 -0
- package/documentation/README.md +47 -23
- package/documentation/architecture.md +371 -61
- package/documentation/auth.md +897 -249
- package/documentation/code-mode.md +37 -16
- package/documentation/deploying.md +126 -25
- package/documentation/integrating.md +97 -23
- package/documentation/meta-tools.md +50 -31
- package/documentation/migration-0.33.md +352 -0
- package/documentation/migration-0.34.md +67 -0
- package/documentation/operating.md +3 -1
- package/documentation/operator-tests.md +147 -34
- package/documentation/operator-ui.md +519 -64
- package/documentation/provider-auth-migration.md +37 -23
- package/documentation/provider-migration-0.29.md +2 -2
- package/examples/worker/AGENTS.md +37 -9
- package/examples/worker/README.md +127 -61
- package/examples/worker/src/connecta.config.ts +40 -23
- package/examples/worker/wrangler.jsonc +4 -1
- package/package.json +19 -18
- package/templates/node/.env.example +3 -0
- package/templates/node/AGENTS.md +33 -6
- package/templates/node/Dockerfile +2 -2
- package/templates/node/README.md +80 -52
- package/templates/node/docker-compose.yml +3 -2
- package/templates/node/package.json +4 -3
- package/templates/node/src/adopt-token.ts +23 -0
- package/templates/node/src/connecta.config.ts +28 -12
- package/templates/node/src/rotate-token.ts +17 -0
- package/templates/node/src/provision-token.ts +0 -17
|
@@ -10,6 +10,8 @@ credential ownership, and grants use [Auth](./auth.md).
|
|
|
10
10
|
| Task | Read |
|
|
11
11
|
| ----------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
|
|
12
12
|
| Enable UI, vault, or history in a deployment | [Setup](#setup), then the platform template |
|
|
13
|
+
| Find what a page shows or where a route goes | [Pages](#pages) |
|
|
14
|
+
| Find a member's endpoint or set up their client | [Use the member page](#use-the-member-page) |
|
|
13
15
|
| Consume config, provenance, status, or activity | [Operator data contract](#operator-data-contract) |
|
|
14
16
|
| Change a UI page or data route | [Source and tests](#source-and-tests), [browser verification](./operator-tests.md) |
|
|
15
17
|
| Diagnose permission refusals | [Management permissions](./auth.md#management-permissions), [activity disclosure below](#operator-data-contract) |
|
|
@@ -22,81 +24,514 @@ and [Worker example](../examples/worker/README.md#select-optional-modules)
|
|
|
22
24
|
own the runnable configuration, variables, and branding shape. The UI is an
|
|
23
25
|
explicit optional import and stays outside the root package import graph.
|
|
24
26
|
|
|
25
|
-
Overview, Connectors, Tools, Access, Activity, and Config show only what the
|
|
26
|
-
caller may inspect. Connector detail tabs cover configuration, schemas,
|
|
27
|
-
authentication, activity, and diagnostics. Config labels values as default or
|
|
28
|
-
configured. Deployment code owns connectors, grants, pools, and classification;
|
|
29
|
-
the UI changes only authorized authentication material.
|
|
30
|
-
|
|
31
27
|
Install the vault for declared credential slots and activity history for
|
|
32
28
|
persisted call records. Neither module grants permission to manage or read
|
|
33
|
-
it.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
29
|
+
it: [auth](./auth.md#management-permissions) does. Interactive maintainers
|
|
30
|
+
administer shared credentials and agent tokens, maintainers read activity, and
|
|
31
|
+
pool members connect their own accounts on personal connectors in their pools.
|
|
32
|
+
Token management issues, rotates, and revokes the tokens of agents declared in
|
|
33
|
+
code; it never creates, renames, or binds an agent. Agent tokens never grant
|
|
34
|
+
interactive credential or token management authority.
|
|
35
|
+
|
|
36
|
+
## Pages
|
|
37
|
+
|
|
38
|
+
The UI shows configuration and never edits it. Deployment code owns
|
|
39
|
+
connectors, grants, pools, agents and classification. The UI changes only
|
|
40
|
+
credentials, OAuth connections and agent tokens, through the existing routes.
|
|
41
|
+
No select menu displays configuration. Copy is short labels; a failure names
|
|
42
|
+
what to do next in one or two sentences and never quotes a route's or
|
|
43
|
+
downstream's text.
|
|
44
|
+
|
|
45
|
+
| Path | Page | Who |
|
|
46
|
+
| ------------------ | ------------------------------------------------------ | ---------- |
|
|
47
|
+
| `/` | Overview (a member gets the member page) | Maintainer |
|
|
48
|
+
| `/endpoints` | Endpoints; `#mcp/<pool>` opens that row | Maintainer |
|
|
49
|
+
| `/connectors` | Connectors list; `?view=matrix` for the matrix | Maintainer |
|
|
50
|
+
| `/connectors/<id>` | Connector detail; `#tools`, `#connection`, `#activity` | Maintainer |
|
|
51
|
+
| `/activity` | Activity | Maintainer |
|
|
52
|
+
| `/tokens` | Tokens, when token management is open to the viewer | Maintainer |
|
|
53
|
+
| `/settings` | Settings | Maintainer |
|
|
54
|
+
|
|
55
|
+
`/access` redirects to `/endpoints`, `/tools` to `/connectors`, and `/config`
|
|
56
|
+
to `/settings`, replacing the history entry. Connector hashes `#config`,
|
|
57
|
+
`#auth` and `#diagnostics` redirect to `#connection` and keep query
|
|
58
|
+
parameters such as signed handoffs. A pool member sees the
|
|
59
|
+
[member page](#use-the-member-page) on every path.
|
|
60
|
+
|
|
61
|
+
### Overview
|
|
62
|
+
|
|
63
|
+
- **Status pill.** "N need attention" (red when a connector is failing) or
|
|
64
|
+
"All healthy". No pill without connectors.
|
|
65
|
+
- **Stat tiles.** Connectors (healthy of total, a bar with one segment per
|
|
66
|
+
connector in its health color), Endpoints (count, a bar split read-only and
|
|
67
|
+
read-write), and People · Agents (both counts, up to eight avatars and agent
|
|
68
|
+
marks; a tokenless agent's mark is hollow). A dot legend counts each segment
|
|
69
|
+
kind; the first two tiles link to their pages. At 760px and below the tiles
|
|
70
|
+
sit two up, with People · Agents as one row across both.
|
|
71
|
+
- **Needs attention.** One row per connector whose health is not ok, failing
|
|
72
|
+
first, then one per agent in a pool whose token is missing or revoked. A
|
|
73
|
+
row names the problem ("crm needs authorization"), the endpoints it
|
|
74
|
+
affects ("Affects /mcp and /mcp/team") or the agent URL it can't connect at,
|
|
75
|
+
and links to the existing fix: Connect, Replace key, Inspect or Review on
|
|
76
|
+
the connector's Connection tab, or Issue token on Tokens. A row with a
|
|
77
|
+
problem code or drift also has Copy fix prompt. A problem keeps its row and
|
|
78
|
+
prompt when the connector's detail read failed, prefixed "Details didn't
|
|
79
|
+
load". With no rows it reads "All clear".
|
|
80
|
+
- **Who reaches what.** The [connection map](#connection-map).
|
|
81
|
+
|
|
82
|
+
### Connection map
|
|
83
|
+
|
|
84
|
+
An SVG flow of callers (people in contract order, then declared agents) to
|
|
85
|
+
endpoints (`/mcp`, then pools) to connectors in config order, with a last
|
|
86
|
+
column of each connector's read and write tool counts. A connector whose
|
|
87
|
+
catalog is unknown (failed or not yet observed) draws a muted dash there
|
|
88
|
+
instead of "0 tools".
|
|
89
|
+
|
|
90
|
+
- A grant link takes its connector's health color. Grants on a read-only
|
|
91
|
+
endpoint are dashed; an agent's link to its pool is dotted while it has no
|
|
92
|
+
issued token. Plain `/mcp` admits no agents. A read-only endpoint carries a
|
|
93
|
+
read-only chip.
|
|
94
|
+
- Hovering or focusing a node dims everything off its paths and replaces the
|
|
95
|
+
legend with one sentence, such as "alice reaches 2 connectors through /mcp
|
|
96
|
+
and /mcp/team: 6 tools, 1 write." The sentence is also the node's accessible
|
|
97
|
+
name. Hover wins while both are set.
|
|
98
|
+
- The map is one tab stop. Arrow keys move within a column and to the nearest
|
|
99
|
+
node in the next one; Home and End go to the first and last node.
|
|
100
|
+
- Click or Enter opens the node's page: a connector's Tools tab (Connection
|
|
101
|
+
when it needs attention), an endpoint's row on Endpoints, a person's first
|
|
102
|
+
endpoint, or Tokens for an agent when that page is open. A node without a
|
|
103
|
+
page is a `group`.
|
|
104
|
+
- The drawing never scales below 880px; a narrower card scrolls it sideways.
|
|
105
|
+
At 960px and below it becomes a list with one entry per endpoint: its mode,
|
|
106
|
+
its callers as chips that link like map nodes, and its connectors with
|
|
107
|
+
health. With no connectors it reads "Nothing to map yet".
|
|
108
|
+
|
|
109
|
+
### Endpoints
|
|
110
|
+
|
|
111
|
+
One row each for `/mcp` and every pool: the path, a read-only pill on a
|
|
112
|
+
read-only endpoint, a copyable URL, who can use it, its connectors as colored
|
|
113
|
+
monograms (four, then "+N"), its tool count over a read and write bar, and a
|
|
114
|
+
Setup button.
|
|
115
|
+
|
|
116
|
+
- Who can use it is `root.maintainers` on `/mcp` and the pool's `members`
|
|
117
|
+
elsewhere, as an avatar stack named on hover and to screen readers (label,
|
|
118
|
+
raw id when the label is null, or agent name). Four show, then a "+N"
|
|
119
|
+
button. A pool with agent members labels its two URLs People and Agents.
|
|
120
|
+
- Expanding a row lists everyone by name, then each connector with what it
|
|
121
|
+
runs as and its tools, write tools amber with a pencil. Runs-as comes from
|
|
122
|
+
the endpoint's matrix cell: "Shared · saved <date>", "Shared · connected
|
|
123
|
+
<date>", "Shared · not configured", "Shared · set in deployment", "Shared ·
|
|
124
|
+
no credential needed", "Personal · N of M connected", "Workspace · people:
|
|
125
|
+
self · agents: <owner>" (or "none"), or "Everyone acts as <subject>".
|
|
126
|
+
- A connector that needs attention gets a status dot on its monogram and
|
|
127
|
+
beside its name, linking to its Connection tab.
|
|
128
|
+
- Setup opens a drawer with the URL and a Claude Code, Codex or JSON snippet
|
|
129
|
+
with a copy button. No snippet carries a token.
|
|
130
|
+
|
|
131
|
+
Counts intersect live tools with the pool's declared tools (the `/mcp` matrix
|
|
132
|
+
cells for the root), guarded grants' live verdicts, and read-only mode.
|
|
133
|
+
|
|
134
|
+
### Connectors
|
|
135
|
+
|
|
136
|
+
One card per connector: title and id, one status pill, a Shared or Per person
|
|
137
|
+
badge, its tool count over a read and write bar, and when it was last called.
|
|
138
|
+
All, Needs attention and Healthy filter the cards, with counts, beside a
|
|
139
|
+
search field. A connector that is not fine adds one action (Connect, Replace
|
|
140
|
+
key, Inspect, or Review for drift) that opens its Connection tab.
|
|
141
|
+
|
|
142
|
+
Every view shares one verdict per connector: the server's problem code first
|
|
143
|
+
(a failed catalog reads "Catalog failed", never "Connected"), then a failed
|
|
144
|
+
detail read ("Couldn't load", with no fix prompt), then a non-ok status, then
|
|
145
|
+
catalog drift.
|
|
146
|
+
|
|
147
|
+
A List / Matrix toggle (`?view=matrix`) switches to a table of connectors by
|
|
148
|
+
endpoint, `/mcp` first. A row header is the connector's monogram and name, plus
|
|
149
|
+
a status dot linking to Connection when it needs fixing. Each cell is a pie of
|
|
150
|
+
how much of the live catalog it grants, with "all", a count, or a dash for
|
|
151
|
+
none; read-only columns are hatched. Only granted names still in the live
|
|
152
|
+
catalog count. An unknown catalog shows a dashed empty ring and "?". A cell
|
|
153
|
+
with grants is a button named like "GitHub on /mcp/support: 1 of 2 live
|
|
154
|
+
tools, read-only"; it opens a popover of that cell's tools, each with a read
|
|
155
|
+
or write pill (a write struck through on a read-only endpoint), and its
|
|
156
|
+
runs-as. Escape or Tab returns focus to the cell. CSS anchor positioning
|
|
157
|
+
places the popover below the cell, or above when there is more room, and the
|
|
158
|
+
page sets no inline styles. Without anchor support the same list opens as a
|
|
159
|
+
row under the connector.
|
|
160
|
+
|
|
161
|
+
### Connector detail
|
|
162
|
+
|
|
163
|
+
The title, status pill, id, auth badge and read and write bar, then three
|
|
164
|
+
tabs:
|
|
165
|
+
|
|
166
|
+
- **Tools.** Each tool by its mono address with a Read or Write badge and
|
|
167
|
+
annotation badges (Destructive, Open world), filtered by search and All,
|
|
168
|
+
Read and Write. A tool opens its schema in a side drawer.
|
|
169
|
+
- **Connection.** An Authentication card (mode, OAuth client mechanism, who
|
|
170
|
+
manages it, OAuth actions, and the credential card with masked last four,
|
|
171
|
+
field states, and Replace, Test and Remove); a Diagnostics card of tiles
|
|
172
|
+
(catalog age, last call, drift counts) with a fix prompt beside each
|
|
173
|
+
problem; and a Configuration card. Its badges name the kind (Remote MCP,
|
|
174
|
+
HTTP API or Custom), provider, auth scope, endpoint host and usage guide.
|
|
175
|
+
The auth row names the mode and draws each auth fact as a mono badge
|
|
176
|
+
(credential fields, header and scheme, static header names, OAuth scope, API
|
|
177
|
+
origins as `→ api.crm.example`, OAuth endpoints, client metadata host,
|
|
178
|
+
token auth method, Client secret, PKCE, extra parameter and header names).
|
|
179
|
+
Tiles follow for the result cap, call admission rules and transport. Any
|
|
180
|
+
other key becomes a tile labelled from its name.
|
|
181
|
+
- **Activity.** The [Activity](#activity) page for that connector, without
|
|
182
|
+
connector chips or monograms.
|
|
183
|
+
|
|
184
|
+
### Settings
|
|
185
|
+
|
|
186
|
+
The configuration snapshot as tiles, tagged "Defined in code", with no
|
|
187
|
+
editing controls. An empty section is not drawn.
|
|
188
|
+
|
|
189
|
+
- **Deployment.** Fact chips: name and version (`Production · v1`), Writes
|
|
190
|
+
allowed or Read-only, connecta version, public URL, allowed origins,
|
|
191
|
+
sandbox, storage, activity store, deployment ID, website, icon count and
|
|
192
|
+
`deploymentInfo` keys. Default memory storage reads "Memory · default" as a
|
|
193
|
+
warning: on Node a restart loses it.
|
|
194
|
+
- **Sign-in.** One tile per inbound auth provider in the order they are tried,
|
|
195
|
+
with its mark and whether it admits people or machines; the agent-token
|
|
196
|
+
tile counts agents ("3 agents"). Then a Maintainers tile with the `/mcp`
|
|
197
|
+
maintainers, or "None". With no providers an Open tile comes first.
|
|
198
|
+
- **Features.** Vault ("Seals OAuth" when it does), activity, agent tokens
|
|
199
|
+
and any other module, on or off.
|
|
200
|
+
- **Limits.** Each limit as a value over a short label: durations in their
|
|
201
|
+
largest whole unit, sizes in decimal KB or MB with exact bytes as a
|
|
202
|
+
tooltip, counts with separators, "No limit", and On or Off. A null tool
|
|
203
|
+
timeout shows the host-call timeout it falls back to. Headline limits and
|
|
204
|
+
any limit set in code draw large. The rest sit behind one disclosure
|
|
205
|
+
("17 defaults") with Discovery, Results, Programs and Requests groups. A
|
|
206
|
+
value set in code (by `configSources`) has an accent dot; a default reads
|
|
207
|
+
muted. Activity retention counts as set only when the activity store
|
|
208
|
+
reports `optionSources.retentionDays` as `"config"`, as the shipped D1 and
|
|
209
|
+
SQLite stores do.
|
|
210
|
+
- **Overrides.** Each classification override as tool address and verdict.
|
|
211
|
+
- **Other.** Any snapshot key Settings does not map, as a tile labelled from
|
|
212
|
+
its name, set only when its value carries `source: "config"`.
|
|
213
|
+
|
|
214
|
+
### Tokens
|
|
215
|
+
|
|
216
|
+
One row per agent declared in code, in `GET /ui/access-tokens` order: agent
|
|
217
|
+
mark and name, pools as chips, a state pill (No token, Issued or Revoked), the
|
|
218
|
+
issue or revoke date, and last seen ("never" when null). The heading note
|
|
219
|
+
reads "Declared in code"; nothing creates or renames an agent. Narrow screens
|
|
220
|
+
stack each row into a card.
|
|
221
|
+
|
|
222
|
+
- Issue appears for a slot with no token or a revoked one; Rotate and a quiet
|
|
223
|
+
red Revoke for an issued one. Rotate and Revoke ask first in a row under the
|
|
224
|
+
agent, with focus on Cancel.
|
|
225
|
+
- Every mutation sends `{ "expect": "<revision>" }` with the slot revision the
|
|
226
|
+
operator saw. A new secret opens once in a dialog with a copy button and
|
|
227
|
+
"You won't see this token again."; closing it drops the secret, and
|
|
228
|
+
recovery never closes it.
|
|
229
|
+
- A 409 `slot_changed` reads "Changed since you looked. Refresh." A 503
|
|
230
|
+
`outcome_unknown` or 499 `aborted` is a failure notice and is never
|
|
231
|
+
retried.
|
|
232
|
+
- A sent mutation leaves its slot unresolved until its successful response is
|
|
233
|
+
validated. Any other outcome, a contract whose `agents[].token` disagrees
|
|
234
|
+
with the list (revision included) or drops the agent, or a failed read
|
|
235
|
+
leaves it unresolved until a later slot-list read succeeds. Until then its
|
|
236
|
+
controls are off with "Refresh to continue", and each action is checked
|
|
237
|
+
again just before it is sent.
|
|
238
|
+
- Under the recovery banner Tokens has no Refresh or list Retry of its own,
|
|
239
|
+
and an open rotate or revoke question closes.
|
|
240
|
+
|
|
241
|
+
### Activity
|
|
242
|
+
|
|
243
|
+
Counts for the loaded history (calls, failed, tools, catalog changes), also
|
|
244
|
+
in its accessible summary, and a strip of calls over time with failures in
|
|
245
|
+
red when the calls span more than a minute.
|
|
246
|
+
|
|
247
|
+
- **Filters.** One bar: search, All / Failed / Succeeded (`?outcome=failed`
|
|
248
|
+
keeps errors and timeouts, `?outcome=succeeded` successes and approvals),
|
|
249
|
+
and chips for each loaded connector and source (`?connector=`, `?source=`).
|
|
250
|
+
Pressing a pressed chip clears it, and a selected value keeps its chip.
|
|
251
|
+
Another `?outcome=` value matches exactly and shows as a clearable Exact
|
|
252
|
+
outcome chip.
|
|
253
|
+
- **Rows.** Grouped by recorded request id on a shared rail. Each shows a
|
|
254
|
+
status dot, time, caller (a person by label or id with initials, an agent
|
|
255
|
+
by name with its mark, anything else by kind), connector monogram and tool
|
|
256
|
+
address, a write tag, the failure reason, and duration and size. Opening a
|
|
257
|
+
row lists what was recorded: result, how it ran, classification, exact
|
|
258
|
+
duration and size, caller, stable caller id, request id, client, and
|
|
259
|
+
connecta version. Unrecorded fields are left out. Catalog changes are rows
|
|
260
|
+
with added, removed and changed counts.
|
|
261
|
+
- **Empty.** "No calls yet" with Refresh, or "No matches" with Clear filters.
|
|
262
|
+
|
|
263
|
+
### Navigation, gates and recovery
|
|
264
|
+
|
|
265
|
+
The top bar is one row: the mark, branding and deployment name, the section
|
|
266
|
+
links (Overview, Endpoints, Connectors, Activity, Tokens, Settings), then
|
|
267
|
+
Search (the command palette, also ⌘K or Ctrl+K), Appearance, and Account
|
|
268
|
+
(the signed-in account with Sign out or Change token). The mark is connecta's
|
|
269
|
+
drawn "C" only when no product name, owner or favicon is configured; with
|
|
270
|
+
`branding.favicon.svg` it is that SVG; otherwise there is none. The sign-in
|
|
271
|
+
gate shows the same mark above "Sign in". Below 820px the section links move
|
|
272
|
+
to a second row that scrolls sideways and keeps the current section in view,
|
|
273
|
+
and Search shrinks to its icon. A member's top bar has only branding and
|
|
274
|
+
Account. The command palette searches visible pages, connectors and tools,
|
|
275
|
+
opening connector results on Tools.
|
|
276
|
+
|
|
277
|
+
`GET /ui/api/config` is the browser's one gate: a 401 shows sign-in, the
|
|
278
|
+
private 404 shows "No access" with who to ask and Sign out or Change token,
|
|
279
|
+
and a 200 renders by `role`. `/ui/data`, connector details, activity and
|
|
280
|
+
tokens are requested only after the contract says `maintainer`, and each read
|
|
281
|
+
checks the role again when it is sent. Until a role is confirmed the page
|
|
282
|
+
shows its loading or error state and no navigation. Activity and Tokens keep
|
|
283
|
+
their own permission gates.
|
|
284
|
+
|
|
285
|
+
The store keeps the last confirmed role through a failed refresh: a
|
|
286
|
+
maintainer's page stays mounted, inert and dimmed, under one shell banner
|
|
287
|
+
("Couldn't load configuration" with Retry), and sends nothing maintainer-only
|
|
288
|
+
until a contract confirms the role again. Recovery closes the page's dialogs,
|
|
289
|
+
drawers, popovers and the command palette, and moves focus to Retry.
|
|
290
|
+
Credential and OAuth writes also wait for a contract that agrees with the
|
|
291
|
+
confirmed role: a maintainer's for a connector it shows, a member's for a
|
|
292
|
+
personal connector whose `manage` lists that action. Otherwise the write is
|
|
293
|
+
not sent and its row says so. An answer with a different role clears
|
|
294
|
+
everything read under the old one.
|
|
295
|
+
|
|
296
|
+
## Use the member page
|
|
297
|
+
|
|
298
|
+
With `operatorUi()` enabled, sign in at the deployment's public URL using
|
|
299
|
+
Clerk (Node) or Cloudflare Access (Workers). A person listed in a pool's
|
|
300
|
+
`members` can open the page without becoming a maintainer. The page, **Your
|
|
301
|
+
connections**, has no tabs; its heading shows the signed-in email when the
|
|
302
|
+
sign-in exposes one (Clerk's primary email), and its top bar shows branding and
|
|
303
|
+
an **Account** button with Sign out or Change token. It lists:
|
|
304
|
+
|
|
305
|
+
- **Your endpoints**: one card per admitted `/mcp/<pool>` URL with a copy button
|
|
306
|
+
and **Client setup**. For example, Bob in pool `team` copies
|
|
307
|
+
`https://connecta.example.com/mcp/team` into an MCP client and authenticates
|
|
308
|
+
as Bob.
|
|
309
|
+
- **Your accounts**: the personal connectors in their pools, each with a
|
|
310
|
+
monogram, tool count, one status badge in an aligned column, and only the
|
|
311
|
+
controls its `manage.actions` lists. A saved credential that no longer fits
|
|
312
|
+
or does not work adds a short note beside the tool count. An OAuth connector
|
|
313
|
+
offers Connect, Reconnect or Disconnect; Reconnect and Disconnect ask first.
|
|
314
|
+
A credential connector offers **Add credential** when only `save` is listed,
|
|
315
|
+
and Replace, Test and Clear once a value is stored; Clear asks first.
|
|
316
|
+
- **Shared with you**: shared connectors by name and tool count, without status.
|
|
317
|
+
|
|
318
|
+
Every browser path shows that same member page; it does not expose maintainer
|
|
319
|
+
connector-detail, activity, token, or settings pages, and it never sends a
|
|
320
|
+
maintainer request. After an action, and when the tab regains focus while an
|
|
321
|
+
authorization it started is still outstanding (up to ten minutes), it re-reads
|
|
322
|
+
`GET /ui/api/config`. Each action is checked against the current `manage`
|
|
323
|
+
again immediately before it is sent, and a refresh that drops an action closes
|
|
324
|
+
its open confirmation or form. If a refresh fails or misses its deadline, the
|
|
325
|
+
page shows its own error with Retry and moves focus to its heading; members
|
|
326
|
+
never see the maintainer recovery banner.
|
|
327
|
+
|
|
328
|
+
The page reads `GET /ui/api/config`: 200 with `role: "member"` confirms
|
|
329
|
+
membership; 401 means sign in; a private 404 means the signed-in person has
|
|
330
|
+
no maintainer role or human pool membership. A `cta_` agent token gets 401
|
|
331
|
+
and cannot sign in to this page. Use the agent's `/agent/<pool>` endpoint
|
|
332
|
+
for machine access instead.
|
|
333
|
+
|
|
334
|
+
Personal OAuth can also start from the person's `/mcp/<pool>` connection with
|
|
335
|
+
`authorize_connector`, finishing its signed browser link. Trusted clients that manage personal credentials use only the actions listed
|
|
336
|
+
in the connector's `manage` field; the API contract below describes their
|
|
337
|
+
routes and preconditions. Shared credentials always require a maintainer.
|
|
37
338
|
|
|
38
339
|
## Operator data contract
|
|
39
340
|
|
|
40
341
|
`GET /ui/api/config`, owned by `operatorUi()`, returns `OperatorUiContract`
|
|
41
|
-
from
|
|
42
|
-
|
|
43
|
-
`
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
`
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
`
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
342
|
+
(`OperatorUiContractV2`) from `@zackbart/connecta/ui`, `schemaVersion: 2`.
|
|
343
|
+
Its declarations ship in `dist/operator-ui/contract.d.ts` in the installed package. Schema
|
|
344
|
+
version 1, `hasGrant`, `you.grants`, and `you.permissions` were removed;
|
|
345
|
+
v2 keeps `you.interactive` to describe whether the session is interactive. It is the page's
|
|
346
|
+
only gate: a signed-out caller gets the auth provider's 401 challenge, and a
|
|
347
|
+
`cta_` agent token the machine-only 401 Bearer challenge every human route
|
|
348
|
+
gives it; a maintainer, or a person listed in a pool's `members`, gets 200
|
|
349
|
+
with `role` `"maintainer"` or `"member"`; anyone else gets the private JSON 404
|
|
350
|
+
`{ "error": "not found" }`. An open deployment's anonymous caller gets
|
|
351
|
+
`role: "maintainer"` but has no principal: activity is `"forbidden"`, the
|
|
352
|
+
activity and access-token routes answer 404, and owners are `null`. Every response is private, `no-store` JSON, and only GET is
|
|
353
|
+
allowed. One shape serves both roles; a field a role does not receive is
|
|
354
|
+
`null` or empty, never omitted.
|
|
355
|
+
|
|
356
|
+
The maintainer view carries:
|
|
357
|
+
|
|
358
|
+
- `config`, the construction-time `describeConfig()` snapshot, including
|
|
359
|
+
`maintainers` and each pool's `members`, and `configSources`, which labels
|
|
360
|
+
each serialized leaf as `default` or `config` from option presence rather
|
|
361
|
+
than equality with the default. Factory descriptions carry relative
|
|
362
|
+
`optionSources` paths so resolved module and transport defaults retain their
|
|
363
|
+
provenance. Paths use connector ids and pool names and are filtered after
|
|
364
|
+
disclosure; hidden values leave no provenance keys. Neither contains source
|
|
365
|
+
code or credential material.
|
|
366
|
+
- `root`: plain `/mcp`, its `readOnly`, and its `maintainers`, people only.
|
|
367
|
+
- `pools`: every declared pool with `humanPath` (`/mcp/<name>`), `agentPath`
|
|
368
|
+
(`/agent/<name>`), `readOnly`, `owner` (the Workspace address its agents act
|
|
369
|
+
as), its declared `tools` (never intersected; no `requireReadOnly` is ever
|
|
370
|
+
true), and its `members`, agents as `{ kind: "agent", name }`. Every listed
|
|
371
|
+
person carries a `label` from the same directory lookup activity actor
|
|
372
|
+
labels use, on an interactive read only, and `null` without a directory
|
|
373
|
+
(Cloudflare Access) or an entry. An open deployment's anonymous maintainer
|
|
374
|
+
reads every `owner` as `null`.
|
|
375
|
+
- `agents`: every agent declared in code, with its pools, its token slot
|
|
376
|
+
(`state`, `issuedAt`, `revokedAt`, `revision`) exactly as
|
|
377
|
+
`GET /ui/access-tokens` lists it, and `lastSeenAt`, the newest visible
|
|
378
|
+
activity row recorded for that agent, or `null` when activity is off or
|
|
379
|
+
none is visible. A slot read that fails answers 503 rather than drop agents.
|
|
380
|
+
- `matrix`: a cell per connector for plain `/mcp` (`pool: null`) and for each
|
|
381
|
+
pool that serves it, with that endpoint's tool names or `"all"` and
|
|
382
|
+
`runsAs`. A Workspace connector with a subject mapping is
|
|
383
|
+
`{ kind: "workspace", humans: "self", agents }`, `agents` being the pool's
|
|
384
|
+
owner, or `null` on plain `/mcp` and in an ownerless pool, where agents do
|
|
385
|
+
not see the connector at all; a fixed subject is
|
|
386
|
+
`{ kind: "workspaceFixed", subject }`. A personal connector counts the
|
|
387
|
+
endpoint's people (the maintainers on plain `/mcp`) and how many have
|
|
388
|
+
connected in their own partition: a stored credential of the declared shape,
|
|
389
|
+
or an `ok` status. A shared connector names its `source`: `vault` (a saved
|
|
390
|
+
slot, with `savedAt`), `missing` (a slot with nothing saved, or shared OAuth
|
|
391
|
+
reporting it needs authorizing), `oauth` (a shared grant; grants carry no
|
|
392
|
+
saved time, so `savedAt` is `null`), `unauthenticated` (a remote MCP server
|
|
393
|
+
that declares no auth), or `config` (everything else, held by deployment
|
|
394
|
+
code).
|
|
395
|
+
- `live.connectors`: status and problem codes, complete registry tools with
|
|
396
|
+
their final read/write classification, catalog age in milliseconds, and
|
|
397
|
+
last-call time/outcome. Catalog descriptions and schemas are allowed;
|
|
398
|
+
grammar-failing names and addresses become `<withheld>`.
|
|
399
|
+
`auth.registrationPath` reports the selected downstream OAuth client
|
|
400
|
+
mechanism when known. Static and unobserved catalogs have a null age;
|
|
401
|
+
persisted catalogs retain their original fetch time.
|
|
402
|
+
- `live.activity`: available, unconfigured, forbidden, or unavailable history.
|
|
403
|
+
Last-call and last-seen lookups need the activity permission and read gate,
|
|
404
|
+
scan up to 1,000 recent rows, filter connector/tool grants, restrict personal
|
|
405
|
+
connectors to the caller's activity identity, and copy a validated timestamp
|
|
406
|
+
and outcome only. A null means unknown or absent in that window.
|
|
407
|
+
- `connectors: []`.
|
|
408
|
+
|
|
409
|
+
The member view is exactly that member's projection: `config`,
|
|
410
|
+
`configSources` and `root` are `null`, `live.connectors`, `agents` and
|
|
411
|
+
`matrix` are empty, and `live.activity` is `"forbidden"`. `pools` lists only
|
|
412
|
+
their pools, each with `owner: null` and `members: []`. `connectors` lists
|
|
413
|
+
each connector in those pools with its title, the member's pools that serve
|
|
414
|
+
it, its auth scope, the tools those pools grant with their classification,
|
|
415
|
+
`connection` (their own partition's state and problem code for a personal
|
|
416
|
+
connector, `null` for a shared one) and `manage`. `manage` is derived on the
|
|
417
|
+
server. A shared connector is always `{ kind: "none" }`. For a personal one,
|
|
418
|
+
the member's own permission (an interactive person in a pool that holds it)
|
|
419
|
+
gates every action. A credential slot offers `save` when a vault is
|
|
420
|
+
configured, `clear` when a value is stored in the member's partition, and
|
|
421
|
+
`test` when one is stored in the declared shape and the connector has the
|
|
422
|
+
matching test hook; an unreadable partition offers `save` alone, so the page
|
|
423
|
+
reads stored-ness from `actions`. OAuth offers `connect` and `restart` when
|
|
424
|
+
the connector has `startAuth`, `finishAuth` and `verifyState` and the
|
|
425
|
+
deployment can sign the connect hand-off, and `disconnect` when it has
|
|
426
|
+
`disconnectAuth`. No actions is `{ kind: "none" }`. The view carries no shared
|
|
427
|
+
credential status, catalog ages, last calls, other members, agents, owners or
|
|
428
|
+
activity. Status prose, error text, credential values or suffixes, arguments,
|
|
429
|
+
results, and code are excluded from both views. Probes run with bounded
|
|
430
|
+
concurrency and the configured probe deadline, and release their scopes. Every
|
|
431
|
+
vault, token-slot and activity read the view makes runs under that same
|
|
432
|
+
deadline and the request's signal, so a stalled store never hangs the page: it
|
|
433
|
+
degrades fail-closed, to `save` alone for a member's credential, `missing` or
|
|
434
|
+
an unconnected person in a matrix cell, unavailable activity, and a 503 for
|
|
435
|
+
the token slots.
|
|
436
|
+
|
|
437
|
+
`/ui/data`, `/ui/connectors/:id`, activity reads and access-token routes
|
|
438
|
+
require a maintainer and give anyone else the same private 404. The connector
|
|
439
|
+
auth routes, `/ui/oauth/<id>` and `/ui/credentials/<id>`, also admit a pool
|
|
440
|
+
member for a personal connector in one of their pools, in their own
|
|
441
|
+
partition. `/ui/oauth/<id>` gates each verb on its own hooks: a connect needs
|
|
442
|
+
`startAuth`, `finishAuth` and `verifyState`, a disconnect only
|
|
443
|
+
`disconnectAuth`. `/ui/credentials/<id>` refuses to clear an empty partition,
|
|
444
|
+
the caller's own for a personal connector or the shared slot, with 409
|
|
445
|
+
`{ "error": "no credential is stored to clear", "problem": "credential_required" }`,
|
|
446
|
+
as its test route refuses to test one; a value that cannot be read can still be
|
|
447
|
+
cleared. The routes thus accept what `manage` lists, with one recovery
|
|
448
|
+
exception: clearing a stored value that cannot be read is accepted although
|
|
449
|
+
`manage` lists only `save` in that state. Public HTML shells and static assets carry no catalog data.
|
|
450
|
+
Access-token management also requires an interactive session.
|
|
451
|
+
|
|
452
|
+
`GET /ui/api/config?connector=<id>` narrows the same contract to one connector
|
|
453
|
+
before status and catalog probes. For a maintainer, config, provenance, live
|
|
454
|
+
rows and matrix cells contain only that connector's facts; for a member,
|
|
455
|
+
`connectors` does. Pools keep their declared tools. An id outside the
|
|
456
|
+
caller's view receives a no-store 404. The selector never widens access.
|
|
80
457
|
|
|
81
458
|
`connecta doctor --config` fetches this authenticated contract and prints only
|
|
82
|
-
`config` as indented JSON
|
|
83
|
-
|
|
84
|
-
|
|
459
|
+
a maintainer's `config` as indented JSON; a member's view has none, and doctor
|
|
460
|
+
says the snapshot is for maintainers. It requires the UI module and the
|
|
461
|
+
existing doctor authentication environment variables; it runs no diagnostic
|
|
462
|
+
program, follows no redirects, and prints no raw HTTP failure body.
|
|
85
463
|
|
|
86
464
|
The operator shell uses React, TanStack Router/Query/Table, Radix, cmdk and
|
|
87
|
-
Tailwind v4.
|
|
465
|
+
Tailwind v4. Hanken Grotesk, JetBrains Mono, CSS, JavaScript and dependency notices are hashed assets
|
|
88
466
|
under `/ui/assets/*`, served identically with immutable cache headers on Node
|
|
89
467
|
and Workers. HTML contains only mount points and escaped inert configuration;
|
|
90
|
-
it remains uncached.
|
|
468
|
+
it remains uncached. Ahead of the stylesheet, every operator page (sign-in
|
|
469
|
+
gate, member page, maintainer pages) loads a blocking hashed scheme initializer
|
|
470
|
+
of under 200 bytes, `src/operator-ui/app/scheme-init.ts`, with a plain
|
|
471
|
+
`<script src>` and no inline code. When the server set no `html[data-scheme]`
|
|
472
|
+
from a pinned `branding.theme.colorScheme`, it copies a saved `light` or `dark`
|
|
473
|
+
from local storage key `connecta:scheme` onto that attribute, ignoring storage
|
|
474
|
+
errors, so the first frame already has the viewer's scheme. The deferred bundle
|
|
475
|
+
learns of a pin from `schemePinned` in the inert configuration; Appearance
|
|
476
|
+
writes the key and moves the attribute live, and is read-only under a pin. Every
|
|
477
|
+
local and session storage access in the UI tolerates storage that throws, as in
|
|
478
|
+
private browsing: a read finds nothing stored and a write keeps nothing, so a
|
|
479
|
+
bearer token is not remembered there. `generated.ts` is ignored and generated before build and
|
|
91
480
|
test; `check:operator-ui` detects stale assets and shared page styles. The UI
|
|
92
481
|
stays behind `./ui`, outside the root import graph. The identity-fenced store
|
|
93
|
-
owns authenticated reads and existing mutations.
|
|
94
|
-
|
|
482
|
+
owns authenticated reads and existing mutations. An Access-only shell selects
|
|
483
|
+
Access even when the HTML request has no trusted context; only authenticated
|
|
484
|
+
API responses establish the session. A gated Access session offers Retry.
|
|
485
|
+
Focus, visibility, and timer-driven recovery share one admission-read schedule
|
|
486
|
+
with at least two seconds between passive attempts. An admission read takes
|
|
487
|
+
the contract first and, for a maintainer, then `/ui/data` and the connector
|
|
488
|
+
details, which reuse that contract rather than read it again. An in-flight
|
|
489
|
+
passive attempt coalesces returns until its admission read finishes, so slow
|
|
490
|
+
successful reads can publish. Each admission read shares one 15-second
|
|
491
|
+
deadline, including token acquisition, fetches and response bodies. This is an admission deadline, not a request
|
|
492
|
+
lifetime limit: it releases the recovery guard and exposes Retry without aborting
|
|
493
|
+
the pending read or invalidating its identity/revision fence. A late healthy
|
|
494
|
+
response still publishes if that cycle is current. Passive timers and returns
|
|
495
|
+
coalesce onto the pending cycle, including after its deadline; they never start
|
|
496
|
+
duplicate summary, token, config, detail or body reads. The passive retry schedule
|
|
497
|
+
stays bounded and does not reset its budget on a deadline. Retry remains available
|
|
498
|
+
during recovery configuration loading and supersedes and aborts the old cycle;
|
|
499
|
+
identity changes, navigation and connector-page unmount also cancel it. Navigation
|
|
500
|
+
that cancels pending data schedules a bounded reread for the destination. Failed reads retry after
|
|
501
|
+
2, 2, 4, and 8 seconds. Refusals preserve the throttle and retry budget. After
|
|
502
|
+
those four automatic retries, a focus return can request one more read after
|
|
503
|
+
the eight-second backoff, without replenishing the automatic budget. Retry
|
|
504
|
+
resets the budget with a 150 ms click debounce. Successful reads and explicit
|
|
505
|
+
identity transitions also reset recovery. Identity changes
|
|
506
|
+
cancel pending retries and fence out responses from the previous identity.
|
|
507
|
+
Queued focus callbacks carry the same identity fence. Explicit sign-out
|
|
508
|
+
suppresses passive reads until an intentional sign-in or a new Clerk session.
|
|
509
|
+
|
|
510
|
+
Catalog and connector auth details share one revisioned refresh cycle. Each
|
|
511
|
+
completed connector publishes its catalog facts and auth controls together,
|
|
512
|
+
while a slow provider leaves other rows usable.
|
|
513
|
+
Catalog refresh, connector refresh, and mutation follow-up reads update both
|
|
514
|
+
consumers together. A later refresh or mutation invalidates an older cycle's publication fence
|
|
515
|
+
without aborting its read, and a failed contract read clears its old snapshot;
|
|
516
|
+
the next refresh then reads the contract before any connector detail. After an explicit OAuth
|
|
517
|
+
start, visible tabs poll only that connector's read-only catalog and auth facts
|
|
518
|
+
every two seconds for up to 30 seconds. The scoped result replaces only that
|
|
519
|
+
connector's matching live row and auth controls. Success, a failed read or status,
|
|
520
|
+
disconnect, navigation away from the connector, unmount, or identity reset ends
|
|
521
|
+
polling and aborts its in-flight reads. The deadline also aborts a stalled read.
|
|
522
|
+
A later focus return can request another status read. Recovery never starts OAuth
|
|
523
|
+
or replays a mutation.
|
|
524
|
+
Unreadable credential metadata uses `configured: null`, including named fields,
|
|
525
|
+
and renders as unavailable with a retry prompt. It does not claim that the slot
|
|
526
|
+
is empty. Overview, Endpoints, Connectors, connector
|
|
527
|
+
detail, Settings, and the member page consume the typed contract; Activity opens
|
|
528
|
+
only to a maintainer whose contract reports readable history. Connector detail
|
|
529
|
+
reads auth permissions from its `/ui/data` connector. Activity retains
|
|
95
530
|
its authenticated data routes. Connector detail tabs live
|
|
96
531
|
in the URL hash; Activity filters live in the query string and apply to loaded
|
|
97
|
-
history. Both `/ui/activity` and `/ui/api/activity` require
|
|
98
|
-
pass the optional activity `readGate`.
|
|
99
|
-
|
|
532
|
+
history. Both `/ui/activity` and `/ui/api/activity` require a maintainer
|
|
533
|
+
principal, interactive or not, and pass the optional activity `readGate`.
|
|
534
|
+
Interactive and machine maintainer reads share the same history disclosure rules.
|
|
100
535
|
Connector/tool grants and grants for the recorded pool filter each event. Shared
|
|
101
536
|
connector history can include other principals' events, with recorded request
|
|
102
537
|
IDs, validated client name/version and package version, and actor kind, ID and
|
|
@@ -118,12 +553,32 @@ id and typed actor when available, otherwise a fresh id and system actor. No
|
|
|
118
553
|
names, descriptions or schemas enter the event. Private catalog changes require
|
|
119
554
|
a matching principal owner even when the connector uses shared auth. Empty credential declarations
|
|
120
555
|
report `credential_required` before running a connector status or catalog probe.
|
|
121
|
-
The Access adapter reports inbound provider kinds, admitted pools, grants, read-only endpoints
|
|
122
|
-
and endpoint setup; token controls retain their existing permission gate.
|
|
123
|
-
Configuration remains in deployment code. The UI mutates only credentials,
|
|
124
|
-
OAuth connections and client tokens through the existing routes.
|
|
125
556
|
|
|
126
|
-
##
|
|
557
|
+
## Contributor reference
|
|
558
|
+
|
|
559
|
+
### Source and tests
|
|
560
|
+
|
|
561
|
+
The browser store reads only v2 and checks `role` before reading a
|
|
562
|
+
maintainer-only field. `test/fixtures/operator-contract-v2.ts` holds
|
|
563
|
+
maintainer and member fixtures, and `test/helpers/operator-member-view.ts`
|
|
564
|
+
checks a member response's exact shape and compares its values with a
|
|
565
|
+
projection built from config, membership, the member's own partition status,
|
|
566
|
+
and each personal connector's exact `manage`;
|
|
567
|
+
`test/operator-contract-server.test.ts` runs it against real responses.
|
|
568
|
+
|
|
569
|
+
The Overview's map and attention rows are pure functions of the contract in
|
|
570
|
+
[connection-map.ts](https://github.com/zackbart/connecta/blob/main/src/operator-ui/connection-map.ts)
|
|
571
|
+
and [overview.ts](https://github.com/zackbart/connecta/blob/main/src/operator-ui/overview.ts),
|
|
572
|
+
covered by `test/operator-connection-map.test.ts` and
|
|
573
|
+
`test/operator-overview.test.ts`; `src/operator-ui/styles/overview.css` holds
|
|
574
|
+
the page's styles.
|
|
575
|
+
|
|
576
|
+
`src/operator-ui/config-summary.ts` maps the snapshot and its provenance to
|
|
577
|
+
those tiles: one table of limit labels, the formatters, and the walk that turns
|
|
578
|
+
an unmapped key into an Other tile. `app/config-tiles.tsx` draws them, and
|
|
579
|
+
`test/operator-config-summary.test.ts` checks formatting, provenance, unknown
|
|
580
|
+
keys, an empty deployment, and that a real deployment's snapshot leaves no key
|
|
581
|
+
unmapped.
|
|
127
582
|
|
|
128
583
|
The contract type is [contract.ts](https://github.com/zackbart/connecta/blob/main/src/operator-ui/contract.ts).
|
|
129
584
|
[UI routes](https://github.com/zackbart/connecta/blob/main/src/routes/ui.ts) and
|