Skip to content

Commit b241e38

Browse files
committed
feat(sdk): add Effect HttpApi codegen
1 parent a0a5003 commit b241e38

16 files changed

Lines changed: 1753 additions & 0 deletions

File tree

bun.lock

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/httpapi-codegen/README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# @opencode-ai/httpapi-codegen
2+
3+
Build-time source generation for domain-oriented Effect APIs derived from `HttpApi` and Effect Schema contracts.
4+
5+
The package is private while its API is explored. Its tests are the executable specification for the generator. It must remain independent of OpenCode Core and use synthetic `HttpApi` fixtures.
6+
7+
## Settled rules
8+
9+
- Flatten path, query, header, and payload fields into one input object.
10+
- Reject duplicate field names across input channels.
11+
- Emit no method argument for zero fields, an optional object when every field is optional, and a required object when any field is required.
12+
- Unwrap exact `{ data: A }` success envelopes.
13+
- Map no-content success to `void`.
14+
- Preserve other single success values.
15+
- Reject ambiguous multiple-success contracts.
16+
- Expose streaming success as `Stream`, not `Effect<Stream>`.
17+
- Reject schemas whose wire/domain transformation cannot be generated exactly.
18+
- Map transport, unexpected-status, and response-decoding failures to one stable generated `ClientError`.
19+
- Generate only the Effect API initially; Promise runtime ownership, cancellation, and stream adaptation are deferred.
20+
- Commit generated source for review; CI regenerates and fails when the worktree changes.
21+
- Track generated files in `.httpapi-codegen.json` so regeneration removes only stale files previously owned by the generator.
22+
23+
## Boundary
24+
25+
This package generates only the remote API derived from `HttpApi`. It does not generate embedded implementations or embedded-only capabilities. The OpenCode integration composes two distinct total objects:
26+
27+
- A remote object containing the generated HTTP capabilities.
28+
- An embedded object implementing the shared shape against local services and adding embedded-only capabilities.
29+
30+
The embedded object may be a structural superset of the remote object, but the constructors and concrete result types remain distinct.
31+
32+
Codegen generates every endpoint in the `HttpApi` it receives. OpenCode owns the product decision by composing the exact remote API before invoking the generator; the generic package has no endpoint filtering policy.
33+
34+
The public `generate(Api, { directory })` operation is an Effect requiring `FileSystem`. Internally it composes a pure `compile(Api)` phase with `write(output, directory)`. Compiler tests inspect virtual files directly; writer tests use `FileSystem.makeNoop`.
35+
36+
Generation formats TypeScript with Prettier before writing. Output paths are flat, unique, and checked against traversal, reserved manifest names, and existing symbolic links.
37+
38+
Generated source starts with one self-contained module per `HttpApiGroup`, plus root client and index modules. Schema dependencies may be duplicated across group modules. Cross-group schema partitioning is deferred until measured output or bundle cost requires it.
39+
40+
Codegen preserves group and endpoint identifiers exactly. The composed remote `HttpApi` owns public names such as `session` and `get`; the generator performs no prefix stripping, casing conversion, or public-name annotation mapping.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"$schema": "https://json.schemastore.org/package.json",
3+
"name": "@opencode-ai/httpapi-codegen",
4+
"private": true,
5+
"type": "module",
6+
"scripts": {
7+
"test": "bun test --timeout 5000 --only-failures",
8+
"typecheck": "tsgo --noEmit"
9+
},
10+
"dependencies": {
11+
"effect": "catalog:",
12+
"prettier": "3.6.2"
13+
},
14+
"devDependencies": {
15+
"@tsconfig/bun": "catalog:",
16+
"@types/bun": "catalog:",
17+
"@typescript/native-preview": "catalog:"
18+
}
19+
}

0 commit comments

Comments
 (0)