@gjermundgaraba/effect-actions 0.19.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -41
- package/dist/Action.d.mts +140 -48
- package/dist/Action.mjs +88 -44
- package/dist/ActionCli.d.mts +70 -35
- package/dist/ActionCli.mjs +53 -34
- package/dist/ActionHttp.d.mts +70 -38
- package/dist/ActionHttp.mjs +76 -25
- package/dist/ActionMcp.d.mts +56 -24
- package/dist/ActionMcp.mjs +104 -61
- package/dist/ActionRpc.d.mts +222 -57
- package/dist/ActionRpc.mjs +301 -49
- package/dist/ActionToolkit.d.mts +22 -7
- package/dist/ActionToolkit.mjs +37 -14
- package/dist/Authentication.d.mts +42 -12
- package/dist/Authentication.mjs +38 -32
- package/dist/Event.d.mts +370 -0
- package/dist/Event.mjs +103 -0
- package/dist/Testing.d.mts +1 -3
- package/dist/Testing.mjs +2 -3
- package/dist/Webhook.d.mts +146 -0
- package/dist/Webhook.mjs +72 -0
- package/dist/authentication/provider.d.mts +35 -12
- package/dist/authentication/provider.mjs +2 -3
- package/dist/authentication/refusal.mjs +3 -4
- package/dist/cli/commands.d.mts +9 -7
- package/dist/cli/commands.mjs +85 -35
- package/dist/contract/ast.mjs +5 -3
- package/dist/contract/authorizer.d.mts +8 -0
- package/dist/contract/authorizer.mjs +20 -0
- package/dist/contract/call.d.mts +9 -8
- package/dist/contract/call.mjs +49 -8
- package/dist/contract/callback.d.mts +7 -0
- package/dist/contract/callback.mjs +27 -0
- package/dist/contract/caller.d.mts +12 -3
- package/dist/contract/caller.mjs +23 -5
- package/dist/contract/canonical.mjs +10 -0
- package/dist/contract/codec.d.mts +9 -0
- package/dist/contract/codec.mjs +9 -0
- package/dist/contract/codes.mjs +81 -0
- package/dist/contract/declared.d.mts +0 -2
- package/dist/contract/declared.mjs +26 -11
- package/dist/contract/digest.mjs +6 -0
- package/dist/contract/errors.d.mts +9 -5
- package/dist/contract/errors.mjs +2 -3
- package/dist/contract/feed.d.mts +127 -0
- package/dist/contract/feed.mjs +249 -0
- package/dist/contract/hints.mjs +1 -2
- package/dist/contract/hub.d.mts +94 -0
- package/dist/contract/hub.mjs +133 -0
- package/dist/contract/idempotency.d.mts +47 -0
- package/dist/contract/idempotency.mjs +99 -0
- package/dist/contract/implementation.d.mts +73 -51
- package/dist/contract/implementation.mjs +94 -60
- package/dist/contract/input-check.d.mts +15 -0
- package/dist/contract/input-check.mjs +16 -0
- package/dist/contract/lease.mjs +28 -0
- package/dist/contract/listed.d.mts +4 -0
- package/dist/contract/listed.mjs +22 -0
- package/dist/contract/log.d.mts +41 -0
- package/dist/contract/log.mjs +144 -0
- package/dist/contract/media.d.mts +1 -3
- package/dist/contract/media.mjs +1 -2
- package/dist/contract/names.mjs +15 -6
- package/dist/contract/occurrence.d.mts +29 -0
- package/dist/contract/occurrence.mjs +45 -0
- package/dist/contract/pages.d.mts +13 -0
- package/dist/contract/pages.mjs +39 -0
- package/dist/contract/progress.d.mts +26 -0
- package/dist/contract/progress.mjs +72 -0
- package/dist/contract/push.d.mts +20 -0
- package/dist/contract/push.mjs +96 -0
- package/dist/contract/receiving.d.mts +29 -0
- package/dist/contract/receiving.mjs +42 -0
- package/dist/contract/recent.mjs +12 -0
- package/dist/contract/reported.mjs +16 -0
- package/dist/contract/serving.mjs +63 -0
- package/dist/contract/status.mjs +15 -7
- package/dist/contract/stream.d.mts +34 -0
- package/dist/contract/stream.mjs +31 -0
- package/dist/contract/subscribe.d.mts +45 -0
- package/dist/contract/subscribe.mjs +50 -0
- package/dist/contract/transient.mjs +28 -0
- package/dist/contract/watch.d.mts +18 -0
- package/dist/contract/watch.mjs +105 -0
- package/dist/contract/webhooks.d.mts +42 -0
- package/dist/contract/webhooks.mjs +53 -0
- package/dist/http/client.d.mts +37 -14
- package/dist/http/client.mjs +52 -14
- package/dist/http/events.d.mts +56 -0
- package/dist/http/events.mjs +102 -0
- package/dist/http/placed.d.mts +36 -0
- package/dist/http/placed.mjs +71 -0
- package/dist/http/schema-errors.mjs +2 -3
- package/dist/http/streamed.d.mts +21 -0
- package/dist/http/streamed.mjs +94 -0
- package/dist/http/watch.mjs +50 -0
- package/dist/mcp/bridge.mjs +283 -0
- package/dist/mcp/client.d.mts +30 -99
- package/dist/mcp/client.mjs +60 -134
- package/dist/mcp/events.mjs +142 -0
- package/dist/mcp/progress.mjs +34 -0
- package/dist/mcp/protocol.mjs +40 -15
- package/dist/mcp/reply.d.mts +79 -0
- package/dist/mcp/reply.mjs +99 -0
- package/dist/mcp/request.d.mts +40 -0
- package/dist/mcp/request.mjs +51 -0
- package/dist/mcp/watch.mjs +115 -0
- package/dist/rpc/watch.mjs +39 -0
- package/dist/stdio/console.mjs +14 -7
- package/dist/testing/memory.d.mts +1 -3
- package/dist/testing/memory.mjs +4 -5
- package/dist/webhook/address.mjs +47 -0
- package/dist/webhook/attempt.mjs +65 -0
- package/dist/webhook/receiver.mjs +67 -0
- package/dist/webhook/signing.mjs +28 -0
- package/dist/webhook/stored.mjs +57 -0
- package/dist/webhook/subscriptions.mjs +342 -0
- package/docs/Action-failures.md +2 -2
- package/docs/Action-streams.md +115 -0
- package/docs/Action.md +58 -124
- package/docs/ActionCli-failures.md +1 -2
- package/docs/ActionCli.md +83 -88
- package/docs/ActionHttp-failures.md +3 -3
- package/docs/ActionHttp.md +90 -70
- package/docs/ActionMcp-failures.md +2 -1
- package/docs/ActionMcp.md +120 -92
- package/docs/ActionRpc-events.md +126 -0
- package/docs/ActionRpc-failures.md +1 -2
- package/docs/ActionRpc.md +108 -79
- package/docs/ActionToolkit-failures.md +1 -2
- package/docs/ActionToolkit.md +33 -90
- package/docs/Authentication-advanced.md +57 -61
- package/docs/Authentication-failures.md +5 -4
- package/docs/Authentication.md +23 -58
- package/docs/Event-failures.md +15 -0
- package/docs/Event.md +281 -0
- package/docs/README.md +51 -82
- package/docs/Testing-failures.md +1 -5
- package/docs/Testing.md +126 -86
- package/docs/Webhook-failures.md +8 -0
- package/docs/Webhook.md +319 -0
- package/docs/setup-failures.md +2 -3
- package/docs/setup.md +32 -53
- package/examples/README.md +12 -37
- package/examples/assistant/README.md +21 -26
- package/examples/assistant/src/agent.ts +66 -24
- package/examples/assistant/src/cli.ts +7 -4
- package/examples/assistant/src/commands.ts +9 -4
- package/examples/assistant/src/identity/Identity.ts +5 -4
- package/examples/assistant/src/identity/authorize.ts +13 -5
- package/examples/assistant/src/identity/handlers.ts +3 -2
- package/examples/assistant/src/identity/permissions.ts +9 -3
- package/examples/assistant/src/platform/tasks-file.ts +15 -11
- package/examples/assistant/src/scripted.ts +7 -4
- package/examples/assistant/src/tasks/Tasks.ts +20 -6
- package/examples/assistant/src/tasks/handlers.ts +9 -5
- package/examples/assistant/src/tasks/store.ts +38 -11
- package/examples/assistant/src/toolkit.ts +11 -7
- package/examples/assistant/test/commands.test.ts +53 -27
- package/examples/assistant/test/identity/identity.test.ts +27 -11
- package/examples/assistant/test/platform/tasks-file.test.ts +39 -23
- package/examples/assistant/test/tasks/tasks.test.ts +62 -34
- package/examples/assistant/test/toolkit.test.ts +104 -75
- package/examples/build-events/README.md +83 -0
- package/examples/build-events/src/Api.ts +27 -0
- package/examples/build-events/src/Rpc.ts +26 -0
- package/examples/build-events/src/builds/Builds.ts +108 -0
- package/examples/build-events/src/builds/events.ts +54 -0
- package/examples/build-events/src/builds/handlers.ts +58 -0
- package/examples/build-events/src/builds/log.ts +30 -0
- package/examples/build-events/src/builds/status.ts +28 -0
- package/examples/build-events/src/builds/store.ts +130 -0
- package/examples/build-events/src/cli.ts +18 -0
- package/examples/build-events/src/commands.ts +32 -0
- package/examples/build-events/src/deploys/Deploys.ts +44 -0
- package/examples/build-events/src/deploys/approvers.ts +55 -0
- package/examples/build-events/src/deploys/events.ts +32 -0
- package/examples/build-events/src/deploys/handlers.ts +38 -0
- package/examples/build-events/src/identity/Identity.ts +29 -0
- package/examples/build-events/src/identity/members.ts +7 -0
- package/examples/build-events/src/identity/verifier.ts +22 -0
- package/examples/build-events/src/notifier/Notices.ts +26 -0
- package/examples/build-events/src/notifier/routes.ts +71 -0
- package/examples/build-events/src/notifier.ts +48 -0
- package/examples/build-events/src/routes.ts +71 -0
- package/examples/build-events/src/server.ts +62 -0
- package/examples/build-events/test/builds/events.test.ts +68 -0
- package/examples/build-events/test/builds/log.test.ts +71 -0
- package/examples/build-events/test/builds/progress.test.ts +57 -0
- package/examples/build-events/test/builds/status.test.ts +42 -0
- package/examples/build-events/test/commands.test.ts +103 -0
- package/examples/build-events/test/deploys/events.test.ts +52 -0
- package/examples/build-events/test/http.test.ts +95 -0
- package/examples/build-events/test/notifier.test.ts +80 -0
- package/examples/build-events/test/routes.test.ts +96 -0
- package/examples/build-events/test/rpc.test.ts +84 -0
- package/examples/build-events/test/support/as.ts +8 -0
- package/examples/build-events/test/support/memory.ts +43 -0
- package/examples/build-events/test/webhooks.test.ts +143 -0
- package/examples/kitchen-sink/README.md +178 -166
- package/examples/kitchen-sink/src/Actions.ts +11 -3
- package/examples/kitchen-sink/src/Api.ts +12 -6
- package/examples/kitchen-sink/src/Rpc.ts +7 -5
- package/examples/kitchen-sink/src/admin/Admin.ts +21 -10
- package/examples/kitchen-sink/src/admin/authenticate.ts +8 -4
- package/examples/kitchen-sink/src/admin/authorize.ts +13 -5
- package/examples/kitchen-sink/src/admin/grants.ts +5 -3
- package/examples/kitchen-sink/src/admin/handlers.ts +9 -5
- package/examples/kitchen-sink/src/agent.ts +14 -6
- package/examples/kitchen-sink/src/assistant/Assistant.ts +21 -15
- package/examples/kitchen-sink/src/assistant/conversations.ts +14 -9
- package/examples/kitchen-sink/src/assistant/demo-model.ts +2 -2
- package/examples/kitchen-sink/src/assistant/handlers.ts +42 -22
- package/examples/kitchen-sink/src/attachments/Attachments.ts +6 -6
- package/examples/kitchen-sink/src/attachments/download.ts +7 -6
- package/examples/kitchen-sink/src/attachments/handlers.ts +9 -4
- package/examples/kitchen-sink/src/attachments/store.ts +25 -18
- package/examples/kitchen-sink/src/browser.ts +10 -4
- package/examples/kitchen-sink/src/cli.ts +28 -12
- package/examples/kitchen-sink/src/config.ts +1 -1
- package/examples/kitchen-sink/src/identity/Identity.ts +24 -10
- package/examples/kitchen-sink/src/identity/authenticate.ts +19 -11
- package/examples/kitchen-sink/src/identity/authorize.ts +14 -4
- package/examples/kitchen-sink/src/identity/directory.ts +16 -7
- package/examples/kitchen-sink/src/identity/handlers.ts +1 -0
- package/examples/kitchen-sink/src/identity/members.ts +7 -2
- package/examples/kitchen-sink/src/identity/quota.ts +23 -20
- package/examples/kitchen-sink/src/issues/Issues.ts +91 -15
- package/examples/kitchen-sink/src/issues/assistant.ts +4 -2
- package/examples/kitchen-sink/src/issues/events.ts +46 -0
- package/examples/kitchen-sink/src/issues/export.ts +35 -0
- package/examples/kitchen-sink/src/issues/guide.ts +4 -3
- package/examples/kitchen-sink/src/issues/handlers.ts +20 -7
- package/examples/kitchen-sink/src/issues/store.ts +156 -67
- package/examples/kitchen-sink/src/issues/write-limit.ts +44 -18
- package/examples/kitchen-sink/src/memory.ts +11 -2
- package/examples/kitchen-sink/src/ops.ts +10 -5
- package/examples/kitchen-sink/src/request-policy.ts +25 -9
- package/examples/kitchen-sink/src/routes.ts +67 -27
- package/examples/kitchen-sink/src/sdk.ts +22 -12
- package/examples/kitchen-sink/src/seed.ts +15 -9
- package/examples/kitchen-sink/src/server.ts +24 -10
- package/examples/kitchen-sink/src/stdio.ts +9 -3
- package/examples/kitchen-sink/src/workspaces/Workspaces.ts +10 -7
- package/examples/kitchen-sink/src/workspaces/handlers.ts +3 -2
- package/examples/kitchen-sink/src/workspaces/registry.ts +16 -10
- package/examples/kitchen-sink/src/workspaces/tenant.ts +12 -5
- package/examples/kitchen-sink/test/admin/admin.test.ts +38 -23
- package/examples/kitchen-sink/test/assistant/assistant.test.ts +471 -299
- package/examples/kitchen-sink/test/attachments/attachments.test.ts +135 -94
- package/examples/kitchen-sink/test/identity/identity.test.ts +110 -82
- package/examples/kitchen-sink/test/identity/session.test.ts +65 -43
- package/examples/kitchen-sink/test/issues/assistant.test.ts +50 -31
- package/examples/kitchen-sink/test/issues/events.test.ts +273 -0
- package/examples/kitchen-sink/test/issues/export.test.ts +120 -0
- package/examples/kitchen-sink/test/issues/issues.test.ts +105 -75
- package/examples/kitchen-sink/test/request-policy.test.ts +130 -33
- package/examples/kitchen-sink/test/routes.test.ts +102 -57
- package/examples/kitchen-sink/test/support/as.ts +9 -0
- package/examples/kitchen-sink/test/support/scripted.ts +6 -5
- package/examples/kitchen-sink/test/support/services.ts +17 -0
- package/examples/live-rpc/README.md +33 -35
- package/examples/live-rpc/src/Rpc.ts +9 -5
- package/examples/live-rpc/src/browser.ts +39 -11
- package/examples/live-rpc/src/chat/Chat.ts +30 -16
- package/examples/live-rpc/src/chat/authorize.ts +2 -1
- package/examples/live-rpc/src/chat/events.ts +74 -0
- package/examples/live-rpc/src/chat/handlers.ts +13 -5
- package/examples/live-rpc/src/chat/room.ts +9 -5
- package/examples/live-rpc/src/chat/store.ts +51 -14
- package/examples/live-rpc/src/client.ts +22 -5
- package/examples/live-rpc/src/identity/Identity.ts +3 -3
- package/examples/live-rpc/src/identity/verifier.ts +8 -4
- package/examples/live-rpc/src/page.ts +58 -12
- package/examples/live-rpc/src/routes.ts +14 -10
- package/examples/live-rpc/src/server.ts +15 -5
- package/examples/live-rpc/test/browser.test.ts +127 -50
- package/examples/live-rpc/test/chat/chat.test.ts +215 -23
- package/examples/live-rpc/test/routes.test.ts +130 -46
- package/examples/live-rpc/test/server.test.ts +94 -33
- package/examples/mcp-tools/README.md +24 -38
- package/examples/mcp-tools/src/platform/fake-farm.ts +63 -24
- package/examples/mcp-tools/src/platform/print-farm.ts +59 -29
- package/examples/mcp-tools/src/printers/Printers.ts +18 -7
- package/examples/mcp-tools/src/printers/farm.ts +15 -5
- package/examples/mcp-tools/src/printers/handlers.ts +12 -6
- package/examples/mcp-tools/src/routes.ts +8 -6
- package/examples/mcp-tools/src/server.ts +12 -5
- package/examples/mcp-tools/src/stdio.ts +3 -2
- package/examples/mcp-tools/test/printers/printers.test.ts +132 -89
- package/examples/mcp-tools/test/routes.test.ts +140 -81
- package/examples/notes-service/README.md +30 -45
- package/examples/notes-service/src/Api.ts +1 -0
- package/examples/notes-service/src/browser.ts +15 -14
- package/examples/notes-service/src/cli.ts +8 -3
- package/examples/notes-service/src/commands.ts +46 -20
- package/examples/notes-service/src/identity/Identity.ts +2 -2
- package/examples/notes-service/src/identity/authorize.ts +6 -2
- package/examples/notes-service/src/identity/handlers.ts +3 -2
- package/examples/notes-service/src/identity/users.ts +2 -1
- package/examples/notes-service/src/identity/verifier.ts +12 -6
- package/examples/notes-service/src/notes/Notes.ts +46 -22
- package/examples/notes-service/src/notes/handlers.ts +18 -9
- package/examples/notes-service/src/notes/store.ts +70 -43
- package/examples/notes-service/src/routes.ts +7 -5
- package/examples/notes-service/src/server.ts +12 -5
- package/examples/notes-service/src/status/Status.ts +1 -1
- package/examples/notes-service/src/status/handlers.ts +5 -3
- package/examples/notes-service/src/stdio.ts +7 -3
- package/examples/notes-service/src/worker.ts +6 -3
- package/examples/notes-service/test/commands.test.ts +164 -91
- package/examples/notes-service/test/notes/as.ts +3 -1
- package/examples/notes-service/test/notes/idempotency.test.ts +97 -67
- package/examples/notes-service/test/notes/in-process.test.ts +26 -15
- package/examples/notes-service/test/notes/notes.test.ts +49 -31
- package/examples/notes-service/test/routes.test.ts +106 -71
- package/examples/notes-service/test/worker.test.ts +21 -13
- package/examples/quickstart/README.md +2 -6
- package/examples/quickstart/src/Api.ts +1 -0
- package/examples/quickstart/src/client.ts +6 -3
- package/examples/quickstart/src/greeting/Greeting.ts +1 -1
- package/examples/quickstart/src/greeting/handlers.ts +5 -2
- package/examples/quickstart/src/routes.ts +3 -2
- package/examples/quickstart/src/server.ts +6 -2
- package/examples/quickstart/test/routes.test.ts +3 -2
- package/package.json +19 -17
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
# kitchen-sink
|
|
2
2
|
|
|
3
|
-
The reference application: one multi-tenant issue tracker that uses every module of the library
|
|
4
|
-
and nearly every option. Members of a workspace file, discuss and close issues, and attach
|
|
5
|
-
screenshots, over HTTP, MCP, Effect RPC, a CLI and an assistant, in process and behind a route.
|
|
6
|
-
Operators suspend workspaces on a second port, or from a console on the host.
|
|
3
|
+
The reference application: one multi-tenant issue tracker that uses every module of the library and nearly every option. Members of a workspace file, discuss and close issues, and attach screenshots, over HTTP, MCP, Effect RPC, a CLI and an assistant, in process and behind a route. Operators suspend workspaces on a second port, or from a console on the host.
|
|
7
4
|
|
|
8
5
|
The [index](#index) maps each export and option to the file that shows it.
|
|
9
6
|
|
|
10
7
|
## Run it
|
|
11
8
|
|
|
12
|
-
From the repository root, after `vp install` (from an installed package, see
|
|
13
|
-
[Run one](../README.md#run-one)):
|
|
9
|
+
From the repository root, after `vp install` (from an installed package, see [Run one](../README.md#run-one)):
|
|
14
10
|
|
|
15
11
|
```sh
|
|
16
12
|
node --import tsx examples/kitchen-sink/src/server.ts # members on 127.0.0.1:3000, operators on :3001
|
|
@@ -22,6 +18,8 @@ node --import tsx examples/kitchen-sink/src/cli.ts list-issues -n 5
|
|
|
22
18
|
node --import tsx examples/kitchen-sink/src/cli.ts get-issue ACME-1
|
|
23
19
|
echo "It crashes on an empty draft" | node --import tsx examples/kitchen-sink/src/cli.ts create-issue --title Crash
|
|
24
20
|
node --import tsx examples/kitchen-sink/src/cli.ts ask-assistant --prompt "Close what is done." # answers with a call to approve
|
|
21
|
+
node --import tsx examples/kitchen-sink/src/cli.ts export-issues # each issue as it arrives, with progress on stderr
|
|
22
|
+
node --import tsx examples/kitchen-sink/src/cli.ts watch issue.changed # each change, until stopped
|
|
25
23
|
|
|
26
24
|
# The admin port takes an operator key, not a member's token.
|
|
27
25
|
curl -s 127.0.0.1:3001/admin/suspendWorkspace -H 'Content-Type: application/json' \
|
|
@@ -33,25 +31,19 @@ node --import tsx examples/kitchen-sink/src/agent.ts # the assis
|
|
|
33
31
|
vp test examples/kitchen-sink
|
|
34
32
|
```
|
|
35
33
|
|
|
36
|
-
`HOST`, `PORT`, `ADMIN_PORT`, `PUBLIC_URL` and `MCP_ORIGIN` configure the server; `TRACKER_URL`
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
|
43
|
-
|
|
|
44
|
-
| `
|
|
45
|
-
| `
|
|
46
|
-
| `
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
| `X-Operator-Key: ops-key` | operator `ops` | list, suspend and resume workspaces |
|
|
50
|
-
| `X-Operator-Key: support-key` | operator `support` | list workspaces |
|
|
51
|
-
|
|
52
|
-
A bearer request names its workspace in `X-Workspace: acme`. `kay` (token `kay`, session
|
|
53
|
-
`kay-at-acme`) is a member of acme granted no scope yet. The session cookie also opens
|
|
54
|
-
`GET /attachments/<id>`, the image for a page of the web app; a token holder calls `getAttachment`.
|
|
34
|
+
`HOST`, `PORT`, `ADMIN_PORT`, `PUBLIC_URL` and `MCP_ORIGIN` configure the server; `TRACKER_URL` points the CLI and the seed at it. `stdio.ts` is an MCP server for a local agent to start as a subprocess. `sdk.ts` and `browser.ts` are imported by client code, not run. The OpenAPI document is at `/api/v1/openapi.json`, Swagger UI at `/docs`, the MCP endpoint at `/mcp`, the socket at `/rpc`.
|
|
35
|
+
|
|
36
|
+
| Credential | Who | May |
|
|
37
|
+
| --- | --- | --- |
|
|
38
|
+
| `Authorization: Bearer ada` | ada, in acme or globex | read and write in acme, read in globex |
|
|
39
|
+
| `Authorization: Bearer linus` | linus, in acme | read |
|
|
40
|
+
| `Authorization: Bearer grace` | grace, in globex | read and write |
|
|
41
|
+
| `Cookie: tracker_session=ada-at-acme` | ada in acme, on `/rpc` | read and write |
|
|
42
|
+
| `Cookie: tracker_session=grace-at-globex` | grace in globex, on `/rpc` | read and write |
|
|
43
|
+
| `X-Operator-Key: ops-key` | operator `ops` | list, suspend and resume workspaces |
|
|
44
|
+
| `X-Operator-Key: support-key` | operator `support` | list workspaces |
|
|
45
|
+
|
|
46
|
+
A bearer request names its workspace in `X-Workspace: acme`. `kay` (token `kay`, session `kay-at-acme`) is a member of acme granted no scope yet. The session cookie also opens `GET /attachments/<id>`, the image for a page of the web app; a token holder calls `getAttachment`.
|
|
55
47
|
|
|
56
48
|
## Layout
|
|
57
49
|
|
|
@@ -71,10 +63,12 @@ src/
|
|
|
71
63
|
│ ├── tenant.ts Tenant, and the router middleware that resolves it per request
|
|
72
64
|
│ └── handlers.ts
|
|
73
65
|
├── issues/
|
|
74
|
-
│ ├── Issues.ts contract: schemas, errors, five actions
|
|
75
|
-
│ ├── store.ts IssueStore, scoped by workspace
|
|
76
|
-
│ ├── write-limit.ts the write
|
|
66
|
+
│ ├── Issues.ts contract: schemas, errors, five actions, exportIssues, issue.changed
|
|
67
|
+
│ ├── store.ts IssueStore, scoped by workspace, and its changes
|
|
68
|
+
│ ├── write-limit.ts the write and export limits, wrapped around handlers
|
|
77
69
|
│ ├── handlers.ts Action.implement over the store
|
|
70
|
+
│ ├── export.ts exportIssues: a stream, with progress
|
|
71
|
+
│ ├── events.ts issue.changed: a log source fed by the store's changes
|
|
78
72
|
│ ├── guide.ts a native MCP resource and prompt
|
|
79
73
|
│ └── assistant.ts the actions as a model's Toolkit, with approval
|
|
80
74
|
├── assistant/ the model loop, served: a turn per request
|
|
@@ -112,9 +106,10 @@ src/
|
|
|
112
106
|
test/
|
|
113
107
|
├── routes.test.ts the host's surfaces: one port over HTTP and MCP, then both ports
|
|
114
108
|
├── request-policy.test.ts raw requests to each port as a web handler
|
|
115
|
-
├── issues/ in process, with Action.client; the assistant's tools
|
|
109
|
+
├── issues/ in process, with Action.client; the assistant's tools; the export over
|
|
110
|
+
│ HTTP and RPC; issue.changed in process and by webhook
|
|
116
111
|
├── assistant/ the assistant over HTTP, with a scripted model
|
|
117
|
-
├── support/ the scripted model the
|
|
112
|
+
├── support/ the scripted model; the services the public routes need in memory
|
|
118
113
|
├── identity/ what authentication adds: tokens over HTTP, sessions over RPC
|
|
119
114
|
├── attachments/ images over HTTP and MCP; the download route
|
|
120
115
|
└── admin/ the operators' grants; the trusted operator
|
|
@@ -122,175 +117,192 @@ test/
|
|
|
122
117
|
|
|
123
118
|
## Where to look
|
|
124
119
|
|
|
125
|
-
| To see
|
|
126
|
-
|
|
|
127
|
-
| How one request is authenticated, placed in a tenant, authorized
|
|
128
|
-
| Two audiences on two ports over one set of services
|
|
129
|
-
| Which actions each surface serves, and why one is no tool
|
|
130
|
-
| A limit before decoding and a limit in the handlers
|
|
131
|
-
| An image for a model and a client (an action), and for a page (a route) | `src/attachments/`
|
|
132
|
-
| A caller the host names itself
|
|
133
|
-
| A model loop behind a route, approvals answered in a later request
|
|
134
|
-
| What to test in process and what over the wire
|
|
120
|
+
| To see | Read |
|
|
121
|
+
| --- | --- |
|
|
122
|
+
| How one request is authenticated, placed in a tenant, authorized | `src/identity/authenticate.ts`, `src/workspaces/tenant.ts`, `src/identity/authorize.ts`, `src/routes.ts` |
|
|
123
|
+
| Two audiences on two ports over one set of services | `src/server.ts`, `src/routes.ts`, `test/routes.test.ts` |
|
|
124
|
+
| Which actions each surface serves, and why one is no tool | `src/Actions.ts` |
|
|
125
|
+
| A limit before decoding and a limit in the handlers | `src/identity/quota.ts`, `src/issues/write-limit.ts` |
|
|
126
|
+
| An image for a model and a client (an action), and for a page (a route) | `src/attachments/` |
|
|
127
|
+
| A caller the host names itself | `src/stdio.ts`, `src/ops.ts`, `src/agent.ts` |
|
|
128
|
+
| A model loop behind a route, approvals answered in a later request | `src/assistant/handlers.ts`, `src/routes.ts` |
|
|
129
|
+
| What to test in process and what over the wire | `test/issues/issues.test.ts`, `test/routes.test.ts` |
|
|
135
130
|
|
|
136
131
|
## Index
|
|
137
132
|
|
|
138
|
-
Each export and option the example uses, and where. A symbol in parentheses is the name to
|
|
139
|
-
search for in the file.
|
|
133
|
+
Each export and option the example uses, and where. A symbol in parentheses is the name to search for in the file.
|
|
140
134
|
|
|
141
135
|
### Action
|
|
142
136
|
|
|
143
|
-
| Export or option
|
|
144
|
-
|
|
|
145
|
-
| `make`: `input`, `success`, `error`, `readOnly`
|
|
146
|
-
| `make`: `caller: Action.Anyone`, a public action
|
|
147
|
-
| `make`: `caller`, an identity service
|
|
148
|
-
| `make`: `mcp` (`title`, hints)
|
|
149
|
-
| `make`: no `input`
|
|
150
|
-
| `make`: an optional and a defaulted input field
|
|
151
|
-
| `make`: errors with `httpApiStatus`
|
|
152
|
-
| `make`: a shared error list
|
|
153
|
-
| `make`: an option bundle, spread
|
|
154
|
-
| `
|
|
155
|
-
| `
|
|
156
|
-
| `
|
|
157
|
-
| `
|
|
158
|
-
| `implement`:
|
|
159
|
-
|
|
|
160
|
-
|
|
|
161
|
-
|
|
|
162
|
-
|
|
|
163
|
-
| `
|
|
164
|
-
| `
|
|
165
|
-
| `
|
|
166
|
-
| `
|
|
167
|
-
| `
|
|
168
|
-
| `
|
|
169
|
-
| `
|
|
170
|
-
| `
|
|
137
|
+
| Export or option | File |
|
|
138
|
+
| --- | --- |
|
|
139
|
+
| `make`: `input`, `success`, `error`, `readOnly` | `src/issues/Issues.ts` |
|
|
140
|
+
| `make`: `caller: Action.Anyone`, a public action | `src/workspaces/Workspaces.ts` (`GetStatus`) |
|
|
141
|
+
| `make`: `caller`, an identity service | `src/identity/Identity.ts` (`CurrentMember`, `WhoAmI`) |
|
|
142
|
+
| `make`: `mcp` (`title`, hints) | `src/issues/Issues.ts` (`CreateIssue`, `CloseIssue`) |
|
|
143
|
+
| `make`: no `input` | `src/identity/Identity.ts` (`WhoAmI`) |
|
|
144
|
+
| `make`: an optional and a defaulted input field | `src/issues/Issues.ts` (`ListIssues`) |
|
|
145
|
+
| `make`: errors with `httpApiStatus` | `src/issues/Issues.ts` (`IssueNotFound`, `RateLimited`) |
|
|
146
|
+
| `make`: a shared error list | `src/issues/Issues.ts` (`IssueWriteErrors`), `src/attachments/Attachments.ts` |
|
|
147
|
+
| `make`: an option bundle, spread | `src/issues/Issues.ts` (`change`), `src/admin/Admin.ts` (`onWorkspace`) |
|
|
148
|
+
| `make`: `progress`, and `Stream`, a success answering a stream | `src/issues/Issues.ts` (`ExportIssues`) |
|
|
149
|
+
| A handler returning a `Stream`, reporting progress | `src/issues/export.ts` |
|
|
150
|
+
| `Image`, in a success and in an input | `src/attachments/Attachments.ts` |
|
|
151
|
+
| `byName` | `src/issues/guide.ts` (`tools`) |
|
|
152
|
+
| `implement`: one action, a plain handler | `src/identity/handlers.ts` |
|
|
153
|
+
| `implement`: one action, a builder | `src/workspaces/handlers.ts` |
|
|
154
|
+
| `implement`: several actions sharing a builder | `src/issues/handlers.ts` |
|
|
155
|
+
| Startup services and per-request services | `src/issues/handlers.ts` |
|
|
156
|
+
| A rate limit in handlers, shared by several | `src/issues/write-limit.ts`, `src/issues/handlers.ts`, `src/attachments/handlers.ts` |
|
|
157
|
+
| `implement`: `authorize`, a rule from `readOnly` | `src/identity/authorize.ts` |
|
|
158
|
+
| `implement`: `authorize`, an Effect building it | `src/admin/authorize.ts` |
|
|
159
|
+
| `allowAll` | `src/identity/handlers.ts` |
|
|
160
|
+
| `Forbidden` with `scopes`, and without | `src/identity/authorize.ts`, `src/admin/authorize.ts` |
|
|
161
|
+
| `Unauthenticated` | `src/identity/directory.ts`, `src/admin/authenticate.ts` |
|
|
162
|
+
| `InvalidInput` with `issues`, from a handler | `src/attachments/handlers.ts` |
|
|
163
|
+
| `layer`, one builder run for an implementation two ports serve | `src/routes.ts` (`builders`), `src/server.ts`, `test/routes.test.ts` |
|
|
164
|
+
| `client` | `src/agent.ts`, `test/issues/issues.test.ts` |
|
|
165
|
+
| `client`: `actions` | `test/issues/issues.test.ts` |
|
|
166
|
+
| `Any`, an authorizer's parameter | `src/identity/authorize.ts` |
|
|
171
167
|
|
|
172
168
|
### Authentication
|
|
173
169
|
|
|
174
|
-
| Export or option
|
|
175
|
-
|
|
|
176
|
-
| `make`, Bearer, with a declared `error` (503)
|
|
177
|
-
| `make`: `security`, a cookie, for the same identity
|
|
178
|
-
| `make`: `security`, an API key in a header
|
|
179
|
-
| `layer`, a verifier built from startup services
|
|
180
|
-
| `layer`, a plain verifier
|
|
181
|
-
| `layer`: `protectedResource`, an Effect over `Config`
|
|
182
|
-
| `ProtectedResource`
|
|
183
|
-
| A request service the verifier reads, and its order
|
|
184
|
-
| `protect`, a route of the host's own, by the cookie descriptor | `src/attachments/download.ts`
|
|
185
|
-
| A trusted identity no verifier returns
|
|
186
|
-
| A verifier's declared error over MCP
|
|
187
|
-
| A test replacing a verifier's service
|
|
170
|
+
| Export or option | File |
|
|
171
|
+
| --- | --- |
|
|
172
|
+
| `make`, Bearer, with a declared `error` (503) | `src/identity/Identity.ts` (`Login`, `IssuerUnavailable`) |
|
|
173
|
+
| `make`: `security`, a cookie, for the same identity | `src/identity/Identity.ts` (`Session`) |
|
|
174
|
+
| `make`: `security`, an API key in a header | `src/admin/Admin.ts` (`OperatorKey`) |
|
|
175
|
+
| `layer`, a verifier built from startup services | `src/identity/authenticate.ts` |
|
|
176
|
+
| `layer`, a plain verifier | `src/admin/authenticate.ts` |
|
|
177
|
+
| `layer`: `protectedResource`, an Effect over `Config` | `src/identity/authenticate.ts` (`protectedResource`) |
|
|
178
|
+
| `ProtectedResource` | `src/identity/authenticate.ts` |
|
|
179
|
+
| A request service the verifier reads, and its order | `src/workspaces/tenant.ts`, `src/routes.ts` (`publicRoutes`) |
|
|
180
|
+
| `protect`, a route of the host's own, by the cookie descriptor | `src/attachments/download.ts` |
|
|
181
|
+
| A trusted identity no verifier returns | `src/admin/Admin.ts`, `src/admin/authenticate.ts`, `src/ops.ts` |
|
|
182
|
+
| A verifier's declared error over MCP | `test/identity/identity.test.ts` |
|
|
183
|
+
| A test replacing a verifier's service | `test/identity/identity.test.ts` (`issuerDown`) |
|
|
184
|
+
| `make`: `principal`, one subscriber per workspace | `src/identity/Identity.ts` (`Login`) |
|
|
185
|
+
|
|
186
|
+
### Event
|
|
187
|
+
|
|
188
|
+
| Export or option | File |
|
|
189
|
+
| --- | --- |
|
|
190
|
+
| `make`: `description`, `input` that filters and shapes, `payload`, `caller` | `src/issues/Issues.ts` (`IssueChanged`) |
|
|
191
|
+
| `implement`: a log source fed by a keyed `emit`, `key` reading the caller, `match`, `transform`, `maxAge` | `src/issues/events.ts` |
|
|
192
|
+
| `implement`: `authorize`, one rule for actions and events | `src/identity/authorize.ts` |
|
|
193
|
+
| `watch` in process, `Forbidden` for a subscriber | `test/issues/events.test.ts` |
|
|
194
|
+
|
|
195
|
+
### Webhook
|
|
196
|
+
|
|
197
|
+
| Export or option | File |
|
|
198
|
+
| --- | --- |
|
|
199
|
+
| `layer`, for MCP and HTTP alike | `src/routes.ts` (`publicRoutes`) |
|
|
200
|
+
| The `HttpClient` and `Dns` delivery needs | `src/server.ts`, `test/support/services.ts` |
|
|
201
|
+
| A delivery, as the subscriber sees it | `test/issues/events.test.ts` |
|
|
188
202
|
|
|
189
203
|
### ActionHttp
|
|
190
204
|
|
|
191
|
-
| Export or option
|
|
192
|
-
|
|
|
193
|
-
| `make`: `prefix`, `authentication`, `error`
|
|
194
|
-
| A second binding for a second identity
|
|
195
|
-
| One action in two bindings
|
|
196
|
-
| `layer`: `actions`
|
|
197
|
-
| `layer`: `middleware`
|
|
198
|
-
| Global router middleware, before authentication and discovery
|
|
199
|
-
| `Http.api`, `Http.prefix`: the OpenAPI document and Swagger UI | `src/routes.ts` (`documentation`)
|
|
200
|
-
| A request body limit
|
|
201
|
-
| Two `HttpRouter.serve`, what they share provided outside both
|
|
202
|
-
| `client`: `baseUrl`, `transformClient`
|
|
203
|
-
| `fetchClient`
|
|
204
|
-
| Declared errors handled by tag
|
|
205
|
+
| Export or option | File |
|
|
206
|
+
| --- | --- |
|
|
207
|
+
| `make`: `prefix`, `authentication`, `error` | `src/Api.ts` (`Http`) |
|
|
208
|
+
| A second binding for a second identity | `src/Api.ts` (`AdminHttp`) |
|
|
209
|
+
| One action in two bindings | `src/Api.ts` (`GetStatus`), `src/routes.ts` (`adminRoutes`) |
|
|
210
|
+
| `layer`: `actions` | `src/routes.ts` (`api`) |
|
|
211
|
+
| `layer`: `middleware` | `src/routes.ts` (`api`), `src/identity/quota.ts` (`HttpQuota`) |
|
|
212
|
+
| Global router middleware, before authentication and discovery | `src/request-policy.ts` (`requestPolicy`), `src/routes.ts` (`publicRoutes`) |
|
|
213
|
+
| `Http.api`, `Http.prefix`: the OpenAPI document and Swagger UI | `src/routes.ts` (`documentation`) |
|
|
214
|
+
| A request body limit | `src/server.ts` |
|
|
215
|
+
| Two `HttpRouter.serve`, what they share provided outside both | `src/server.ts` |
|
|
216
|
+
| `client`: `baseUrl`, `transformClient` | `src/seed.ts` |
|
|
217
|
+
| `fetchClient` | `src/sdk.ts` |
|
|
218
|
+
| Declared errors handled by tag | `src/seed.ts`, `src/sdk.ts` |
|
|
219
|
+
| An event at `events/<name>`, polled or streamed | `src/Api.ts` |
|
|
220
|
+
| `layer`: an event given to one layer of a binding | `src/routes.ts` (`events`, `api`) |
|
|
221
|
+
| A stream action's route and method, with `onProgress` | `test/issues/export.test.ts` |
|
|
222
|
+
| An event's `subscribe` route | `test/issues/events.test.ts` |
|
|
205
223
|
|
|
206
224
|
### ActionMcp
|
|
207
225
|
|
|
208
|
-
| Export or option
|
|
209
|
-
|
|
|
210
|
-
| `layerHttp`, public and protected tools together | `src/routes.ts` (`mcp`)
|
|
211
|
-
| `layerHttp`: `authentication`, `instructions`
|
|
212
|
-
| `layerHttp`: `actions`, one action left off
|
|
213
|
-
| `layerHttp`: `allowedOrigins`
|
|
214
|
-
| `layerHttp`: `features`, a resource and a prompt | `src/issues/guide.ts`
|
|
215
|
-
| CORS for a browser MCP client
|
|
216
|
-
| `runStdio`, the host naming the caller
|
|
217
|
-
| An image block from a media field
|
|
218
|
-
| `client`: `transformClient`
|
|
219
|
-
| `client`, decoding an image
|
|
220
|
-
| `client`: `authentication`, a verifier's error
|
|
221
|
-
| `request`: `headers`, `url`
|
|
226
|
+
| Export or option | File |
|
|
227
|
+
| --- | --- |
|
|
228
|
+
| `layerHttp`, public and protected tools together | `src/routes.ts` (`mcp`) |
|
|
229
|
+
| `layerHttp`: `authentication`, `instructions` | `src/routes.ts` (`mcp`) |
|
|
230
|
+
| `layerHttp`: `actions`, one action left off | `src/routes.ts` (`mcp`), `src/Actions.ts` (`Tools`) |
|
|
231
|
+
| `layerHttp`: `allowedOrigins` | `src/routes.ts` (`mcp`), `test/routes.test.ts` |
|
|
232
|
+
| `layerHttp`: `features`, a resource and a prompt | `src/issues/guide.ts` |
|
|
233
|
+
| CORS for a browser MCP client | `src/request-policy.ts` (`cors`) |
|
|
234
|
+
| `runStdio`, the host naming the caller | `src/stdio.ts` |
|
|
235
|
+
| An image block from a media field | `src/attachments/Attachments.ts` (`GetAttachment`) |
|
|
236
|
+
| `client`: `transformClient` | `test/routes.test.ts` |
|
|
237
|
+
| `client`, decoding an image | `test/attachments/attachments.test.ts` |
|
|
238
|
+
| `client`: `authentication`, a verifier's error | `test/identity/identity.test.ts` |
|
|
239
|
+
| `request`: `headers`, `url` | `test/attachments/attachments.test.ts`, `test/routes.test.ts` |
|
|
240
|
+
| `layerHttp`: an event, polled, streamed or by webhook | `src/routes.ts` (`mcp`) |
|
|
222
241
|
|
|
223
242
|
### ActionRpc
|
|
224
243
|
|
|
225
|
-
| Export or option
|
|
226
|
-
|
|
|
227
|
-
| `make`: `authentication`, `error` | `src/Rpc.ts`
|
|
228
|
-
| `layer`: `middleware`
|
|
229
|
-
| A WebSocket protocol
|
|
230
|
-
| `client`, over a WebSocket
|
|
231
|
-
| A credential per message
|
|
244
|
+
| Export or option | File |
|
|
245
|
+
| --- | --- |
|
|
246
|
+
| `make`: `authentication`, `error` | `src/Rpc.ts` |
|
|
247
|
+
| `layer`: `middleware` | `src/routes.ts` (`rpc`), `src/identity/quota.ts` (`RpcQuota`) |
|
|
248
|
+
| A WebSocket protocol | `src/server.ts` (`socket`) |
|
|
249
|
+
| `client`, over a WebSocket | `src/browser.ts` |
|
|
250
|
+
| A credential per message | `test/identity/session.test.ts` (`as`) |
|
|
251
|
+
| An event as a stream rpc | `src/Rpc.ts` |
|
|
252
|
+
| A stream action's method | `test/issues/export.test.ts` |
|
|
232
253
|
|
|
233
254
|
### ActionToolkit
|
|
234
255
|
|
|
235
|
-
| Export or option
|
|
236
|
-
|
|
|
237
|
-
| `make`: `actions`, `needsApproval` (a boolean rule)
|
|
238
|
-
| `toolkit` given to `LanguageModel`
|
|
239
|
-
| `layer`, and the caller per turn
|
|
240
|
-
| `toolkit` and the model yielded in a builder
|
|
241
|
-
| `layer` provided to the routes
|
|
242
|
-
| An approval answered in a later request (`openApprovals`) | `src/assistant/handlers.ts`
|
|
243
|
-
| `tools.handle`, a call made by hand
|
|
256
|
+
| Export or option | File |
|
|
257
|
+
| --- | --- |
|
|
258
|
+
| `make`: `actions`, `needsApproval` (a boolean rule) | `src/issues/assistant.ts` |
|
|
259
|
+
| `toolkit` given to `LanguageModel` | `src/issues/assistant.ts` (`triage`) |
|
|
260
|
+
| `layer`, and the caller per turn | `src/agent.ts` |
|
|
261
|
+
| `toolkit` and the model yielded in a builder | `src/assistant/handlers.ts` |
|
|
262
|
+
| `layer` provided to the routes | `src/routes.ts` (`assistantTools`) |
|
|
263
|
+
| An approval answered in a later request (`openApprovals`) | `src/assistant/handlers.ts` |
|
|
264
|
+
| `tools.handle`, a call made by hand | `test/issues/assistant.test.ts` |
|
|
244
265
|
|
|
245
266
|
### ActionCli
|
|
246
267
|
|
|
247
|
-
| Export or option
|
|
248
|
-
|
|
|
249
|
-
| `remote`: `name`, `commands`, `client`
|
|
250
|
-
| `commands`: `stdin`, `positional`, `aliases`, `render`, `name`, `description` | `src/cli.ts`
|
|
251
|
-
| A client from `Config`, its credentials optional
|
|
252
|
-
| `make`, with a trusted identity the host supplies
|
|
253
|
-
| `logToStderr`
|
|
268
|
+
| Export or option | File |
|
|
269
|
+
| --- | --- |
|
|
270
|
+
| `remote`: `name`, `commands`, `client` | `src/cli.ts` |
|
|
271
|
+
| `commands`: `stdin`, `positional`, `aliases`, `render`, `name`, `description` | `src/cli.ts` |
|
|
272
|
+
| A client from `Config`, its credentials optional | `src/cli.ts` |
|
|
273
|
+
| `make`, with a trusted identity the host supplies | `src/ops.ts` |
|
|
274
|
+
| `logToStderr` | `src/cli.ts`, `src/ops.ts`, `src/stdio.ts` |
|
|
275
|
+
| `render` of each element of a stream action | `src/cli.ts` (`exportIssues`) |
|
|
276
|
+
| `watch <event>`, derived from the binding | `src/cli.ts` |
|
|
254
277
|
|
|
255
278
|
### Testing
|
|
256
279
|
|
|
257
|
-
| Export or option
|
|
258
|
-
|
|
|
259
|
-
| `layer(routes)`
|
|
260
|
-
| `layer(routes)`, twice, over shared builders
|
|
261
|
-
| `layer(handler)`, over `HttpRouter.toWebHandler` | `test/request-policy.test.ts`
|
|
262
|
-
| RPC in memory, over Effect's HTTP protocol
|
|
263
|
-
| A service the test and the routes both read
|
|
264
|
-
| A test replacing one service
|
|
265
|
-
| `Action.client`, a caller per call
|
|
266
|
-
| A scripted `LanguageModel`
|
|
267
|
-
| A test replacing the model the routes are given
|
|
268
|
-
| An error's message asserted beside its fields
|
|
280
|
+
| Export or option | File |
|
|
281
|
+
| --- | --- |
|
|
282
|
+
| `layer(routes)` | `test/identity/identity.test.ts` |
|
|
283
|
+
| `layer(routes)`, twice, over shared builders | `test/routes.test.ts` (`shared`) |
|
|
284
|
+
| `layer(handler)`, over `HttpRouter.toWebHandler` | `test/request-policy.test.ts` |
|
|
285
|
+
| RPC in memory, over Effect's HTTP protocol | `test/identity/session.test.ts` |
|
|
286
|
+
| A service the test and the routes both read | `test/identity/session.test.ts` (`served`) |
|
|
287
|
+
| A test replacing one service | `test/identity/identity.test.ts` (`servedWith`) |
|
|
288
|
+
| `Action.client`, a caller per call | `test/issues/issues.test.ts` |
|
|
289
|
+
| A scripted `LanguageModel` | `test/issues/assistant.test.ts`, `test/support/scripted.ts` |
|
|
290
|
+
| A test replacing the model the routes are given | `test/assistant/assistant.test.ts` (`served`) |
|
|
291
|
+
| An error's message asserted beside its fields | `test/issues/issues.test.ts` |
|
|
269
292
|
|
|
270
293
|
## Not shown
|
|
271
294
|
|
|
272
295
|
Left out because this application has no honest place for them:
|
|
273
296
|
|
|
274
|
-
- `Authentication.refusalResponse` and `bearerTokenOf`. They serve a caller the router never
|
|
275
|
-
routes, such as a Node `upgrade` handler. Every caller here is routed: the socket is Effect's
|
|
276
|
-
own WebSocket route, authenticated per message.
|
|
297
|
+
- `Authentication.refusalResponse` and `bearerTokenOf`. They serve a caller the router never routes, such as a Node `upgrade` handler. Every caller here is routed: the socket is Effect's own WebSocket route, authenticated per message.
|
|
277
298
|
- A descriptor with `HttpApiSecurity.basic`, and an API key in the query.
|
|
278
|
-
- `Action.implement` with a plain record of handlers: every implementation of several actions
|
|
279
|
-
|
|
280
|
-
- `ActionCli.command` and `remoteCommand`, one action as one command; `make`'s and `remote`'s
|
|
281
|
-
`actions`. Both CLIs here are aggregates of every action, and the remote one reads its client
|
|
282
|
-
from `Config`. `subcommands` and `toUserError`, a command written by hand:
|
|
283
|
-
[notes-service](../notes-service/) has two.
|
|
299
|
+
- `Action.implement` with a plain record of handlers: every implementation of several actions here has a builder. `implementation.actions`. `mcp._meta`.
|
|
300
|
+
- `ActionCli.command` and `remoteCommand`, one action as one command; `make`'s and `remote`'s `actions`. Both CLIs here are aggregates of every action, and the remote one reads its client from `Config`. `subcommands` and `toUserError`, a command written by hand: [notes-service](../notes-service/) has two.
|
|
284
301
|
- `ActionRpc.layer`'s `actions`, `Rpc.group`, and `ActionRpc.client`'s options.
|
|
285
302
|
- A binding's other fields, `Http.actions`, `Http.error` and `Http.authentication`.
|
|
286
|
-
- `ActionMcp`'s `path`, `description`, `websiteUrl`, `icons`, `extensions`, `allowSubscriptions`
|
|
287
|
-
and `requestScoped` ([notes-service](../notes-service/) has it), and `McpCallError`;
|
|
288
|
-
`fetchClient`'s `fetch`.
|
|
303
|
+
- `ActionMcp`'s `path`, `description`, `websiteUrl`, `icons`, `extensions`, `allowSubscriptions` and `requestScoped` ([notes-service](../notes-service/) has it), and `McpCallError`; `fetchClient`'s `fetch`.
|
|
289
304
|
- `needsApproval` as an Effect reading the caller: the rule here is a boolean of the action.
|
|
290
|
-
- `Action.InvalidInput.fromSchemaError`, the `Action.Refusal` and `Action.BuiltIn` schemas, and the
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
- A
|
|
294
|
-
`McpSchema.McpRequestContext`.
|
|
295
|
-
- A tenant taken from a subdomain. The workspace is a header, so the OAuth resource the server
|
|
296
|
-
publishes is one fixed URL.
|
|
305
|
+
- `Action.InvalidInput.fromSchemaError`, the `Action.Refusal` and `Action.BuiltIn` schemas, and the helper types: `Action.Issue`, `Errors`, `Handlers`, `Client`, `AnyImplementation`, `BuildServices`, `ActionHttp.Client`, `Authentication.Any`.
|
|
306
|
+
- A handler sending MCP notifications through `McpServer.McpServer`, and one reading `McpSchema.McpRequestContext`.
|
|
307
|
+
- An event's `check` source and `subscription`, and a watch's `resume` and `mode`; and `Webhook.delivery`, `layerReceiver` and `persist`: [build-events](../build-events/) has them. No example sets a `subscription`'s `lease` or an occurrence's `timestamp`: the defaults (5 minutes, and when the occurrence arrived) serve both.
|
|
308
|
+
- A tenant taken from a subdomain. The workspace is a header, so the OAuth resource the server publishes is one fixed URL.
|
|
@@ -1,18 +1,26 @@
|
|
|
1
1
|
import { Assistant } from "./assistant/Assistant.js";
|
|
2
2
|
import { AttachImage, GetAttachment } from "./attachments/Attachments.js";
|
|
3
3
|
import { WhoAmI } from "./identity/Identity.js";
|
|
4
|
-
import { Issues } from "./issues/Issues.js";
|
|
4
|
+
import { ExportIssues, Issues } from "./issues/Issues.js";
|
|
5
5
|
import { GetStatus } from "./workspaces/Workspaces.js";
|
|
6
6
|
|
|
7
7
|
// Which actions each surface gets. A contract says nothing about where it is served: each
|
|
8
8
|
// surface takes a list, and these are the lists, built from the contracts themselves.
|
|
9
9
|
|
|
10
10
|
/** What a signed-in member may call: every protected action of the public port. */
|
|
11
|
-
export const MemberActions = [
|
|
11
|
+
export const MemberActions = [
|
|
12
|
+
WhoAmI,
|
|
13
|
+
...Issues,
|
|
14
|
+
ExportIssues,
|
|
15
|
+
AttachImage,
|
|
16
|
+
GetAttachment,
|
|
17
|
+
...Assistant,
|
|
18
|
+
] as const;
|
|
12
19
|
|
|
13
20
|
/**
|
|
14
21
|
* The MCP tools, for the HTTP endpoint and the stdio server alike. `attachImage` is left out:
|
|
15
22
|
* listing it throws, since MCP takes no image as input. So is the assistant: it is a model
|
|
16
|
-
* itself, and its tools are already here.
|
|
23
|
+
* itself, and its tools are already here. So is `exportIssues`: a tool collects its stream
|
|
24
|
+
* whole before answering, every issue of the workspace at once in a model's context.
|
|
17
25
|
*/
|
|
18
26
|
export const Tools = [GetStatus, WhoAmI, ...Issues, GetAttachment] as const;
|
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
import * as ActionHttp from "@gjermundgaraba/effect-actions/ActionHttp";
|
|
2
|
+
|
|
2
3
|
import { MemberActions } from "./Actions.js";
|
|
3
4
|
import { Admin, OperatorKey } from "./admin/Admin.js";
|
|
4
5
|
import { Login, QuotaExceeded } from "./identity/Identity.js";
|
|
6
|
+
import { IssueChanged } from "./issues/Issues.js";
|
|
5
7
|
import { GetStatus } from "./workspaces/Workspaces.js";
|
|
6
8
|
|
|
7
|
-
// The members' HTTP binding: every action at `POST /api/v1/<name
|
|
9
|
+
// The members' HTTP binding: every action at `POST /api/v1/<name>`, and `issue.changed` at
|
|
10
|
+
// `POST /api/v1/events/issue.changed`, polled or held open as a stream. It is plain data and
|
|
8
11
|
// imports no server code, so the server, the CLI, the SDK and a test all import this one value.
|
|
9
12
|
// - `authentication`: how the protected actions' caller proves who it is. `getStatus` is public.
|
|
10
13
|
// - `error`: the quota middleware's, so a client decodes its 429 as a typed `QuotaExceeded`.
|
|
11
|
-
export const Http = ActionHttp.make(
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
export const Http = ActionHttp.make(
|
|
15
|
+
[GetStatus, ...MemberActions, IssueChanged],
|
|
16
|
+
{
|
|
17
|
+
prefix: "/api/v1",
|
|
18
|
+
authentication: Login,
|
|
19
|
+
error: QuotaExceeded,
|
|
20
|
+
}
|
|
21
|
+
);
|
|
16
22
|
|
|
17
23
|
// The operators' binding: other actions, another identity, another descriptor, served on a port
|
|
18
24
|
// of its own.
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import * as ActionRpc from "@gjermundgaraba/effect-actions/ActionRpc";
|
|
2
|
+
|
|
2
3
|
import { MemberActions } from "./Actions.js";
|
|
3
4
|
import { QuotaExceeded, Session } from "./identity/Identity.js";
|
|
5
|
+
import { IssueChanged } from "./issues/Issues.js";
|
|
4
6
|
|
|
5
|
-
// The web app's binding: the members' actions as Effect RPC, one native rpc per action,
|
|
6
|
-
// one WebSocket. Browser-safe, as the HTTP binding is. It
|
|
7
|
-
// same identity: a page proves who it is with its session
|
|
8
|
-
// the socket's upgrade. Its `error` is what the layer's middleware, the quota, fails with.
|
|
9
|
-
export const Rpc = ActionRpc.make(MemberActions, {
|
|
7
|
+
// The web app's binding: the members' actions as Effect RPC, one native rpc per action, and
|
|
8
|
+
// `issue.changed` as a stream rpc, over one WebSocket. Browser-safe, as the HTTP binding is. It
|
|
9
|
+
// names the other descriptor of the same identity: a page proves who it is with its session
|
|
10
|
+
// cookie, which the browser sends on the socket's upgrade. Its `error` is what the layer's middleware, the quota, fails with.
|
|
11
|
+
export const Rpc = ActionRpc.make([...MemberActions, IssueChanged], {
|
|
10
12
|
authentication: Session,
|
|
11
13
|
error: QuotaExceeded,
|
|
12
14
|
});
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { Context, Schema } from "effect";
|
|
2
|
-
import { HttpApiSecurity } from "effect/http-api";
|
|
3
1
|
import * as Action from "@gjermundgaraba/effect-actions/Action";
|
|
4
2
|
import * as Authentication from "@gjermundgaraba/effect-actions/Authentication";
|
|
3
|
+
import { Context, Schema } from "effect";
|
|
4
|
+
import { HttpApiSecurity } from "effect/http-api";
|
|
5
|
+
|
|
5
6
|
import { Workspace, WorkspaceNotFound } from "../workspaces/Workspaces.js";
|
|
6
7
|
|
|
7
8
|
/** What a verified operator key can name. */
|
|
@@ -20,15 +21,20 @@ export interface TrustedOperator {
|
|
|
20
21
|
* The operators' identity, another audience than the members: its own service, its own
|
|
21
22
|
* descriptor, its own port. Typed in two parts, so the trusted one cannot arrive over the wire.
|
|
22
23
|
*/
|
|
23
|
-
export class Operator extends Context.Service<
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
export class Operator extends Context.Service<
|
|
25
|
+
Operator,
|
|
26
|
+
KeyOperator | TrustedOperator
|
|
27
|
+
>()("tracker/Operator") {}
|
|
26
28
|
|
|
27
29
|
// How a remote operator proves it: an API key in a header, a native scheme named by
|
|
28
30
|
// `security`. A key cannot step up, and has no OAuth discovery.
|
|
29
|
-
export const OperatorKey = Authentication.make(
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
export const OperatorKey = Authentication.make(
|
|
32
|
+
"tracker.OperatorKey",
|
|
33
|
+
Operator,
|
|
34
|
+
{
|
|
35
|
+
security: HttpApiSecurity.apiKey({ in: "header", key: "x-operator-key" }),
|
|
36
|
+
}
|
|
37
|
+
);
|
|
32
38
|
|
|
33
39
|
// What the two actions on one workspace share, their input and success included.
|
|
34
40
|
const onWorkspace = {
|
|
@@ -48,7 +54,8 @@ export const ListWorkspaces = Action.make("listWorkspaces", {
|
|
|
48
54
|
|
|
49
55
|
export const SuspendWorkspace = Action.make("suspendWorkspace", {
|
|
50
56
|
...onWorkspace,
|
|
51
|
-
description:
|
|
57
|
+
description:
|
|
58
|
+
"Suspend a workspace: its members are refused on the public port until resumed.",
|
|
52
59
|
});
|
|
53
60
|
|
|
54
61
|
export const ResumeWorkspace = Action.make("resumeWorkspace", {
|
|
@@ -56,4 +63,8 @@ export const ResumeWorkspace = Action.make("resumeWorkspace", {
|
|
|
56
63
|
description: "Resume a suspended workspace.",
|
|
57
64
|
});
|
|
58
65
|
|
|
59
|
-
export const Admin = [
|
|
66
|
+
export const Admin = [
|
|
67
|
+
ListWorkspaces,
|
|
68
|
+
SuspendWorkspace,
|
|
69
|
+
ResumeWorkspace,
|
|
70
|
+
] as const;
|