@zackbart/connecta 0.20.0 → 0.21.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/CHANGELOG.md +93 -0
  2. package/README.md +3 -1
  3. package/bin/connecta.mjs +23 -6
  4. package/dist/auth/bearer.d.ts +2 -2
  5. package/dist/auth/bearer.js +2 -2
  6. package/dist/auth/clerk.js +1 -0
  7. package/dist/auth/cloudflare-access.d.ts +8 -0
  8. package/dist/auth/cloudflare-access.js +66 -0
  9. package/dist/execute.js +12 -6
  10. package/dist/index.d.ts +2 -2
  11. package/dist/index.js +2 -2
  12. package/dist/meta-tools.js +3 -3
  13. package/dist/operator-ui/generated.js +1 -1
  14. package/dist/operator-ui/model.d.ts +3 -3
  15. package/dist/operator-ui/view.d.ts +1 -1
  16. package/dist/operator-ui/view.js +6 -3
  17. package/dist/providers/cloudflare.js +233 -61
  18. package/dist/providers/linear.js +7 -0
  19. package/dist/providers/mixpanel.js +6 -4
  20. package/dist/providers/revenuecat.js +2 -1
  21. package/dist/providers/stripe.js +7 -6
  22. package/dist/routes/access-tokens.d.ts +1 -1
  23. package/dist/routes/access-tokens.js +2 -2
  24. package/dist/routes/activity.js +2 -2
  25. package/dist/routes/credentials.js +1 -1
  26. package/dist/routes/mcp.js +1 -1
  27. package/dist/routes/oauth.js +1 -1
  28. package/dist/routes/shared.d.ts +4 -4
  29. package/dist/routes/shared.js +10 -10
  30. package/dist/routes/ui.js +12 -9
  31. package/dist/skills.d.ts +1 -1
  32. package/dist/skills.js +7 -4
  33. package/dist/types.d.ts +37 -22
  34. package/dist/ui.d.ts +1 -1
  35. package/dist/ui.js +3 -3
  36. package/dist/version.d.ts +1 -1
  37. package/dist/version.js +1 -1
  38. package/documentation/architecture.md +7 -4
  39. package/documentation/auth.md +71 -7
  40. package/documentation/cloudflare.md +19 -1
  41. package/documentation/code-mode.md +4 -4
  42. package/documentation/linear.md +6 -4
  43. package/documentation/meta-tools.md +22 -20
  44. package/documentation/mixpanel.md +5 -3
  45. package/documentation/operations.md +28 -13
  46. package/documentation/operator-ui.md +21 -5
  47. package/documentation/provider-conventions.md +4 -2
  48. package/documentation/revenuecat.md +21 -21
  49. package/documentation/stripe.md +14 -13
  50. package/documentation/upgrading.md +77 -4
  51. package/ethos.md +2 -3
  52. package/examples/worker/README.md +52 -32
  53. package/examples/worker/src/index.ts +32 -38
  54. package/examples/worker/wrangler.jsonc +12 -4
  55. package/package.json +5 -1
  56. package/templates/node/package.json +1 -1
package/ethos.md CHANGED
@@ -1,9 +1,7 @@
1
1
  # connecta — ethos
2
2
 
3
3
  What connecta is, what it refuses to be, and the invariants every change must
4
- preserve. Deliberately terse: when a change contradicts a line here, either the
5
- change is wrong or this file needs amending — in that order, and amending it is
6
- a design decision, not a drive-by edit.
4
+ preserve. A contradiction needs a design decision, not a drive-by edit.
7
5
 
8
6
  ## What this is
9
7
 
