History

feat: API contract, server handler, and frontend with effect-atom

- packages/core/api: HttpApi contract with ToolsApi + SecretsApi groups SDK tagged errors pass through directly with status annotations (ToolNotFoundError→404, PolicyDeniedError→403, etc.) - apps/server: API handler implementation via HttpApiBuilder Exports createApiHandler() for reuse (no baked-in server runtime) Handlers are pure pass-through — no manual error catching - apps/web: Vite + React frontend served on same port as API Vite plugin forwards /v1/*, /docs, /openapi.json to Effect handler effect-atom integration: AtomHttpApi.Tag typed client, query/mutation atoms RegistryProvider + useAtomValue with Result pattern matching - Catalog pins @effect/platform, platform-bun, platform-node, cluster - All 9 packages typecheck clean

Rhys Sullivan committed 7 months ago

Commit 8babea81 parent 00219a926 files · +1022 −32Browse files

Showing the changes to packages/core/api/src/secrets (1 of 26 files). Show all

Unified · Split

packages/core/api/src/secrets/api.ts+78−0
@@ -0,0 +1,78 @@
1+import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from "@effect/platform";
2+import { Schema } from "effect";
3+import {
4+ ScopeId,
5+ SecretId,
6+ SecretNotFoundError,
7+ SecretResolutionError,
8+} from "@executor/sdk";
9+
10+// ---------------------------------------------------------------------------
11+// Params
12+// ---------------------------------------------------------------------------
13+
14+const scopeIdParam = HttpApiSchema.param("scopeId", ScopeId);
15+const secretIdParam = HttpApiSchema.param("secretId", SecretId);
16+
17+// ---------------------------------------------------------------------------
18+// Response / payload schemas
19+// ---------------------------------------------------------------------------
20+
21+const SecretRefResponse = Schema.Struct({
22+ id: SecretId,
23+ scopeId: ScopeId,
24+ name: Schema.String,
25+ provider: Schema.optional(Schema.String),
26+ purpose: Schema.optional(Schema.String),
27+ createdAt: Schema.Number,
28+});
29+
30+const SecretStatusResponse = Schema.Struct({
31+ secretId: SecretId,
32+ status: Schema.Literal("resolved", "missing"),
33+});
34+
35+const SetSecretPayload = Schema.Struct({
36+ id: SecretId,
37+ name: Schema.String,
38+ value: Schema.String,
39+ purpose: Schema.optional(Schema.String),
40+ provider: Schema.optional(Schema.String),
41+});
42+
43+// ---------------------------------------------------------------------------
44+// Error schemas with HTTP status annotations
45+// ---------------------------------------------------------------------------
46+
47+const SecretNotFound = SecretNotFoundError.annotations(
48+ HttpApiSchema.annotations({ status: 404 }),
49+);
50+const SecretResolution = SecretResolutionError.annotations(
51+ HttpApiSchema.annotations({ status: 500 }),
52+);
53+
54+// ---------------------------------------------------------------------------
55+// Group
56+// ---------------------------------------------------------------------------
57+
58+export class SecretsApi extends HttpApiGroup.make("secrets")
59+ .add(
60+ HttpApiEndpoint.get("list")`/scopes/${scopeIdParam}/secrets`
61+ .addSuccess(Schema.Array(SecretRefResponse)),
62+ )
63+ .add(
64+ HttpApiEndpoint.get("status")`/scopes/${scopeIdParam}/secrets/${secretIdParam}/status`
65+ .addSuccess(SecretStatusResponse),
66+ )
67+ .add(
68+ HttpApiEndpoint.post("set")`/scopes/${scopeIdParam}/secrets`
69+ .setPayload(SetSecretPayload)
70+ .addSuccess(SecretRefResponse)
71+ .addError(SecretResolution),
72+ )
73+ .add(
74+ HttpApiEndpoint.del("remove")`/scopes/${scopeIdParam}/secrets/${secretIdParam}`
75+ .addSuccess(Schema.Struct({ removed: Schema.Boolean }))
76+ .addError(SecretNotFound),
77+ )
78+ .prefix("/v1") {}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t