@adhd/apigen-cli 0.1.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 +89 -0
- package/README.md +146 -0
- package/default-tsconfig.json +10 -0
- package/index.d.ts +1 -0
- package/index.js +123 -0
- package/index.mjs +6525 -0
- package/lib/apigen-cli.d.ts +1 -0
- package/lib/commands/generate-registry.d.ts +4 -0
- package/lib/commands/generate.d.ts +6 -0
- package/lib/commands/run-registry.d.ts +4 -0
- package/lib/commands/run.d.ts +4 -0
- package/lib/import-source.d.ts +14 -0
- package/lib/logging.d.ts +16 -0
- package/lib/orchestrator.d.ts +153 -0
- package/lib/pipeline.d.ts +22 -0
- package/lib/registry.d.ts +12 -0
- package/lib/resolve-tsconfig.d.ts +26 -0
- package/lib/scaffold.d.ts +12 -0
- package/package.json +32 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Changelog — `@adhd/apigen-*`
|
|
2
|
+
|
|
3
|
+
All notable changes to the apigen toolchain (`@adhd/apigen-cli`, `-core`, `-runtime`,
|
|
4
|
+
`-logical`, plugins, and generators). Format based on
|
|
5
|
+
[Keep a Changelog](https://keepachangelog.com/); this project uses
|
|
6
|
+
[Semantic Versioning](https://semver.org/).
|
|
7
|
+
|
|
8
|
+
Open/actionable work lives in [`/BACKLOG.md`](../../BACKLOG.md); plan-level design in
|
|
9
|
+
[`docs/plan/apigen-logical-types/DESIGN.md`](../../docs/plan/apigen-logical-types/DESIGN.md).
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## [Unreleased] — apigen-logical-types (PENDING)
|
|
14
|
+
|
|
15
|
+
> Cross-language serialization of non-JSON-native types and custom classes. Tracked by the
|
|
16
|
+
> `apigen-logical-types` plan-state-machine plan (DESIGN.md §1–§18). **Not yet released** —
|
|
17
|
+
> gated on the plan reaching its Definition of Done + publishing the apigen v2 packages.
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
- **Rich types now round-trip through `run`/`generate` with no new flags.** Functions whose
|
|
21
|
+
signatures use **`Date`, `int64`/`BigInt`, `Decimal`, `bytes`, `UUID`, `Map`, `Set`,
|
|
22
|
+
tuples**, or **user-defined classes** are exposed and (de)serialized correctly across
|
|
23
|
+
MCP / HTTP / CLI. Previously these silently broke (e.g. `Date` extracted as `{}`, inputs
|
|
24
|
+
never rehydrated). *(dod.1/dod.2)*
|
|
25
|
+
- **Custom-class round-trips, including cross-host.** A `User` class survives
|
|
26
|
+
`TS → wire → Python → wire → TS` and is reconstructed as a **real instance on both hosts**
|
|
27
|
+
(not a prototype-stripped object). Discriminated unions (`Dog | Cat`) dispatch by wire
|
|
28
|
+
discriminator. *(dod.3/dod.4)*
|
|
29
|
+
- **Meaningful MCP/OpenAPI schemas.** `tools/list` and the OpenAPI emitter now carry proper
|
|
30
|
+
`format` (`date-time`, `int64`, `uuid`, `byte`, …) and named `$ref` for classes instead of
|
|
31
|
+
empty `{}` — so MCP clients (and the driving model) and generated OpenAPI clients in any
|
|
32
|
+
language get real, validatable types.
|
|
33
|
+
- **Idiomatic generated clients.** Generated TS clients emit `Date`, Python clients emit
|
|
34
|
+
`datetime` (via `x-apigen-*` codegen hints) — consumers get typed values, not raw ISO
|
|
35
|
+
strings to hand-parse.
|
|
36
|
+
- **Cross-host interop for rich types.** Expose a TS function, call it from a Python client
|
|
37
|
+
(or vice versa), with Date/Decimal/classes preserved — guaranteed **byte-equal** by a
|
|
38
|
+
conformance-vector matrix (a TCK every host must pass). *(dod.5)*
|
|
39
|
+
- **New developer tooling:** an `apigen-nx` **`host` generator** to scaffold a new host
|
|
40
|
+
language (a template column + conformance harness), and a workspace
|
|
41
|
+
**`nx run …:conformance`** target that verifies the cross-host matrix.
|
|
42
|
+
- **New package `@adhd/apigen-logical`** — the single source of truth: canonical wire table +
|
|
43
|
+
per-language native-hook template columns + generate-time emitter + run-mode closure builder.
|
|
44
|
+
- **Optional knob `--opt logical.decimal=branded|lib`** — zero-dependency branded-string mode
|
|
45
|
+
vs a real `Decimal` runtime type.
|
|
46
|
+
|
|
47
|
+
### Changed
|
|
48
|
+
- `generate` emits a **standalone-runnable** `package.json`: rich-type deps (e.g. `decimal.js`)
|
|
49
|
+
are added per-surface (only the types actually used), so generated output runs after a plain
|
|
50
|
+
`npm install` — `--link-workspace` no longer required for the publish path.
|
|
51
|
+
*(dod.10 — resolves BUG-APIGEN-002 dep-manifest slice)*
|
|
52
|
+
- Validation actually enforces formats — the validate-Layer wires `ajv-formats`, so a malformed
|
|
53
|
+
`date-time` (`2099-02-30`) is rejected instead of silently passing. *(dod.6)*
|
|
54
|
+
|
|
55
|
+
### Fixed
|
|
56
|
+
- **BUG-APIGEN-005** — language-specific serializable types (`Date → {}`, lost precision,
|
|
57
|
+
un-rehydrated inputs) and custom-class identity loss. *(this feature)*
|
|
58
|
+
- **BUG-APIGEN-004** — `run`/`generate` now **fail fast** with an actionable message on 0
|
|
59
|
+
extracted functions and on a used rich type whose optional dependency is missing
|
|
60
|
+
(e.g. *"function `quote` takes a Decimal; install `decimal.js`"*), instead of a cryptic
|
|
61
|
+
`ERR_MODULE_NOT_FOUND`. *(dod.9)*
|
|
62
|
+
|
|
63
|
+
### Engineering notes
|
|
64
|
+
- Codegen-first design: encode uses each language's **native hook**
|
|
65
|
+
(`toJSON` / `JSONEncoder.default` / serde / Jackson / `MarshalJSON`); decode is schema-driven
|
|
66
|
+
glue emitted once by the generator — **no per-host runtime interpreter**.
|
|
67
|
+
- Languages with native-hook mappings resolved: **TypeScript/JS, Python, Rust, Go, Java**.
|
|
68
|
+
3rd-party deps introduced: Python 0, Java 1, TS 1, Go 2, Rust ~6 (all pinned, minimal-per-surface).
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## [1.0.0] — apigen v2 (released to disk, publish pending)
|
|
73
|
+
|
|
74
|
+
### Added
|
|
75
|
+
- apigen v2 — an 18-package TypeScript→API toolchain. Takes any unmodified `.ts` file and
|
|
76
|
+
exposes its exports as an **MCP server, HTTP API, or CLI** without source changes
|
|
77
|
+
(`apigen-cli run/generate`). Canonical Operation descriptor (JSON-Schema-2020-12 IR),
|
|
78
|
+
symbol/class extractor (ts-morph), v2 plugin interface, Layer harness + streaming + single
|
|
79
|
+
canonical dispatch path, `mcp`/`api-fastify`/`api-express`/`cli` plugins, `apigen-nx`
|
|
80
|
+
generator, and a real Python host passing the conformance vectors.
|
|
81
|
+
Plan: `docs/plan/apigen-client-generation` (46/46 states, final audit 117/117, DoD confirmed).
|
|
82
|
+
|
|
83
|
+
### Fixed
|
|
84
|
+
- **BUG-APIGEN-001** — ctx-param functions returned wrong results via generated servers
|
|
85
|
+
(`hasCtx` now threaded through extraction→dispatch).
|
|
86
|
+
- **BUG-APIGEN-002** — generated output portability via the Option-A publish model + default-off
|
|
87
|
+
`--link-workspace` (dep-manifest extension for rich types tracked in Unreleased above).
|
|
88
|
+
- **BUG-APIGEN-003** — MCP SSE transport reachable (stdio + streaming-http + sse); probe
|
|
89
|
+
hardened (`waitForPort` 15s→60s for cold compiles).
|
package/README.md
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# @adhd/apigen-cli
|
|
2
|
+
|
|
3
|
+
The user-facing CLI for **apigen** — take any `.ts` file and expose its exports as an
|
|
4
|
+
**MCP server, HTTP API (Fastify/Express), CLI, or JSON Schema**, with **zero changes to
|
|
5
|
+
the source**. Functions are the single source of truth; everything is derived.
|
|
6
|
+
|
|
7
|
+
> This documents the **v1** (TypeScript-only) implementation that ships today. The
|
|
8
|
+
> transport-neutral, polyglot **v2** standard is specified in
|
|
9
|
+
> [`docs/apigen/SPEC.md`](../../../docs/apigen/SPEC.md) and is in active build-out.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Install / launch
|
|
14
|
+
|
|
15
|
+
The CLI is not bundled to `dist` by default. Use whichever fits:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
cd <repo-root>
|
|
19
|
+
|
|
20
|
+
# A) Dev — run the TypeScript entry directly (no build):
|
|
21
|
+
alias apigen='npx tsx packages/apigen/cli/src/index.ts'
|
|
22
|
+
|
|
23
|
+
# B) Bundled bin — build once, then run dist (bin name: apigen-cli):
|
|
24
|
+
npx nx build apigen-cli
|
|
25
|
+
# → node packages/apigen/cli/dist/index.js
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Commands:** `run`, `generate`, `run-registry`, `generate-registry`
|
|
29
|
+
**`--type` (target plugin):** `mcp` · `api-fastify` · `api-express` · `cli` · `jsonschema`
|
|
30
|
+
**Server knobs:** passed through repeatable `--opt key=value`.
|
|
31
|
+
|
|
32
|
+
A ready fixture lives at `packages/apigen/cli/src/test/fixtures/api.ts` (`getUser`, `sendEmail`),
|
|
33
|
+
used in the examples below.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Run a live server — `run`
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# MCP over stdio (default transport)
|
|
41
|
+
apigen run --source packages/apigen/cli/src/test/fixtures/api.ts --type mcp
|
|
42
|
+
|
|
43
|
+
# MCP over HTTP transports
|
|
44
|
+
apigen run --source .../api.ts --type mcp --opt transport=sse --opt port=3000
|
|
45
|
+
apigen run --source .../api.ts --type mcp --opt transport=streaming-http --opt port=3000
|
|
46
|
+
|
|
47
|
+
# HTTP API (Fastify or Express) — --namespace sets the route prefix segment
|
|
48
|
+
apigen run --source packages/apigen/cli/src/test/fixtures/api.ts \
|
|
49
|
+
--type api-fastify --namespace api --opt port=3000
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Call an HTTP server — **method must be uppercase `POST`**, arguments wrapped in
|
|
53
|
+
`{"data":{…}}` (the request envelope), route is `/<namespace>/<fn>`:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
curl -X POST http://127.0.0.1:3000/api/getUser \
|
|
57
|
+
-H 'content-type: application/json' \
|
|
58
|
+
-d '{"data":{"userId":"abc"}}'
|
|
59
|
+
# → {"id":"abc"}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### `--opt` keys read by the server plugins
|
|
63
|
+
|
|
64
|
+
| key | targets | default | meaning |
|
|
65
|
+
|---|---|---|---|
|
|
66
|
+
| `transport` | `mcp` | `stdio` | `stdio` \| `sse` \| `streaming-http` |
|
|
67
|
+
| `port` | `mcp` (http transports), `api-fastify`, `api-express` | `3000` | listen port |
|
|
68
|
+
| `host` | `mcp` (http), `api-fastify`, `api-express` | `127.0.0.1` | bind host |
|
|
69
|
+
| `routePrefix` | `api-fastify`, `api-express` | `""` | path prefix before `/<namespace>/<fn>` |
|
|
70
|
+
|
|
71
|
+
`mcp` over `stdio` keeps **stdout** clean for the JSON-RPC channel — all logs go to stderr.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Generate to disk — `generate`
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
# MCP server source
|
|
79
|
+
apigen generate --source packages/apigen/cli/src/test/fixtures/api.ts \
|
|
80
|
+
--type mcp --out-dir /tmp/apigen-out
|
|
81
|
+
node /tmp/apigen-out/server.ts # or: npx tsx /tmp/apigen-out/server.ts
|
|
82
|
+
|
|
83
|
+
apigen generate --source .../api.ts --type api-fastify --out-dir /tmp/out-http # routes.ts
|
|
84
|
+
apigen generate --source .../api.ts --type cli --out-dir /tmp/out-cli # cli.ts
|
|
85
|
+
apigen generate --source .../api.ts --type jsonschema --out-dir /tmp/out-schema # *.json
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Generated servers import `dispatch`/`buildFnTable` from `@adhd/apigen-runtime` — no inlined
|
|
89
|
+
dispatch logic — so disk output behaves identically to `run`.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Multi-package — `run-registry` / `generate-registry`
|
|
94
|
+
|
|
95
|
+
Discover packages in a directory by **nx tag** and wire them into one surface:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
apigen run-registry --packages-dir packages/apigen/cli/src/test/fixtures/registry \
|
|
99
|
+
--tag api --type mcp
|
|
100
|
+
apigen generate-registry --packages-dir <dir> --tag api --type mcp --out-dir /tmp/reg-out
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
`--tag` / `--exclude-tag` are repeatable; untagged exports stay out of the surface.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Flags
|
|
108
|
+
|
|
109
|
+
### Export shapes — `--export`
|
|
110
|
+
- *(omit)* — named exports (`export function f`, `export const f = …`).
|
|
111
|
+
- `--export default` — a default-exported function/object.
|
|
112
|
+
- `--export <objName>` — a named object whose properties are the operations.
|
|
113
|
+
|
|
114
|
+
> **Known v1 limitations (tracked, fixed by v2):** `export { x as y }` aliases,
|
|
115
|
+
> anonymous default exports, and CJS-source files mis-name routes because v1 names by the
|
|
116
|
+
> *declaration* identifier rather than the *exported symbol*. v2 (`docs/apigen/SPEC.md`)
|
|
117
|
+
> names by exported symbol and closes these.
|
|
118
|
+
|
|
119
|
+
### Resolution
|
|
120
|
+
- `--tsconfig <path>` — explicit tsconfig; otherwise the nearest one, else a builtin default.
|
|
121
|
+
- `--namespace <name>` — the package id / route prefix segment. Defaults to the tsconfig
|
|
122
|
+
folder name, falling back to the source file's folder.
|
|
123
|
+
|
|
124
|
+
### Plugin options
|
|
125
|
+
- `--opt key=value` — repeatable; forwarded to the target plugin (see table above).
|
|
126
|
+
|
|
127
|
+
### Logging (stderr — stdout stays protocol-clean)
|
|
128
|
+
- `--log-level trace|debug|info|warn|error|fatal|silent` (env `APIGEN_LOG_LEVEL`)
|
|
129
|
+
- `--log-format json|pretty` (env `APIGEN_LOG_FORMAT`)
|
|
130
|
+
- `--log-file <path>` — write logs to a file instead of stderr (env `APIGEN_LOG_FILE`)
|
|
131
|
+
|
|
132
|
+
Lifecycle logged: compile → server start → host/port → route/tool list → per-request → shutdown.
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Nx integration
|
|
137
|
+
|
|
138
|
+
- Cache-aware generate target: `@adhd/apigen-nx:generate` (see [`../nx`](../nx)).
|
|
139
|
+
- Scaffold a new output plugin: `nx g @adhd/apigen-nx:plugin <name>`.
|
|
140
|
+
|
|
141
|
+
## Develop
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
npx nx build apigen-cli # bundle
|
|
145
|
+
npx nx test apigen-cli # Vitest (unit + integration)
|
|
146
|
+
```
|
package/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|