@@ -78,6 +76,7 @@ CHANGELOG, not here.
78
76
  | MRTR / `input_required` passthrough | gated | relayable statelessly; no host or downstream emits it yet ([#176](https://github.com/zackbart/connecta/issues/176)) |
79
77
  | Downstream `ttlMs` cache hints | gated | needs refresh-churn evidence ([#206](https://github.com/zackbart/connecta/issues/206)) |
80
78
  | Downstream MCP Apps template passthrough | gated | needs a downstream that ships one ([#266](https://github.com/zackbart/connecta/issues/266)) |
79
+ | Worker Access inbound auth | provisional | Managed OAuth and Clerk migration need production evidence ([#506](https://github.com/zackbart/connecta/issues/506)) |
81
80
  | Program UI tool calls | removed | the read bridge added a second contract without improving agent data retrieval; views are display-only again ([#287](https://github.com/zackbart/connecta/issues/287), [#484](https://github.com/zackbart/connecta/issues/484)) |
82
81
 
83
82
  ## Invariants
@@ -1,9 +1,9 @@
1
1
  # connecta — Cloudflare Worker example
2
2
 
3
3
  A deployable Worker that aggregates a downstream remote MCP and an in-code HTTP
4
- API connector, guarded by Clerk OAuth *and* a static bearer token, with state in
5
- a KV namespace. Its required Worker Loader binding backs the seven-tool surface
6
- and requires the Workers Paid plan.
4
+ API connector, guarded by Cloudflare Access, with state in a KV namespace. Its
5
+ required Worker Loader binding backs the seven-tool surface and requires the
6
+ Workers Paid plan.
7
7
 
8
8
  This is also the **starting template for a deployment**: a real deployment
9
9
  should be its own repository that pins an exact `@zackbart/connecta` version and
@@ -37,18 +37,27 @@ npm install # from the package root
37
37
  wrangler kv namespace create CONNECTA_KV # paste the id into wrangler.jsonc
38
38
 
39
39
  cd examples/worker
40
- wrangler secret put SUPPORT_TOKEN # one headless client
41
- wrangler secret put EXEC_TOKEN # another headless client
42
- wrangler secret put CLERK_SECRET_KEY
43
40
  wrangler secret put DOWNSTREAM_TOKEN
44
41
  wrangler secret put CREDENTIAL_ENCRYPTION_KEY # base64 32-byte AES key
45
42
  wrangler deploy
46
43
  ```
47
44
 
48
- `PUBLIC_URL` and `CLERK_PUBLISHABLE_KEY` are plain vars in `wrangler.jsonc`.
49
- Enable Dynamic Client Registration on the Clerk instance (OAuth Applications
50
- DCR) so Claude/Cursor can self-register full walkthrough in
51
- [setting up Clerk](../../documentation/auth.md).
45
+ `PUBLIC_URL` is a plain var in `wrangler.jsonc`. After the first deploy, attach
46
+ Cloudflare Access to the Worker itself (the API destination type is `worker`,
47
+ not a hostname application) and choose the account, email-domain, or
48
+ advanced Zero Trust policy that owns admission. Enable **Managed OAuth** on
49
+ that Access application for interactive MCP clients. Access then serves OAuth
50
+ discovery and turns the client's opaque token into the trusted `ctx.access`
51
+ identity connecta reads. A cron job or CI client uses an Access service token
52
+ instead.
53
+
54
+ Cloudflare's [Worker Access guide](https://developers.cloudflare.com/workers/configuration/cloudflare-access/)
55
+ owns the dashboard/API steps; its [Managed OAuth guide](https://developers.cloudflare.com/cloudflare-one/access-controls/applications/http-apps/managed-oauth/)
56
+ owns client registration, redirect allowlists, and token lifetimes.
57
+
58
+ The checked-in `access.dev` block gives `wrangler dev` a local operator
59
+ identity. Remove the block to test the missing-Access refusal. It has no effect
60
+ on a deployed Worker's production identity.
52
61
 
53
62
  ### Copied into its own repository
54
63
 
@@ -57,24 +66,22 @@ dependency this file imports. A copy with its own `package.json` installs three
57
66
  things, because two of them are not part of connecta and never install with it:
58
67
 
59
68
  ```sh
60
- npm install @zackbart/connecta @cloudflare/codemode @clerk/backend
69
+ npm install @zackbart/connecta @cloudflare/codemode
61
70
  ```
62
71
 
63
- Both are optional peers of `@zackbart/connecta` declared in its manifest,
64
- never installed with it, and each carrying the range this release supports.
65
- `@cloudflare/codemode` is the executor behind `execute_code`, published as
72
+ `@cloudflare/codemode` is the optional peer behind `execute_code`, declared in
73
+ connecta's manifest but never installed with it, and published as
66
74
  `^0.4.4 || ^0.5.0`: install a version inside that and npm stays quiet, install
67
75
  one outside and npm says so at install time instead of leaving a Worker to
68
76
  discover the skew in production ([#376](https://github.com/zackbart/connecta/issues/376)).
69
77
 
70
- `@clerk/backend` is the peer behind `@zackbart/connecta/auth/clerk`, which
71
- `src/index.ts` imports at the top level, so wrangler must resolve it at
72
- build time. Miss it and the build stops at
73
- `Could not resolve "@clerk/backend"`, which is a missing peer rather than a
74
- broken example. Drop `clerkAuth` from `auth` if this deployment has no operator
75
- sign-in, and the peer goes with it — but read
76
- [the operator surface](#the-operator-surface) first, because a deployment
77
- without it can never write a credential or issue an access token.
78
+ `cloudflareAccessAuth()` has no dependency of its own. A deployment keeping
79
+ Clerk for rollback still installs `@clerk/backend` and keeps the commented
80
+ provider shape in `src/index.ts` until the migration is verified.
81
+
82
+ ```sh
83
+ npm install @clerk/backend # migration window only
84
+ ```
78
85
 
79
86
  Then point an MCP client at `<PUBLIC_URL>/mcp`, and open `<PUBLIC_URL>/` for
80
87
  Connections. Credentials is at `/credentials`, named MCP access tokens are at
@@ -87,11 +94,11 @@ the next section for what turns each one on.
87
94
  This example ships the whole operator feature set. Three quarters of it is on
88
95
  as deployed; the fourth needs a database, so it is commented in place.
89
96
 
90
- **Operator sign-in** is the `clerkAuth` entry in `src/index.ts`, alongside two
91
- static bearers. The split is deliberate: a bearer is a client key that may call
92
- tools and read connector status, while writing a credential or issuing an
93
- access token requires an interactive Clerk identity. Narrow who that can be
94
- with `allowedDomains`, or with a `gate` for anything a domain cannot express.
97
+ **Operator sign-in** is the `cloudflareAccessAuth()` entry in `src/index.ts`.
98
+ Access authenticates before the Worker runs. A human Access identity can use
99
+ MCP and operator pages; a service-token identity can use MCP but cannot write a
100
+ credential, run downstream OAuth, or issue a connecta token. Narrow admission
101
+ in the Access policy rather than repeating email domains or groups in code.
95
102
 
96
103
  **The credential vault** is `credentials: { encryptionKey: … }`, backed by the
97
104
  same KV namespace as everything else and encrypted with the
@@ -116,12 +123,18 @@ shape on `echo` is exactly it) or use a provider connector such as `notion()`,
116
123
  which declares its own, and Credentials appears for a signed-in operator on the
117
124
  next load.
118
125
 
119
- **Access tokens** are `accessTokens: {}`. A signed-in operator mints named,
126
+ **Access tokens** are `accessTokens: {}`. A signed-in human operator mints named,
120
127
  revocable Bearer tokens at `/tokens` for header-capable clients that will not do
121
128
  OAuth. Secrets are shown once and only their hashes enter KV; a lost token is
122
129
  reissued, never recovered. Note the KV caveat above — revocation is visible
123
130
  everywhere only as fast as the namespace converges.
124
131
 
132
+ Worker-level Access still runs before these tokens. A `cta_…` token therefore
133
+ does not reach connecta by itself; retain the feature as a rollback path or for
134
+ a caller that already supplies separate Access service-token headers. Normal
135
+ interactive MCP clients should use Managed OAuth, and unattended clients should
136
+ use Access service tokens.
137
+
125
138
  **Activity** is the commented block in `src/index.ts` and the commented
126
139
  `d1_databases` binding in `wrangler.jsonc`; the section below creates the
127
140
  database and applies the schema.
@@ -134,10 +147,17 @@ never the connector set, the tool catalog, or its annotations.
134
147
  this on: connector count, executor, seven tools. The executor it names is this
135
148
  one — `DynamicWorkerExecutor executed`, not the Node template's QuickJS, which
136
149
  is what doctor used to claim everywhere
137
- ([#368](https://github.com/zackbart/connecta/issues/368)). It carries a bearer, and a
138
- bearer learns the model-facing surface rather than the deployment's
139
- configuration topology. Confirm the operator surface the way an operator will:
140
- sign in at `<PUBLIC_URL>/` and check that Tokens is live. Credentials joins it
150
+ ([#368](https://github.com/zackbart/connecta/issues/368)). Against Access it
151
+ carries `CF_ACCESS_CLIENT_ID` and `CF_ACCESS_CLIENT_SECRET`, and the service
152
+ identity learns the model-facing surface rather than deployment topology:
153
+
154
+ ```sh
155
+ CF_ACCESS_CLIENT_ID=… CF_ACCESS_CLIENT_SECRET=… \
156
+ npx connecta doctor --url "$PUBLIC_URL"
157
+ ```
158
+
159
+ Confirm the operator surface the way an operator will: sign in at
160
+ `<PUBLIC_URL>/` and check that Tokens is live. Credentials joins it
141
161
  once a connector declares a `credential` slot, and Activity once the D1 wiring
142
162
  below is on — the nav shows a page when the deployment can actually serve it,
143
163
  so a missing page is the honest report that its half is still off.
@@ -2,9 +2,10 @@
2
2
  * connecta on Cloudflare Workers.
3
3
  *
4
4
  * One MCP endpoint aggregating a downstream remote MCP and an HTTP API, guarded
5
- * by Clerk OAuth *and* a static bearer token, with OAuth/cache state in a KV
6
- * namespace. The required Worker Loader binding in wrangler.jsonc backs the
7
- * seven-tool surface.
5
+ * by Cloudflare Access, with OAuth/cache state in a KV namespace. Access
6
+ * authenticates the request before this Worker runs and supplies the trusted
7
+ * identity through ctx.access. The required Worker Loader binding in
8
+ * wrangler.jsonc backs the seven-tool surface.
8
9
  *
9
10
  * The operator surface is wired here except for activity history, which needs
10
11
  * a database this example does not create for you: sign-in, the credential
@@ -15,19 +16,16 @@
15
16
  * installed `@zackbart/connecta` package):
16
17
  * 1. `npm install` in the connecta package root (../../ from here) so the
17
18
  * package import and wrangler resolve. A copy in its own repository
18
- * installs `@zackbart/connecta @cloudflare/codemode @clerk/backend`
19
- * instead the last two are not part of connecta, and the Clerk import
20
- * below is an optional peer wrangler resolves at build time.
19
+ * installs `@zackbart/connecta @cloudflare/codemode` instead. Codemode is
20
+ * an optional peer; a migrating deployment also keeps `@clerk/backend`
21
+ * until it removes the commented rollback provider below.
21
22
  * 2. Create a KV namespace and put its id in wrangler.jsonc under `kv_namespaces`.
22
23
  * 3. Set secrets:
23
- * wrangler secret put SUPPORT_TOKEN
24
- * wrangler secret put EXEC_TOKEN
25
- * wrangler secret put CLERK_SECRET_KEY
26
24
  * wrangler secret put DOWNSTREAM_TOKEN
27
25
  * wrangler secret put CREDENTIAL_ENCRYPTION_KEY
28
- * and CLERK_PUBLISHABLE_KEY + PUBLIC_URL as plain vars in wrangler.jsonc.
29
- * 4. Enable Dynamic Client Registration in the Clerk dashboard
30
- * (OAuth Applications -> DCR toggle) so Claude/Cursor can self-register.
26
+ * and PUBLIC_URL as a plain var in wrangler.jsonc.
27
+ * 4. Attach Cloudflare Access to this Worker. Enable Managed OAuth on the
28
+ * Access application for interactive MCP clients.
31
29
  * 5. Use the Workers Paid plan required by the `worker_loaders` binding.
32
30
  * 6. `wrangler deploy` from this folder (examples/worker), where wrangler.jsonc
33
31
  * lives. Point your MCP client at `<PUBLIC_URL>/mcp`.
@@ -35,23 +33,21 @@
35
33
  import { DynamicWorkerExecutor } from "@cloudflare/codemode";
36
34
  import {
37
35
  api,
38
- bearerToken,
39
36
  createConnecta,
40
37
  remoteMcp,
41
38
  } from "@zackbart/connecta";
42
- import { clerkAuth } from "@zackbart/connecta/auth/clerk";
39
+ import { cloudflareAccessAuth } from "@zackbart/connecta/auth/cloudflare-access";
40
+ // Rollback for a deployment migrating from Clerk:
41
+ // import { clerkAuth } from "@zackbart/connecta/auth/clerk";
43
42
  import { cloudflareKvStorage } from "./cloudflare-kv.js";
44
43
  // Activity history, off by default because it needs a D1 database.
45
44
  // import { d1ActivityStore } from "./d1-activity.js";
46
45
 
47
46
  interface Env {
48
47
  CONNECTA_KV: KVNamespace;
49
- /** Bearer token for one headless client in this deployment's audience. */
50
- SUPPORT_TOKEN: string;
51
- /** Bearer token for another headless client in the same audience. */
52
- EXEC_TOKEN: string;
53
- CLERK_PUBLISHABLE_KEY: string;
54
- CLERK_SECRET_KEY: string;
48
+ // Keep these during a Clerk migration until Access has been verified:
49
+ // CLERK_PUBLISHABLE_KEY: string;
50
+ // CLERK_SECRET_KEY: string;
55
51
  /**
56
52
  * Base64 32-byte AES key encrypting operator-managed credentials in KV.
57
53
  * Unset means no vault: /credentials stays read-only and connecta says so at
@@ -75,22 +71,19 @@ function build(env: Env) {
75
71
  storage: cloudflareKvStorage(env.CONNECTA_KV),
76
72
  executor: new DynamicWorkerExecutor({ loader: env.LOADER }),
77
73
  auth: [
78
- // Multiple credentials may identify callers in one deployment. Every
79
- // admitted caller reaches this deployment's deliberate connector set.
80
- bearerToken(env.SUPPORT_TOKEN, {
81
- subjectId: "support-team",
82
- }),
83
- bearerToken(env.EXEC_TOKEN, {
84
- subjectId: "exec-team",
85
- }),
86
- // The operator signs in with Clerk. Restrict who may sign in with
87
- // `allowedDomains` (or a `gate`, for anything a domain cannot express).
88
- clerkAuth({
89
- publishableKey: env.CLERK_PUBLISHABLE_KEY,
90
- secretKey: env.CLERK_SECRET_KEY,
91
- publicUrl: env.PUBLIC_URL,
92
- // allowedDomains: ["acme.com"],
93
- }),
74
+ // Access owns admission policy. A human identity may use MCP and the
75
+ // operator pages; a service token may use MCP but cannot mutate operator
76
+ // state. Neither path asks connecta to parse a JWT.
77
+ cloudflareAccessAuth(),
78
+ // Leave the previous Clerk provider below this entry during migration.
79
+ // It is a rollback path until Worker-level Access is detached; Access
80
+ // itself decides whether a request reaches this array.
81
+ // clerkAuth({
82
+ // publishableKey: env.CLERK_PUBLISHABLE_KEY,
83
+ // secretKey: env.CLERK_SECRET_KEY,
84
+ // publicUrl: env.PUBLIC_URL,
85
+ // allowedDomains: ["acme.com"],
86
+ // }),
94
87
  ],
95
88
  // Connectors that declare a `credential` slot become editable at
96
89
  // /credentials, encrypted with this key before anything reaches KV. A
@@ -105,8 +98,9 @@ function build(env: Env) {
105
98
  // `echo`, or use a provider connector like `notion()`, which declares its
106
99
  // own) and the page appears on the next load.
107
100
  credentials: { encryptionKey: env.CREDENTIAL_ENCRYPTION_KEY },
108
- // Eligible Clerk operators can create named, revocable MCP Bearer tokens
109
- // at /tokens. Secrets are shown once; only their hashes enter KV.
101
+ // Eligible human operators can create named, revocable MCP Bearer tokens
102
+ // at /tokens. Under Worker-level Access those tokens are a rollback tool,
103
+ // not standalone edge credentials: Access still runs before connecta.
110
104
  accessTokens: {},
111
105
  // Payload-free activity at /activity, off until a database exists to hold
112
106
  // it. Uncomment the `d1_databases` binding in wrangler.jsonc, apply the
@@ -6,12 +6,20 @@
6
6
  "compatibility_flags": ["nodejs_compat"],
7
7
  "observability": { "enabled": true },
8
8
 
9
- // Plain vars. Secrets (SUPPORT_TOKEN, EXEC_TOKEN, CLERK_SECRET_KEY,
10
- // CREDENTIAL_ENCRYPTION_KEY, DOWNSTREAM_TOKEN) are set with
9
+ // Plain vars. Secrets (CREDENTIAL_ENCRYPTION_KEY, DOWNSTREAM_TOKEN) are set with
11
10
  // `wrangler secret put <NAME>`, not here.
12
11
  "vars": {
13
- "PUBLIC_URL": "https://connecta.example.workers.dev",
14
- "CLERK_PUBLISHABLE_KEY": "pk_test_replace-me"
12
+ "PUBLIC_URL": "https://connecta.example.workers.dev"
13
+ },
14
+
15
+ // Local-only Access identity. Remove this block to exercise the
16
+ // unauthenticated path in `wrangler dev`; production identity comes from the
17
+ // Worker-level Access application, not from this file.
18
+ "access": {
19
+ "dev": {
20
+ "aud": "connecta-local",
21
+ "identity": { "email": "operator@example.com" }
22
+ }
15
23
  },
16
24
 
17
25
  // Create with `wrangler kv namespace create CONNECTA_KV` and paste the id.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zackbart/connecta",
3
- "version": "0.20.0",
3
+ "version": "0.21.1",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "description": "One MCP to rule them all — a single MCP endpoint aggregating many downstream connectors behind a code-first surface of seven meta-tools.",
@@ -63,6 +63,10 @@
63
63
  "types": "./dist/auth/clerk.d.ts",
64
64
  "import": "./dist/auth/clerk.js"
65
65
  },
66
+ "./auth/cloudflare-access": {
67
+ "types": "./dist/auth/cloudflare-access.d.ts",
68
+ "import": "./dist/auth/cloudflare-access.js"
69
+ },
66
70
  "./providers/cloudflare": {
67
71
  "types": "./dist/providers/cloudflare.d.ts",
68
72
  "import": "./dist/providers/cloudflare.js"
@@ -15,7 +15,7 @@
15
15
  "typecheck": "tsc --noEmit"
16
16
  },
17
17
  "dependencies": {
18
- "@zackbart/connecta": "0.20.0",
18
+ "@zackbart/connecta": "0.21.1",
19
19
  "quickjs-emscripten": "0.32.0"
20
20
  },
21
21
  "devDependencies": {