@zackbart/connecta 0.4.1 → 0.6.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 +527 -0
- package/README.md +83 -7
- package/SECURITY.md +10 -6
- package/dist/activity.d.ts +8 -0
- package/dist/activity.d.ts.map +1 -1
- package/dist/activity.js +1 -0
- package/dist/activity.js.map +1 -1
- package/dist/auth/bearer.d.ts +10 -3
- package/dist/auth/bearer.d.ts.map +1 -1
- package/dist/auth/bearer.js +21 -0
- package/dist/auth/bearer.js.map +1 -1
- package/dist/auth/clerk.d.ts +26 -1
- package/dist/auth/clerk.d.ts.map +1 -1
- package/dist/auth/clerk.js +161 -4
- package/dist/auth/clerk.js.map +1 -1
- package/dist/connectors/api.d.ts +13 -0
- package/dist/connectors/api.d.ts.map +1 -1
- package/dist/connectors/api.js +2 -0
- package/dist/connectors/api.js.map +1 -1
- package/dist/connectors/remote-mcp.d.ts +13 -0
- package/dist/connectors/remote-mcp.d.ts.map +1 -1
- package/dist/connectors/remote-mcp.js +10 -0
- package/dist/connectors/remote-mcp.js.map +1 -1
- package/dist/credential-health.d.ts +212 -0
- package/dist/credential-health.d.ts.map +1 -0
- package/dist/credential-health.js +535 -0
- package/dist/credential-health.js.map +1 -0
- package/dist/execute.d.ts +4 -4
- package/dist/execute.d.ts.map +1 -1
- package/dist/execute.js +16 -4
- package/dist/execute.js.map +1 -1
- package/dist/index.d.ts +77 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +112 -2
- package/dist/index.js.map +1 -1
- package/dist/meta-tools.d.ts +76 -7
- package/dist/meta-tools.d.ts.map +1 -1
- package/dist/meta-tools.js +328 -98
- package/dist/meta-tools.js.map +1 -1
- package/dist/registry.d.ts +245 -2
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +377 -27
- package/dist/registry.js.map +1 -1
- package/dist/server.d.ts +7 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +342 -27
- package/dist/server.js.map +1 -1
- package/dist/skills.d.ts +53 -2
- package/dist/skills.d.ts.map +1 -1
- package/dist/skills.js +162 -2
- package/dist/skills.js.map +1 -1
- package/dist/timeout.d.ts +16 -0
- package/dist/timeout.d.ts.map +1 -0
- package/dist/timeout.js +38 -0
- package/dist/timeout.js.map +1 -0
- package/dist/toolkits.d.ts +138 -0
- package/dist/toolkits.d.ts.map +1 -0
- package/dist/toolkits.js +319 -0
- package/dist/toolkits.js.map +1 -0
- package/dist/types.d.ts +90 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/ui.d.ts +63 -0
- package/dist/ui.d.ts.map +1 -1
- package/dist/ui.js +176 -11
- package/dist/ui.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +5 -2
- package/src/activity.ts +9 -0
- package/src/auth/bearer.ts +35 -1
- package/src/auth/clerk.ts +202 -5
- package/src/connectors/api.ts +15 -0
- package/src/connectors/remote-mcp.ts +24 -0
- package/src/credential-health.ts +736 -0
- package/src/execute.ts +32 -8
- package/src/index.ts +226 -2
- package/src/meta-tools.ts +397 -119
- package/src/registry.ts +540 -29
- package/src/server.ts +431 -25
- package/src/skills.ts +185 -2
- package/src/timeout.ts +49 -0
- package/src/toolkits.ts +450 -0
- package/src/types.ts +96 -2
- package/src/ui.ts +190 -11
- package/src/version.ts +1 -1
package/README.md
CHANGED
|
@@ -43,14 +43,14 @@ A tool **address** is `<connectorId>.<toolName>` (e.g. `notion.search`).
|
|
|
43
43
|
|
|
44
44
|
| Tool | Input | Returns |
|
|
45
45
|
| --- | --- | --- |
|
|
46
|
-
| `list_connectors` | `{ probe? }` | live (`probe: true`, default) or cached health, tool count,
|
|
47
|
-
| `skills` | `{ name? }` | lists or fetches the concise `usage` guide for choosing among the meta-tools |
|
|
46
|
+
| `list_connectors` | `{ probe? }` | live (`probe: true`, default) or cached health, tool count, recent real-call observations, and the last proactive credential check |
|
|
47
|
+
| `skills` | `{ name? }` | lists or fetches the concise `usage` guide for choosing among the meta-tools, plus any operator-authored per-connector guide (`connector:<connectorId>`) |
|
|
48
48
|
| `search_tools` | `{ query?, connector?, limit?, offset?, fullDescriptions?, includeSchemas? }` | ranked, paginated matches; optionally includes compact/raw schemas to remove a round trip |
|
|
49
49
|
| `describe_tools` | `{ addresses[], format?, fullDescriptions? }` | names, descriptions, input/output schemas, and behavior annotations |
|
|
50
50
|
| `call_tool` | `{ address, args?, fields?, resultMode?, timeoutMs?, maxRetries?, diagnostics? }` | invokes only tools explicitly annotated `readOnlyHint: true` |
|
|
51
51
|
| `call_destructive_tool` | same as `call_tool` | invokes unannotated, write-capable, or destructive tools through a host-visible approval boundary |
|
|
52
52
|
| `authorize_connector` | `{ connector, force? }` | starts (or with `force`, restarts) the downstream OAuth flow; returns the `authorizationUrl` to open |
|
|
53
|
-
| `get_result` | `{ id, offset?, maxBytes? }` | a byte-slice page of a truncated result — `{ text, offset, nextOffset?, totalBytes }` |
|
|
53
|
+
| `get_result` | `{ id, offset?, maxBytes? }` | a byte-slice page of a truncated result — `{ text, offset, nextOffset?, totalBytes }`; `maxBytes` is a whole number of bytes >= 1 and `offset` a whole number of bytes >= 0, aligned back to a character boundary and echoed as the `offset` served |
|
|
54
54
|
| `batch_call` | `{ calls, resultMode?, timeoutMs?, maxRetries? }` | 1–10 parallel calls sharing request-scoped clients, with attempts/timing/errors |
|
|
55
55
|
| `execute_code` *(optional)* | `{ code }` | result + logs of bounded async JS orchestration over explicitly read-only tools; registered only when an `executor` is configured |
|
|
56
56
|
|
|
@@ -81,6 +81,7 @@ const build = (env: Env) =>
|
|
|
81
81
|
publishableKey: env.CLERK_PUBLISHABLE_KEY,
|
|
82
82
|
secretKey: env.CLERK_SECRET_KEY,
|
|
83
83
|
publicUrl: env.PUBLIC_URL,
|
|
84
|
+
// allowedDomains: ["acme.com"], // only your org's verified emails
|
|
84
85
|
}),
|
|
85
86
|
],
|
|
86
87
|
connectors: [
|
|
@@ -141,6 +142,51 @@ listen(connecta, 8787); // http://localhost:8787/mcp
|
|
|
141
142
|
Example: [`examples/node/`](./examples/node/). Docker (single-service compose
|
|
142
143
|
stack): [`examples/docker/`](./examples/docker/).
|
|
143
144
|
|
|
145
|
+
## Toolkits — one deployment, many teams
|
|
146
|
+
|
|
147
|
+
A deployment belongs to an org. Optional **toolkits** give each group of team
|
|
148
|
+
members its own scoped view of the same registry — bound to that group's
|
|
149
|
+
credential — so different teams no longer need separate deployments:
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
createConnecta({
|
|
153
|
+
connectors: [zendesk, notion, gmail],
|
|
154
|
+
auth: [
|
|
155
|
+
// Each team's credential is bound to that team's view.
|
|
156
|
+
bearerToken(env.SUPPORT_TOKEN, { subjectId: "support", toolkits: ["support"] }),
|
|
157
|
+
bearerToken(env.EXEC_TOKEN, { subjectId: "exec", toolkits: ["exec"] }),
|
|
158
|
+
// The operator's: every view, plus /ui — declared, not left unbound.
|
|
159
|
+
bearerToken(env.OPS_TOKEN, {
|
|
160
|
+
subjectId: "ops",
|
|
161
|
+
toolkits: ["support", "exec"],
|
|
162
|
+
unscoped: true,
|
|
163
|
+
}),
|
|
164
|
+
],
|
|
165
|
+
toolkits: {
|
|
166
|
+
support: { connectors: ["zendesk", "notion"] },
|
|
167
|
+
exec: {
|
|
168
|
+
connectors: ["zendesk", "notion", "gmail"],
|
|
169
|
+
excludeTools: ["gmail.send_message"], // finer grain than a connector id
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
});
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
A client picks one at connect time: `https://…/mcp?toolkit=support`. Inside a
|
|
176
|
+
scoped session **every** meta-tool — search, describe, call, batch, skills,
|
|
177
|
+
authorize, `get_result`, and `execute_code` host calls — behaves as if
|
|
178
|
+
out-of-scope connectors and tools do not exist, and an out-of-scope address
|
|
179
|
+
fails identically to a nonexistent one. No `?toolkit=` ⇒ the full registry, as
|
|
180
|
+
before; an unknown name is an error, never a silent fallback.
|
|
181
|
+
|
|
182
|
+
`toolkits: [...]` on an auth adapter **binds** a credential to its views: the
|
|
183
|
+
support token cannot open `?toolkit=exec`, cannot connect unscoped (unless it also
|
|
184
|
+
passes `unscoped: true`), and cannot read the deployment-wide operator surfaces.
|
|
185
|
+
Refusal is a flat 403 at connect time, identical whether the toolkit is another
|
|
186
|
+
team's or does not exist at all — a mapping, not a policy engine. Leave `toolkits`
|
|
187
|
+
off and that credential keeps today's self-service selection. Details:
|
|
188
|
+
[docs §16](./docs/documentation.md#16-toolkits-scoped-views).
|
|
189
|
+
|
|
144
190
|
## Code mode
|
|
145
191
|
|
|
146
192
|
With an `executor` configured, the model can write an async function instead of
|
|
@@ -210,6 +256,35 @@ Connecta does not bundle service-specific HTTP API connectors. Package consumers
|
|
|
210
256
|
define them with `api()` (or implement `Connector` directly), keeping endpoint,
|
|
211
257
|
credential, and tool choices in the consuming project.
|
|
212
258
|
|
|
259
|
+
## Credential health
|
|
260
|
+
|
|
261
|
+
Stored credentials are checked for liveness *before* an agent's call trips over a
|
|
262
|
+
dead one. Connecta asks each connector holding a credential it stores — a vault
|
|
263
|
+
credential, or a downstream-OAuth grant — whether that credential still works,
|
|
264
|
+
using the connector's own `testCredential(s)` or `status()` hook. No downstream
|
|
265
|
+
tool is ever called. A check that finds the credential *rejected* flips the
|
|
266
|
+
connector to `auth_required` in `list_connectors({ probe: false })` and on
|
|
267
|
+
`/ui`, with the URL to open; a later success (or re-authorizing) flips it back
|
|
268
|
+
with no restart. A check that merely failed to complete — a timeout, a 502 from
|
|
269
|
+
the status endpoint — is reported but never decides the status: it learned
|
|
270
|
+
nothing about the credential.
|
|
271
|
+
|
|
272
|
+
Checks are triggered two ways and share one rate limit — at most one per
|
|
273
|
+
connector per 15 minutes by default, four in flight, 30 s each:
|
|
274
|
+
|
|
275
|
+
```ts
|
|
276
|
+
// 1. Opportunistically, on authenticated traffic connecta already serves.
|
|
277
|
+
// On by default; nothing to wire. Disable with:
|
|
278
|
+
createConnecta({ connectors, credentialHealth: { onRequest: false } });
|
|
279
|
+
|
|
280
|
+
// 2. On a schedule you own — the core starts no timers, so this works the same
|
|
281
|
+
// on Workers (cron trigger) and Node.
|
|
282
|
+
async scheduled(_c, env, ctx) { ctx.waitUntil(build(env).checkCredentials()); }
|
|
283
|
+
setInterval(() => void connecta.checkCredentials(), 15 * 60_000).unref();
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Details: [docs §17](./docs/documentation.md#17-credential-health-proactive-liveness-checks).
|
|
287
|
+
|
|
213
288
|
## Payload-free tool activity
|
|
214
289
|
|
|
215
290
|
Connecta can record which resolved downstream tools were actually invoked
|
|
@@ -246,7 +321,8 @@ a complete D1 implementation with keyset paging and a retention pass.
|
|
|
246
321
|
|
|
247
322
|
## Operator dashboard
|
|
248
323
|
|
|
249
|
-
`GET /ui` is a read-only dashboard with no build step: connector health
|
|
324
|
+
`GET /ui` is a read-only dashboard with no build step: connector health and the
|
|
325
|
+
last credential check, tool
|
|
250
326
|
counts and descriptions with a client-side filter, downstream authorization
|
|
251
327
|
links, the credential controls above, and an Activity tab when an activity store
|
|
252
328
|
is configured. The shell is open because it carries no data; everything it shows
|
|
@@ -262,8 +338,8 @@ neutral Connecta default. Nothing about the operator is baked into the package.
|
|
|
262
338
|
## Learn more
|
|
263
339
|
|
|
264
340
|
- **[`docs/documentation.md`](./docs/documentation.md)** — how everything works: architecture,
|
|
265
|
-
the meta-tools, connectors, inbound auth, downstream
|
|
266
|
-
(Node / Workers / Docker), Clerk setup, testing,
|
|
267
|
-
the status UI,
|
|
341
|
+
the meta-tools, connectors and their usage guides, inbound auth, downstream
|
|
342
|
+
OAuth, storage, running it (Node / Workers / Docker), Clerk setup, testing,
|
|
343
|
+
troubleshooting, code mode, the status UI, activity history, and toolkits.
|
|
268
344
|
- **[`docs/design.md`](./docs/design.md)** — why it's built this way, and the non-goals.
|
|
269
345
|
- **[`CHANGELOG.md`](./CHANGELOG.md)** — what changed in each release.
|
package/SECURITY.md
CHANGED
|
@@ -12,14 +12,18 @@ sensitive payloads in a public issue.
|
|
|
12
12
|
|
|
13
13
|
## Dependency policy
|
|
14
14
|
|
|
15
|
-
CI blocks high and critical production dependency advisories.
|
|
16
|
-
are reviewed for reachability and recorded when an upstream package has
|
|
17
|
-
released a compatible fix.
|
|
15
|
+
CI blocks moderate, high, and critical production dependency advisories. Lower
|
|
16
|
+
findings are reviewed for reachability and recorded when an upstream package has
|
|
17
|
+
not yet released a compatible fix.
|
|
18
18
|
|
|
19
|
-
As of 0.4.0, one such finding remains open:
|
|
20
19
|
`@modelcontextprotocol/sdk@1.29.0` declares `@hono/node-server` 1.x, which is
|
|
21
20
|
covered by `GHSA-frvp-7c67-39w9`. The advisory affects Hono's Windows
|
|
22
21
|
`serve-static` implementation. Connecta does not import that adapter or serve
|
|
23
22
|
static files through Hono. npm's suggested fix downgrades the MCP SDK below
|
|
24
|
-
security behavior Connecta relies on, so the package
|
|
25
|
-
|
|
23
|
+
security behavior Connecta relies on, so the package instead pins
|
|
24
|
+
`@hono/node-server` to 2.x through an `overrides` entry and keeps SDK 1.29.0.
|
|
25
|
+
|
|
26
|
+
Because npm only applies `overrides` to the root project, that pin governs this
|
|
27
|
+
repository's own installs rather than trees built by consumers of the published
|
|
28
|
+
package. The override is removed once the SDK declares `@hono/node-server` ^2
|
|
29
|
+
upstream.
|
package/dist/activity.d.ts
CHANGED
|
@@ -34,6 +34,12 @@ export interface ToolCallActivityEvent {
|
|
|
34
34
|
serverName: string;
|
|
35
35
|
serverVersion: string;
|
|
36
36
|
deploymentId?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Name of the toolkit this connection selected with `?toolkit=`, when it
|
|
39
|
+
* selected one. Calls are recorded the same way with or without it; this only
|
|
40
|
+
* says which scoped view the call came through.
|
|
41
|
+
*/
|
|
42
|
+
toolkitId?: string;
|
|
37
43
|
}
|
|
38
44
|
export interface ActivityPage {
|
|
39
45
|
events: ToolCallActivityEvent[];
|
|
@@ -69,6 +75,8 @@ export interface ActivityRequestContext {
|
|
|
69
75
|
version: string;
|
|
70
76
|
};
|
|
71
77
|
deploymentId?: string;
|
|
78
|
+
/** Toolkit this connection is scoped to, when `?toolkit=` selected one. */
|
|
79
|
+
toolkitId?: string;
|
|
72
80
|
defer?: (promise: Promise<unknown>) => void;
|
|
73
81
|
logger: Logger;
|
|
74
82
|
}
|
package/dist/activity.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"activity.d.ts","sourceRoot":"","sources":["../src/activity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,MAAM,kBAAkB,GAC1B,WAAW,GACX,uBAAuB,GACvB,YAAY,GACZ,cAAc,CAAC;AAEnB,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;AAE9D;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC,aAAa,EAAE,CAAC,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,aAAa,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,OAAO,EAAE,eAAe,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"activity.d.ts","sourceRoot":"","sources":["../src/activity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,MAAM,kBAAkB,GAC1B,WAAW,GACX,uBAAuB,GACvB,YAAY,GACZ,cAAc,CAAC;AAEnB,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;AAE9D;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC,aAAa,EAAE,CAAC,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,aAAa,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,OAAO,EAAE,eAAe,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,qBAAqB,EAAE,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,iFAAiF;AACjF,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,KAAK,EAAE,qBAAqB,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5D;AAED,uEAAuE;AACvE,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,OAAO,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CAC1E;AAED,MAAM,WAAW,aAAc,SAAQ,YAAY;IACjD,IAAI,CAAC,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;CAC/B;AAED,iFAAiF;AACjF,qBAAa,0BAA2B,SAAQ,KAAK;IAC1C,IAAI,SAAgC;;CAK9C;AAED,MAAM,MAAM,gBAAgB,GAAG,CAC7B,KAAK,EAAE,aAAa,KACjB,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAEhC,gFAAgF;AAChF,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,EAAE,aAAa,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;IAC5C,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,kBAAkB,GAAG,IAAI,CACnC,qBAAqB,EACnB,aAAa,GACb,UAAU,GACV,SAAS,GACT,QAAQ,GACR,SAAS,GACT,YAAY,GACZ,UAAU,GACV,WAAW,CACd,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,sBAAsB,GAAG,SAAS,EAC3C,KAAK,EAAE,kBAAkB,GACxB,IAAI,CAmCN"}
|
package/dist/activity.js
CHANGED
|
@@ -32,6 +32,7 @@ export function recordToolActivity(context, input) {
|
|
|
32
32
|
...(context.deploymentId
|
|
33
33
|
? { deploymentId: context.deploymentId }
|
|
34
34
|
: {}),
|
|
35
|
+
...(context.toolkitId ? { toolkitId: context.toolkitId } : {}),
|
|
35
36
|
};
|
|
36
37
|
try {
|
|
37
38
|
const result = context.sink.record(event);
|
package/dist/activity.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"activity.js","sourceRoot":"","sources":["../src/activity.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"activity.js","sourceRoot":"","sources":["../src/activity.ts"],"names":[],"mappings":"AAuEA,iFAAiF;AACjF,MAAM,OAAO,0BAA2B,SAAQ,KAAK;IAC1C,IAAI,GAAG,4BAA4B,CAAC;IAE7C;QACE,KAAK,CAAC,yBAAyB,CAAC,CAAC;IACnC,CAAC;CACF;AA+BD;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAChC,OAA2C,EAC3C,KAAyB;IAEzB,IAAI,CAAC,OAAO;QAAE,OAAO;IACrB,MAAM,KAAK,GAA0B;QACnC,aAAa,EAAE,CAAC;QAChB,EAAE,EAAE,MAAM,CAAC,UAAU,EAAE;QACvB,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACpC,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QACrD,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACjD,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1D,UAAU,EAAE,OAAO,CAAC,UAAU,CAAC,IAAI;QACnC,aAAa,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO;QACzC,GAAG,CAAC,OAAO,CAAC,YAAY;YACtB,CAAC,CAAC,EAAE,YAAY,EAAE,OAAO,CAAC,YAAY,EAAE;YACxC,CAAC,CAAC,EAAE,CAAC;QACP,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC/D,CAAC;IACF,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC1C,IAAI,CAAC,MAAM,IAAI,OAAQ,MAA2B,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YACvE,OAAO;QACT,CAAC;QACD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YACtD,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,mCAAmC,EAAE,KAAK,CAAC,CAAC;QAClE,CAAC,CAAC,CAAC;QACH,IAAI,OAAO,CAAC,KAAK;YAAE,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,mCAAmC,EAAE,KAAK,CAAC,CAAC;IAClE,CAAC;AACH,CAAC"}
|
package/dist/auth/bearer.d.ts
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
|
+
import { type ToolkitBindingOptions } from "../toolkits.js";
|
|
1
2
|
import type { InboundAuth } from "../types.js";
|
|
3
|
+
export interface BearerTokenOptions extends ToolkitBindingOptions {
|
|
4
|
+
/** Stable identity for this credential, used on activity events. */
|
|
5
|
+
subjectId?: string;
|
|
6
|
+
}
|
|
2
7
|
/**
|
|
3
8
|
* Static bearer-token inbound auth. Constant-time compares the Bearer token
|
|
4
9
|
* against `secret`. Checked BEFORE the Clerk gate in the server; a mismatch
|
|
5
10
|
* falls through so a co-configured Clerk provider can still admit the request.
|
|
11
|
+
*
|
|
12
|
+
* `toolkits` binds the token to named toolkits (§16): one `bearerToken(...)` per
|
|
13
|
+
* team credential, each naming the view that team may open. Omit it and the
|
|
14
|
+
* token stays unbound — every declared toolkit plus the full registry.
|
|
6
15
|
*/
|
|
7
|
-
export declare function bearerToken(secret: string, options?:
|
|
8
|
-
subjectId?: string;
|
|
9
|
-
}): InboundAuth;
|
|
16
|
+
export declare function bearerToken(secret: string, options?: BearerTokenOptions): InboundAuth;
|
|
10
17
|
//# sourceMappingURL=bearer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bearer.d.ts","sourceRoot":"","sources":["../../src/auth/bearer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAc,WAAW,EAAE,MAAM,aAAa,CAAC;AAiB3D
|
|
1
|
+
{"version":3,"file":"bearer.d.ts","sourceRoot":"","sources":["../../src/auth/bearer.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAc,WAAW,EAAE,MAAM,aAAa,CAAC;AAiB3D,MAAM,WAAW,kBAAmB,SAAQ,qBAAqB;IAC/D,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,kBAAuB,GAC/B,WAAW,CAiDb"}
|
package/dist/auth/bearer.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resolveToolkitBinding, } from "../toolkits.js";
|
|
1
2
|
const encoder = new TextEncoder();
|
|
2
3
|
/** Constant-time byte comparison. Differing lengths still iterate to reduce leak. */
|
|
3
4
|
function timingSafeEqual(a, b) {
|
|
@@ -17,11 +18,31 @@ function timingSafeEqual(a, b) {
|
|
|
17
18
|
* Static bearer-token inbound auth. Constant-time compares the Bearer token
|
|
18
19
|
* against `secret`. Checked BEFORE the Clerk gate in the server; a mismatch
|
|
19
20
|
* falls through so a co-configured Clerk provider can still admit the request.
|
|
21
|
+
*
|
|
22
|
+
* `toolkits` binds the token to named toolkits (§16): one `bearerToken(...)` per
|
|
23
|
+
* team credential, each naming the view that team may open. Omit it and the
|
|
24
|
+
* token stays unbound — every declared toolkit plus the full registry.
|
|
20
25
|
*/
|
|
21
26
|
export function bearerToken(secret, options = {}) {
|
|
22
27
|
const secretBytes = encoder.encode(secret);
|
|
28
|
+
const toolkitBinding = resolveToolkitBinding(options.subjectId
|
|
29
|
+
? `bearerToken (subjectId "${options.subjectId}")`
|
|
30
|
+
: "bearerToken", options);
|
|
31
|
+
if (toolkitBinding && !options.subjectId) {
|
|
32
|
+
// A bound token stands for one team, and both surfaces that report on it —
|
|
33
|
+
// the 403 refusal log (§16) and activity events (§15) — can only say
|
|
34
|
+
// "bearer" without a subjectId. With several bound tokens that makes an
|
|
35
|
+
// operator unable to tell which credential was refused, or whose call
|
|
36
|
+
// succeeded. console.warn (as the Clerk adapter does) because an adapter is
|
|
37
|
+
// constructed before `createConnecta` has a logger to hand it.
|
|
38
|
+
console.warn("[connecta] bearerToken is bound to toolkits " +
|
|
39
|
+
`(${toolkitBinding.toolkits.join(", ") || "unscoped only"}) but has no ` +
|
|
40
|
+
"subjectId: refusal logs and activity events cannot say which " +
|
|
41
|
+
"credential they came from. Pass { subjectId: \"<team>\" }.");
|
|
42
|
+
}
|
|
23
43
|
return {
|
|
24
44
|
kind: "bearer",
|
|
45
|
+
...(toolkitBinding ? { toolkitBinding } : {}),
|
|
25
46
|
authorize(request) {
|
|
26
47
|
const header = request.headers.get("authorization") ?? "";
|
|
27
48
|
const match = /^Bearer\s+(.+)$/i.exec(header);
|
package/dist/auth/bearer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bearer.js","sourceRoot":"","sources":["../../src/auth/bearer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"bearer.js","sourceRoot":"","sources":["../../src/auth/bearer.ts"],"names":[],"mappings":"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"}
|
package/dist/auth/clerk.d.ts
CHANGED
|
@@ -1,11 +1,24 @@
|
|
|
1
1
|
import { createClerkClient } from "@clerk/backend";
|
|
2
|
+
import { type ToolkitBindingOptions } from "../toolkits.js";
|
|
2
3
|
import type { InboundAuth } from "../types.js";
|
|
3
4
|
type ClerkClient = ReturnType<typeof createClerkClient>;
|
|
4
|
-
export interface ClerkAuthOptions {
|
|
5
|
+
export interface ClerkAuthOptions extends ToolkitBindingOptions {
|
|
5
6
|
publishableKey: string;
|
|
6
7
|
secretKey: string;
|
|
7
8
|
/** Public base URL of this deployment. Defaults to the request origin. */
|
|
8
9
|
publicUrl?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Email domains this deployment admits, e.g. `["acme.com"]`. An
|
|
12
|
+
* authenticated user whose verified primary email is not on one of them is
|
|
13
|
+
* rejected exactly like a `gate` rejection. Matching is exact on the whole
|
|
14
|
+
* domain and case-insensitive: `acme.com` admits neither `evil-acme.com` nor
|
|
15
|
+
* `mail.acme.com` — spell a subdomain out to allow it. Entries must be ASCII
|
|
16
|
+
* (punycode for an internationalized domain) and are validated at
|
|
17
|
+
* construction. Absent ⇒ every authenticated user passes this check, as
|
|
18
|
+
* before the option existed. Governs Clerk sign-in only: a co-configured
|
|
19
|
+
* `bearerToken` has no email to read and is admitted without a domain check.
|
|
20
|
+
*/
|
|
21
|
+
allowedDomains?: readonly string[];
|
|
9
22
|
/** Optional allow-list hook. Return false to reject an authenticated user. */
|
|
10
23
|
gate?: (userId: string, clerk: ClerkClient) => boolean | Promise<boolean>;
|
|
11
24
|
/** Advertised scopes in protected-resource metadata. */
|
|
@@ -15,6 +28,18 @@ export interface ClerkAuthOptions {
|
|
|
15
28
|
/** Optional hosted Account Portal sign-up URL for `/ui`. */
|
|
16
29
|
signUpUrl?: string;
|
|
17
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Clerk inbound auth.
|
|
33
|
+
*
|
|
34
|
+
* `allowedDomains` and `gate` decide WHO is admitted (both must pass);
|
|
35
|
+
* `toolkits` decides WHICH view the admitted user gets.
|
|
36
|
+
*
|
|
37
|
+
* `toolkits` binds every user this provider admits to those toolkits (§16). For
|
|
38
|
+
* a per-team split, configure one `clerkAuth(...)` per team — the same keys, a
|
|
39
|
+
* `gate` naming that team's users, and that team's `toolkits`. The server tries
|
|
40
|
+
* providers in order and the first that admits the user supplies the binding, so
|
|
41
|
+
* a user one gate rejects falls through to the next.
|
|
42
|
+
*/
|
|
18
43
|
export declare function clerkAuth(opts: ClerkAuthOptions): InboundAuth;
|
|
19
44
|
export {};
|
|
20
45
|
//# sourceMappingURL=clerk.d.ts.map
|
package/dist/auth/clerk.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clerk.d.ts","sourceRoot":"","sources":["../../src/auth/clerk.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,KAAK,EAAc,WAAW,EAAE,MAAM,aAAa,CAAC;AAE3D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAExD,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"clerk.d.ts","sourceRoot":"","sources":["../../src/auth/clerk.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAc,WAAW,EAAE,MAAM,aAAa,CAAC;AAE3D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAExD,MAAM,WAAW,gBAAiB,SAAQ,qBAAqB;IAC7D,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;;;;OAUG;IACH,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,8EAA8E;IAC9E,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1E,wDAAwD;IACxD,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,4DAA4D;IAC5D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA0ID;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,gBAAgB,GAAG,WAAW,CA0O7D"}
|
package/dist/auth/clerk.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// Clerk as the OAuth 2.1 authorization server; connecta is the resource server.
|
|
2
|
-
// Single tenant, no tenant-tag requirement, optional gate() with
|
|
3
|
-
// caching.
|
|
2
|
+
// Single tenant, no tenant-tag requirement, optional allowedDomains/gate() with
|
|
3
|
+
// ~60s identity caching.
|
|
4
4
|
import { createClerkClient } from "@clerk/backend";
|
|
5
|
+
import { resolveToolkitBinding, } from "../toolkits.js";
|
|
5
6
|
const CORS_HEADERS = {
|
|
6
7
|
"Access-Control-Allow-Origin": "*",
|
|
7
8
|
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
|
|
@@ -27,11 +28,118 @@ function fapiUrl(publishableKey) {
|
|
|
27
28
|
}
|
|
28
29
|
const GATE_ALLOWED_TTL_MS = 60 * 1000;
|
|
29
30
|
const GATE_FORBIDDEN_TTL_MS = 30 * 1000;
|
|
31
|
+
/**
|
|
32
|
+
* One label of a domain: ASCII letters/digits, interior hyphens only, 63
|
|
33
|
+
* characters at most. ASCII-only is deliberate — an internationalized domain
|
|
34
|
+
* must be in its punycode (`xn--…`) form, so a Unicode confusable can neither be
|
|
35
|
+
* typed into the allowlist nor arrive in an email address and pass for a domain
|
|
36
|
+
* the operator cannot tell from theirs by eye.
|
|
37
|
+
*/
|
|
38
|
+
const DOMAIN_LABEL_RE = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/i;
|
|
39
|
+
/**
|
|
40
|
+
* Is this string a domain, before any case folding? Both sides of the
|
|
41
|
+
* comparison — the operator's allowlist entries and the domain read off a
|
|
42
|
+
* user's email — are checked against this one grammar, so neither side can be
|
|
43
|
+
* *repaired* into a match by the normalization that follows: `"acme.com\n"` and
|
|
44
|
+
* `" acme.com"` are malformed, not `acme.com`, and an `akme.com` spelled with a
|
|
45
|
+
* U+212A KELVIN SIGN is rejected here rather than folded to plain ASCII `k` by
|
|
46
|
+
* `toLowerCase`.
|
|
47
|
+
*/
|
|
48
|
+
function isDomain(domain) {
|
|
49
|
+
return (domain.length > 0 &&
|
|
50
|
+
domain.length <= 253 &&
|
|
51
|
+
domain.includes(".") &&
|
|
52
|
+
domain.split(".").every((label) => DOMAIN_LABEL_RE.test(label)));
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Validate and lowercase `allowedDomains` at construction. Everything here
|
|
56
|
+
* throws rather than dropping the entry: an allowlist that does not say what
|
|
57
|
+
* its author meant is invisible until the day it admits the wrong caller.
|
|
58
|
+
*/
|
|
59
|
+
function normalizeAllowedDomains(value) {
|
|
60
|
+
if (value === undefined)
|
|
61
|
+
return undefined;
|
|
62
|
+
if (!Array.isArray(value)) {
|
|
63
|
+
throw new Error("clerkAuth: `allowedDomains` must be an array of domains.");
|
|
64
|
+
}
|
|
65
|
+
if (value.length === 0) {
|
|
66
|
+
// Fail-closed, an empty list admits nobody and the deployment is dead on
|
|
67
|
+
// arrival; read as "no restriction", it is the one shape here that fails
|
|
68
|
+
// OPEN. Neither is what anyone meant to write.
|
|
69
|
+
throw new Error("clerkAuth: `allowedDomains` is empty. List at least one domain, or " +
|
|
70
|
+
"drop the option to admit every authenticated user.");
|
|
71
|
+
}
|
|
72
|
+
const domains = new Set();
|
|
73
|
+
for (const entry of value) {
|
|
74
|
+
if (typeof entry !== "string") {
|
|
75
|
+
throw new Error(`clerkAuth: \`allowedDomains\` entry ${JSON.stringify(entry)} is not a string.`);
|
|
76
|
+
}
|
|
77
|
+
// Surrounding whitespace is the one thing forgiven, and only here: this is
|
|
78
|
+
// operator config read at construction, where a stray space is a typo the
|
|
79
|
+
// operator can see in the throw. Nothing is forgiven on the email side.
|
|
80
|
+
const domain = entry.trim();
|
|
81
|
+
if (!isDomain(domain)) {
|
|
82
|
+
const hint = domain.includes("@")
|
|
83
|
+
? " Write the domain alone, with no `@` and no local part."
|
|
84
|
+
: "";
|
|
85
|
+
throw new Error(`clerkAuth: \`allowedDomains\` entry ${JSON.stringify(entry)} is not a ` +
|
|
86
|
+
`domain (expected something like "acme.com").${hint}`);
|
|
87
|
+
}
|
|
88
|
+
domains.add(domain.toLowerCase());
|
|
89
|
+
}
|
|
90
|
+
return domains;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Bounded, escaped form of the denied domain for the operator log — the same
|
|
94
|
+
* treatment `src/server.ts` gives a rejected toolkit name. An email domain is
|
|
95
|
+
* caller-influenced (anyone who controls a mailbox controls its domain): the
|
|
96
|
+
* bound is what a 253-byte domain needs, and the escaping — JSON.stringify plus
|
|
97
|
+
* the hand-rolled U+2028/U+2029 pass it leaves raw — is defense in depth behind
|
|
98
|
+
* `isDomain`, which has already ruled out the newline that would forge a line.
|
|
99
|
+
*/
|
|
100
|
+
function loggableDomain(domain) {
|
|
101
|
+
const bounded = domain.slice(0, 100);
|
|
102
|
+
const escaped = JSON.stringify(bounded).replace(/[\u2028\u2029]/g, (ch) => `\\u${ch.charCodeAt(0).toString(16)}`);
|
|
103
|
+
return escaped + (bounded.length < domain.length ? " (truncated)" : "");
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* The domain of an email address, lowercased for comparison, or null when the
|
|
107
|
+
* address does not have exactly one well-formed domain to read.
|
|
108
|
+
*
|
|
109
|
+
* Nothing here repairs the input. The domain is validated as it arrived and
|
|
110
|
+
* only then lowercased, so `dev@ acme.com`, `dev@acme.com\n` and `dev@acme.com.`
|
|
111
|
+
* are malformed addresses that DENY, rather than whitespace-trimmed or
|
|
112
|
+
* dot-stripped into a match for `acme.com`. The split is on the last `@`, the
|
|
113
|
+
* part a mail system routes on, so this reads the same domain that would
|
|
114
|
+
* receive the mail. (Under exact set matching a first-`@` split could not fail
|
|
115
|
+
* open either — it would just read a domain nobody delivers to.)
|
|
116
|
+
*/
|
|
117
|
+
function emailDomain(email) {
|
|
118
|
+
const at = email.lastIndexOf("@");
|
|
119
|
+
if (at <= 0 || at === email.length - 1)
|
|
120
|
+
return null;
|
|
121
|
+
const domain = email.slice(at + 1);
|
|
122
|
+
return isDomain(domain) ? domain.toLowerCase() : null;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Clerk inbound auth.
|
|
126
|
+
*
|
|
127
|
+
* `allowedDomains` and `gate` decide WHO is admitted (both must pass);
|
|
128
|
+
* `toolkits` decides WHICH view the admitted user gets.
|
|
129
|
+
*
|
|
130
|
+
* `toolkits` binds every user this provider admits to those toolkits (§16). For
|
|
131
|
+
* a per-team split, configure one `clerkAuth(...)` per team — the same keys, a
|
|
132
|
+
* `gate` naming that team's users, and that team's `toolkits`. The server tries
|
|
133
|
+
* providers in order and the first that admits the user supplies the binding, so
|
|
134
|
+
* a user one gate rejects falls through to the next.
|
|
135
|
+
*/
|
|
30
136
|
export function clerkAuth(opts) {
|
|
31
137
|
const clerk = createClerkClient({
|
|
32
138
|
secretKey: opts.secretKey,
|
|
33
139
|
publishableKey: opts.publishableKey,
|
|
34
140
|
});
|
|
141
|
+
const toolkitBinding = resolveToolkitBinding("clerkAuth", opts);
|
|
142
|
+
const allowedDomains = normalizeAllowedDomains(opts.allowedDomains);
|
|
35
143
|
const scopes = opts.scopes ?? ["openid", "profile", "email"];
|
|
36
144
|
const gateCache = new Map();
|
|
37
145
|
const resolveBase = (baseUrl) => opts.publicUrl ?? baseUrl;
|
|
@@ -47,15 +155,63 @@ export function clerkAuth(opts) {
|
|
|
47
155
|
});
|
|
48
156
|
};
|
|
49
157
|
const forbidden = () => new Response(JSON.stringify({ error: "forbidden" }), { status: 403, headers: { "Content-Type": "application/json" } });
|
|
158
|
+
/**
|
|
159
|
+
* The domain half of admission. Fails CLOSED on every uncertainty — no
|
|
160
|
+
* primary email, an unverified one, a malformed address, or the lookup
|
|
161
|
+
* itself failing — because "we could not tell" and "they belong here" must
|
|
162
|
+
* not be the same answer for a membership rule.
|
|
163
|
+
*/
|
|
164
|
+
const checkDomain = async (userId) => {
|
|
165
|
+
if (!allowedDomains)
|
|
166
|
+
return true;
|
|
167
|
+
let email;
|
|
168
|
+
try {
|
|
169
|
+
const user = await clerk.users.getUser(userId);
|
|
170
|
+
const primary = user.emailAddresses?.find((address) => address.id === user.primaryEmailAddressId);
|
|
171
|
+
if (primary?.verification?.status === "verified") {
|
|
172
|
+
email = primary.emailAddress;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
catch (error) {
|
|
176
|
+
console.warn(`[connecta] clerk email lookup failed for ${userId}: ${error instanceof Error ? error.message : String(error)} — denying`);
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
const domain = email ? emailDomain(email) : null;
|
|
180
|
+
if (!domain) {
|
|
181
|
+
// One line for three cases (no primary email, unverified, or an address
|
|
182
|
+
// with no readable domain) because the caller must not be able to tell
|
|
183
|
+
// them apart — but it must not claim the email is missing when it is
|
|
184
|
+
// there and malformed.
|
|
185
|
+
console.warn(`[connecta] clerk user ${userId} has no verified primary email with a ` +
|
|
186
|
+
"well-formed domain — denying");
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
if (!allowedDomains.has(domain)) {
|
|
190
|
+
// The domain, never the address: this is an operator log, not a place to
|
|
191
|
+
// spill the local part of someone's email on every denied request.
|
|
192
|
+
console.warn(`[connecta] clerk user ${userId} denied: email domain ` +
|
|
193
|
+
`${loggableDomain(domain)} is not on allowedDomains`);
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
return true;
|
|
197
|
+
};
|
|
198
|
+
/**
|
|
199
|
+
* Is this authenticated user admitted? The domain allowlist and `gate` both
|
|
200
|
+
* have to say yes, and the allowlist runs first so an outsider never reaches
|
|
201
|
+
* operator gate code. One cached verdict covers both, so composing them costs
|
|
202
|
+
* no more Clerk calls than `gate` alone did.
|
|
203
|
+
*/
|
|
50
204
|
const checkGate = async (userId) => {
|
|
51
|
-
if (!opts.gate)
|
|
205
|
+
if (!opts.gate && !allowedDomains)
|
|
52
206
|
return true;
|
|
53
207
|
const hit = gateCache.get(userId);
|
|
54
208
|
if (hit && Date.now() < hit.exp)
|
|
55
209
|
return hit.allowed;
|
|
56
210
|
let allowed = false;
|
|
57
211
|
try {
|
|
58
|
-
allowed =
|
|
212
|
+
allowed =
|
|
213
|
+
(await checkDomain(userId)) &&
|
|
214
|
+
(opts.gate ? await opts.gate(userId, clerk) : true);
|
|
59
215
|
}
|
|
60
216
|
catch {
|
|
61
217
|
allowed = false;
|
|
@@ -69,6 +225,7 @@ export function clerkAuth(opts) {
|
|
|
69
225
|
};
|
|
70
226
|
return {
|
|
71
227
|
kind: "clerk",
|
|
228
|
+
...(toolkitBinding ? { toolkitBinding } : {}),
|
|
72
229
|
uiAuth: {
|
|
73
230
|
kind: "clerk",
|
|
74
231
|
publishableKey: opts.publishableKey,
|
package/dist/auth/clerk.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clerk.js","sourceRoot":"","sources":["../../src/auth/clerk.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF
|
|
1
|
+
{"version":3,"file":"clerk.js","sourceRoot":"","sources":["../../src/auth/clerk.ts"],"names":[],"mappings":"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"}
|
package/dist/connectors/api.d.ts
CHANGED
|
@@ -17,6 +17,19 @@ export interface ApiOptions {
|
|
|
17
17
|
/** Human-readable display name; the connector id remains the address prefix. */
|
|
18
18
|
title?: string;
|
|
19
19
|
description?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Max inline result size (bytes) for this connector's tools before
|
|
22
|
+
* call_tool/batch_call truncate and stash the full text for get_result
|
|
23
|
+
* paging. Overrides the deployment's `maxResultBytes`; omit to inherit it.
|
|
24
|
+
* Must be a whole number of bytes >= 1; anything else warns at startup and
|
|
25
|
+
* is ignored.
|
|
26
|
+
*/
|
|
27
|
+
maxResultBytes?: number;
|
|
28
|
+
/**
|
|
29
|
+
* Optional agent-facing usage guide (markdown) served by the `skills`
|
|
30
|
+
* meta-tool as `connector:<id>`. See `Connector.usageGuide`.
|
|
31
|
+
*/
|
|
32
|
+
usageGuide?: string;
|
|
20
33
|
/** Optional operator-managed credential exposed through ctx.credential and /ui. */
|
|
21
34
|
credential?: ConnectorCredentialConfig;
|
|
22
35
|
/** Optional validation behind /ui's Test action. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/connectors/api.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,SAAS,EACT,yBAAyB,EACzB,yBAAyB,EACzB,gBAAgB,EAChB,oBAAoB,EACpB,UAAU,EACV,eAAe,EAEhB,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,WAAW,CAAC,EAAE,UAAU,CAAC;IACzB,0EAA0E;IAC1E,YAAY,CAAC,EAAE,UAAU,CAAC;IAC1B;;;OAGG;IACH,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,OAAO,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,gBAAgB,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;CAC3E;AAED,MAAM,WAAW,UAAU;IACzB,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mFAAmF;IACnF,UAAU,CAAC,EAAE,yBAAyB,CAAC;IACvC,oDAAoD;IACpD,cAAc,CAAC,EAAE,CACf,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,gBAAgB,KAClB,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACnC,6DAA6D;IAC7D,eAAe,CAAC,EAAE,CAChB,MAAM,EAAE,yBAAyB,EACjC,GAAG,EAAE,gBAAgB,KAClB,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACnC;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;;;;;OAQG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,KAAK,EAAE,OAAO,EAAE,CAAC;CAClB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/connectors/api.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,SAAS,EACT,yBAAyB,EACzB,yBAAyB,EACzB,gBAAgB,EAChB,oBAAoB,EACpB,UAAU,EACV,eAAe,EAEhB,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,WAAW,CAAC,EAAE,UAAU,CAAC;IACzB,0EAA0E;IAC1E,YAAY,CAAC,EAAE,UAAU,CAAC;IAC1B;;;OAGG;IACH,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,OAAO,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,gBAAgB,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;CAC3E;AAED,MAAM,WAAW,UAAU;IACzB,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mFAAmF;IACnF,UAAU,CAAC,EAAE,yBAAyB,CAAC;IACvC,oDAAoD;IACpD,cAAc,CAAC,EAAE,CACf,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,gBAAgB,KAClB,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACnC,6DAA6D;IAC7D,eAAe,CAAC,EAAE,CAChB,MAAM,EAAE,yBAAyB,EACjC,GAAG,EAAE,gBAAgB,KAClB,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACnC;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;;;;;OAQG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,KAAK,EAAE,OAAO,EAAE,CAAC;CAClB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,SAAS,CAkD3D"}
|
package/dist/connectors/api.js
CHANGED
|
@@ -34,6 +34,8 @@ export function api(id, opts) {
|
|
|
34
34
|
title: opts.title,
|
|
35
35
|
kind: "api",
|
|
36
36
|
description: opts.description,
|
|
37
|
+
maxResultBytes: opts.maxResultBytes,
|
|
38
|
+
usageGuide: opts.usageGuide,
|
|
37
39
|
credential: opts.credential,
|
|
38
40
|
testCredential: opts.testCredential,
|
|
39
41
|
testCredentials: opts.testCredentials,
|