@supacloud/compiler 0.15.0 → 0.19.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.
- package/DELIVERY.md +223 -0
- package/README.md +184 -5
- package/dist/benchmark.d.ts +10 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +10544 -4205
- package/dist/config.d.ts +8 -1
- package/dist/delivery-build-schema.d.ts +184 -0
- package/dist/delivery-build.d.ts +4 -0
- package/dist/delivery-bundle.d.ts +7 -0
- package/dist/delivery-files.d.ts +17 -0
- package/dist/delivery-plan.d.ts +7 -0
- package/dist/delivery-render.d.ts +5 -0
- package/dist/delivery-schema.d.ts +186 -0
- package/dist/fixtures/bad-project.d.ts +7 -0
- package/dist/fixtures/good-project.d.ts +12 -0
- package/dist/fixtures/helpers.d.ts +5 -0
- package/dist/fixtures/runtime-source.d.ts +7 -0
- package/dist/generate.d.ts +13 -2
- package/dist/index.d.ts +13 -3
- package/dist/index.js +9792 -3622
- package/dist/migrations.d.ts +41 -0
- package/dist/openapi-tools.d.ts +41 -0
- package/dist/route-contracts.d.ts +2 -2
- package/dist/type-safety.d.ts +26 -0
- package/dist/types.d.ts +60 -2
- package/package.json +5 -3
package/DELIVERY.md
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# Local Delivery Planning And Builds
|
|
2
|
+
|
|
3
|
+
`supacloud-compiler plan --json` is a read-only first step toward automated app
|
|
4
|
+
delivery. It uses the existing source analysis and compiler checks, then groups
|
|
5
|
+
HTTP routes and declared Jobs into deterministic target previews.
|
|
6
|
+
|
|
7
|
+
`supacloud-compiler build-delivery --json` additionally builds independent local
|
|
8
|
+
module factory bundles. It does **not** configure queues or gateways, verify remote
|
|
9
|
+
hosts, deploy functions, or run an unattended AI repair loop.
|
|
10
|
+
Existing compile/check/dev output remains unchanged.
|
|
11
|
+
|
|
12
|
+
## Zero-Configuration HTTP
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
supacloud-compiler plan --json
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
All discovered HTTP routes default to `api`. Module imports contribute dependencies,
|
|
19
|
+
not route ownership. A dependency module's own routes remain with their own explicit
|
|
20
|
+
owner or the default API; they are not copied into the importing target.
|
|
21
|
+
All discovered routes remain exposed in the plan. To make a module private, remove
|
|
22
|
+
its route declarations; simply omitting a module from target configuration does not
|
|
23
|
+
hide its routes.
|
|
24
|
+
|
|
25
|
+
Declared Jobs default to `jobs`, require a durable queue declaration, and default
|
|
26
|
+
to process isolation. A Job declaration does not rewrite a synchronous HTTP route.
|
|
27
|
+
If these runtime declarations are absent, planning returns errors with no plan.
|
|
28
|
+
|
|
29
|
+
## Explicit Boundaries
|
|
30
|
+
|
|
31
|
+
Add an optional `delivery` section to the existing configuration:
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import { defineSupacloudConfig } from "@supacloud/compiler";
|
|
35
|
+
|
|
36
|
+
export default defineSupacloudConfig({
|
|
37
|
+
delivery: {
|
|
38
|
+
version: 1,
|
|
39
|
+
targets: [
|
|
40
|
+
{ name: "orders", kind: "api", modules: ["orders"] },
|
|
41
|
+
{
|
|
42
|
+
name: "payment-hooks",
|
|
43
|
+
kind: "webhook",
|
|
44
|
+
modules: ["payments"],
|
|
45
|
+
isolation: "process",
|
|
46
|
+
capabilities: ["payments.verify"],
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
runtime: {
|
|
50
|
+
processIsolation: true,
|
|
51
|
+
durableQueue: true,
|
|
52
|
+
capabilities: ["payments.verify"],
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The names in `modules` are declared module names, not class names or paths.
|
|
59
|
+
Targets select all routes or all jobs belonging to those modules, depending on
|
|
60
|
+
their kind. HTTP and Job ownership are independent, so one module can contribute
|
|
61
|
+
HTTP to `api` and Jobs to `jobs`. Two HTTP targets cannot both own the same module.
|
|
62
|
+
`api` and `jobs` are reserved for their matching workload kinds.
|
|
63
|
+
|
|
64
|
+
No unused explicit target is accepted. Unknown modules, duplicate ownership,
|
|
65
|
+
unresolved imports, cyclic dependencies, duplicate job names, and conflicting
|
|
66
|
+
method/path patterns reject the plan. Parameter-name aliases such as `/:id` and
|
|
67
|
+
`/:key` do not establish different route identities.
|
|
68
|
+
|
|
69
|
+
`runtime` is a declaration only, not host attestation. `capabilities` contains
|
|
70
|
+
adapter/credential boundary references, never values. Declaring a webhook target
|
|
71
|
+
does not implement signature verification or authorize public ingress. The runtime
|
|
72
|
+
and deployment layers must still verify these requirements before activation.
|
|
73
|
+
Changing `isolation` to `shared` is an explicit relaxation requiring user review.
|
|
74
|
+
|
|
75
|
+
For an AI-generated JSON declaration instead of editing executable config:
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
supacloud-compiler plan --delivery delivery.json --json
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`delivery.json` contains the `delivery` object above, not the outer project config.
|
|
82
|
+
It replaces, rather than merges with, `config.delivery`. The executable project
|
|
83
|
+
config is still loaded normally. Invalid configuration is rejected, not echoed.
|
|
84
|
+
`--write` and unknown plan arguments fail. Successful output exits 0; failures exit 1.
|
|
85
|
+
|
|
86
|
+
## Programmatic Contract
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
import {
|
|
90
|
+
compileOptionsFromConfig,
|
|
91
|
+
loadSupacloudConfig,
|
|
92
|
+
planDeliveryProject,
|
|
93
|
+
parseDeliveryPlanResult,
|
|
94
|
+
} from "@supacloud/compiler";
|
|
95
|
+
|
|
96
|
+
const config = await loadSupacloudConfig();
|
|
97
|
+
const result = await planDeliveryProject(compileOptionsFromConfig(config), config.delivery);
|
|
98
|
+
if (result.ok) {
|
|
99
|
+
for (const target of result.plan.targets) {
|
|
100
|
+
console.log(target.name, target.routes, target.requirements);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// File/message data must be validated, not asserted as DeliveryPlanResult.
|
|
105
|
+
const received: unknown = JSON.parse(JSON.stringify(result));
|
|
106
|
+
const validated = parseDeliveryPlanResult(received);
|
|
107
|
+
console.log(validated.ok);
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Exported TypeBox schemas are the source of both runtime validation and static types:
|
|
111
|
+
`DeliveryOptionsSchema`, `DeliveryTargetSchema`, `DeliveryPlanSchema`,
|
|
112
|
+
`DeliveryPlanResultSchema`. `createDeliveryPlan` accepts a trusted compiler graph;
|
|
113
|
+
it is not a deserializer for arbitrary external graph JSON.
|
|
114
|
+
|
|
115
|
+
## Local Builds
|
|
116
|
+
|
|
117
|
+
```sh
|
|
118
|
+
supacloud-compiler build-delivery --json
|
|
119
|
+
supacloud-compiler build-delivery --delivery delivery.json --json
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Requires Bun and a project `tsconfig.json`. The configured output directory must
|
|
123
|
+
be project-local and must not contain the application source root. Output uses
|
|
124
|
+
the dedicated `<outDir>/delivery` namespace:
|
|
125
|
+
|
|
126
|
+
```text
|
|
127
|
+
delivery/
|
|
128
|
+
owner.json
|
|
129
|
+
delivery.manifest.json
|
|
130
|
+
objects/<objectId>/
|
|
131
|
+
generated/application.ts
|
|
132
|
+
bundle/index.js
|
|
133
|
+
bundle/package.json
|
|
134
|
+
bundle/app.manifest.json
|
|
135
|
+
bundle/target.json
|
|
136
|
+
bundle/assets/...
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
`bundle/index.js` exports `createCompiledModules`. Move the whole `bundle` directory,
|
|
140
|
+
not just its entrypoint. The generated TypeScript is inspection output and still
|
|
141
|
+
references application sources; the bundle does not require those source files.
|
|
142
|
+
This is **not** a default HTTP handler or a ready-to-deploy Function. A compatible
|
|
143
|
+
host must supply HTTP composition, trusted identity, database/governance adapters,
|
|
144
|
+
and durable Job execution. Route mappings are local metadata, not applied gateway
|
|
145
|
+
configuration. All results continue to report `deploymentReady: false`.
|
|
146
|
+
|
|
147
|
+
Optional build settings live in the same validated `delivery` declaration:
|
|
148
|
+
|
|
149
|
+
```json
|
|
150
|
+
{
|
|
151
|
+
"version": 1,
|
|
152
|
+
"build": {
|
|
153
|
+
"minify": true,
|
|
154
|
+
"environmentContract": "app-env-v1",
|
|
155
|
+
"assets": [
|
|
156
|
+
{ "target": "api", "source": "templates/report.html", "path": "report.html" }
|
|
157
|
+
]
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Asset `source` is relative to configured source root; `path` is relative to
|
|
163
|
+
`bundle/assets`. Only explicit relative paths are accepted. Missing assets, path
|
|
164
|
+
traversal, duplicate destinations, and symlinks reject the build. Environment
|
|
165
|
+
contracts are references, not secret values. Environment values are not inlined.
|
|
166
|
+
Code doing runtime filesystem reads must use declared assets and the host's
|
|
167
|
+
documented asset-location convention; automatic discovery is not provided.
|
|
168
|
+
Computed `import()` and direct computed `require()` calls are rejected. This is
|
|
169
|
+
not a sandbox for arbitrary JavaScript, eval, or filesystem access.
|
|
170
|
+
|
|
171
|
+
Each target includes its conservative module dependency closure, while route and
|
|
172
|
+
Job descriptors remain exclusive to their owner. Provider pruning is disabled to
|
|
173
|
+
preserve Job and lifecycle dependencies. Package imports are bundled; only Bun
|
|
174
|
+
and Node builtin imports may remain external. Native/platform-dependent packages
|
|
175
|
+
still need destination-platform validation.
|
|
176
|
+
|
|
177
|
+
Every invocation reruns compiler checks, TypeScript diagnostics, and bundling for
|
|
178
|
+
**all** targets. The generator's type-check project includes application source
|
|
179
|
+
and target-generated files, preserving configured checks and widening only the
|
|
180
|
+
emit-path `rootDir` to the project directory. This does not replace application
|
|
181
|
+
tests or full release checks. Refresh GraphQL artifacts through normal `compile`
|
|
182
|
+
before building when GraphQL drift is reported.
|
|
183
|
+
|
|
184
|
+
`inputDigest` includes generated source, captured bundled inputs, compiler and Bun
|
|
185
|
+
identity, configuration/lockfile hashes, target build options, explicit assets,
|
|
186
|
+
and environment-contract reference. Shared dependency changes invalidate dependent
|
|
187
|
+
targets; configuration changes conservatively invalidate more targets. Unchanged
|
|
188
|
+
immutable artifacts are reused without touching their files. This is **artifact
|
|
189
|
+
reuse, not skipped bundler work**.
|
|
190
|
+
|
|
191
|
+
Success exposes `manifest`, `bundledTargets`, `changedTargets`, `unchangedTargets`,
|
|
192
|
+
`removedTargets`, and `written`. An unchanged build has `written: []`.
|
|
193
|
+
`manifest.objects` records per-file size and SHA-256 plus the object identity.
|
|
194
|
+
Use `parseDeliveryBuildResult` / `parseDeliveryBuildManifest` for received JSON;
|
|
195
|
+
matching hashes are integrity checks, not authorization or authenticity proofs.
|
|
196
|
+
|
|
197
|
+
An exclusive lock protects the owned output directory. Existing unowned output,
|
|
198
|
+
invalid manifests, and modified immutable objects are rejected without overwrites.
|
|
199
|
+
Only an atomic replacement of `delivery.manifest.json` activates a local build.
|
|
200
|
+
Failures preserve the previous active pointer; inactive objects can remain after
|
|
201
|
+
an interrupted publication. Removed target objects are retained for inspection,
|
|
202
|
+
not automatically garbage-collected. Inspect stale locks after confirming no
|
|
203
|
+
writer is active; the builder never removes them automatically.
|
|
204
|
+
|
|
205
|
+
## Planning Evidence And Limits
|
|
206
|
+
|
|
207
|
+
- Every result has `written: []`. A failure has `ok: false` and `plan: null`.
|
|
208
|
+
- Success has `deploymentReady: false`. No planning result authorizes deployment.
|
|
209
|
+
- `topologyDigest` hashes canonical target topology, requirements, and declared
|
|
210
|
+
readiness. It excludes business source contents, toolchain, lockfile, credentials,
|
|
211
|
+
migrations, and full runtime contracts. It is **not** an artifact hash, cache key,
|
|
212
|
+
approval token, or proof that a received plan is authentic.
|
|
213
|
+
- Dependencies are a conservative module closure, not provider-level tree shaking.
|
|
214
|
+
External token inventory is conservative within that closure.
|
|
215
|
+
- `planDeliveryProject` runs existing compiler analysis/governance/contract gates
|
|
216
|
+
using supplied compile options. Artifact drift is intentionally ignored so a
|
|
217
|
+
new project can be planned before generation. Existing artifacts are not rewritten.
|
|
218
|
+
- Compiler analysis is not a complete TypeScript type check. Run the application's
|
|
219
|
+
type checker, tests, full integration/build gates, and host verification before
|
|
220
|
+
release. Do not weaken those gates to make a plan succeed.
|
|
221
|
+
- This version does not reconcile old deployment topology, validate all possible
|
|
222
|
+
router-specific pattern overlaps, or attest queue adapters. Deployment remains
|
|
223
|
+
a separate, explicitly authorized step.
|
package/README.md
CHANGED
|
@@ -1,5 +1,58 @@
|
|
|
1
1
|
# @supacloud/compiler
|
|
2
2
|
|
|
3
|
+
## Local Delivery
|
|
4
|
+
|
|
5
|
+
`supacloud-compiler plan --json` previews workload targets, dependency closures,
|
|
6
|
+
route ownership, and required runtime capabilities without writing or deploying.
|
|
7
|
+
`supacloud-compiler build-delivery --json` creates independent local factory bundles
|
|
8
|
+
and an atomic inspection manifest, reusing unchanged artifacts without deployment.
|
|
9
|
+
See [local delivery](./DELIVERY.md) for validated configuration, AI-facing
|
|
10
|
+
contracts, and the distinction between a topology preview and release evidence.
|
|
11
|
+
|
|
12
|
+
## Persistent Execution Policy
|
|
13
|
+
|
|
14
|
+
Set `commandCapabilities.requirePersistentAdapters: true` to require named adapters
|
|
15
|
+
with explicit `database`/`external` boundaries, permission, audit and idempotency.
|
|
16
|
+
Database commands require transactional capability and `transaction: "required"`.
|
|
17
|
+
External adapters cannot satisfy a required database transaction: use durable
|
|
18
|
+
intent and read-only reconciliation instead.
|
|
19
|
+
|
|
20
|
+
`command-persistence-required` and `command-external-transaction` diagnostics include
|
|
21
|
+
recovery suggestions and participate in JSON output and the existing no-write-on-error
|
|
22
|
+
gate. These checks validate declared policy, not the implementation of a custom
|
|
23
|
+
adapter. See [configuration and migration](../../docs/command-migration.md).
|
|
24
|
+
|
|
25
|
+
## Source Migrations
|
|
26
|
+
|
|
27
|
+
The compiler includes deterministic, versioned source migrations for breaking
|
|
28
|
+
framework changes. The command is preview-only unless `--write` is explicit:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# Preview files, replacements, and manual conflicts
|
|
32
|
+
bunx supacloud-compiler migrate --root . --json
|
|
33
|
+
|
|
34
|
+
# Apply only after reviewing the preview
|
|
35
|
+
bunx supacloud-compiler migrate --root . --write
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Migrations operate on TypeScript ASTs and skip `node_modules`, `dist`, and
|
|
39
|
+
`generated`. Route options are resolved through local constants,
|
|
40
|
+
`defineRouteContract(...)`, namespace properties, named imports, and the
|
|
41
|
+
project's `tsconfig` path/module settings, so a shared contract declaration is
|
|
42
|
+
changed once even when several controllers import it. If the contract is outside
|
|
43
|
+
the selected root/include set, or any file has an ambiguous transformation, the
|
|
44
|
+
command exits non-zero and writes no file. A successful write uses a
|
|
45
|
+
same-directory temporary file followed by replacement for each changed file; it
|
|
46
|
+
is not a version-control rollback mechanism. Review the diff, then run `compile`,
|
|
47
|
+
`check`, and focused tests with the same compiler version. Use version control to
|
|
48
|
+
revert a migration.
|
|
49
|
+
|
|
50
|
+
The current route-contract migration is `route-response-to-responses` (`0.11.0`
|
|
51
|
+
to `0.12.0`): it changes `response: Schema` into
|
|
52
|
+
`responses: { 200: Schema }`. It refuses to guess when `responses` is already
|
|
53
|
+
present. See the [route contract migration guide](../../docs/route-contract-migration.md)
|
|
54
|
+
for the complete upgrade and release sequence.
|
|
55
|
+
|
|
3
56
|
FA-derived direct-command RPC ownership, contract inspection and POST command
|
|
4
57
|
protocol migration are documented in `docs/fa-consumer-governance.md` in the
|
|
5
58
|
repository. `context <module> --json` reports `routeContracts` and standalone
|
|
@@ -191,6 +244,7 @@ bunx supacloud-compiler dev
|
|
|
191
244
|
| 文件发现 | `**/*.module.ts`、`**/*.ts` |
|
|
192
245
|
| strict 类型安全门 | 开启 |
|
|
193
246
|
| typed client | 开启 |
|
|
247
|
+
| OpenAPI 3.1 module | 开启 |
|
|
194
248
|
| permissions manifest | 开启 |
|
|
195
249
|
| module boundary preset | `modular-monolith` |
|
|
196
250
|
| provider tree-shaking | 开启 |
|
|
@@ -205,6 +259,11 @@ export default defineSupacloudConfig({
|
|
|
205
259
|
outDir: "generated",
|
|
206
260
|
strict: true,
|
|
207
261
|
generateClient: true,
|
|
262
|
+
generateOpenApi: true,
|
|
263
|
+
openApi: {
|
|
264
|
+
title: "Orders API",
|
|
265
|
+
version: "1.0.0",
|
|
266
|
+
},
|
|
208
267
|
generatePermissions: true,
|
|
209
268
|
moduleBoundaryPreset: "modular-monolith",
|
|
210
269
|
commandCapabilities: {
|
|
@@ -221,6 +280,37 @@ export default defineSupacloudConfig({
|
|
|
221
280
|
`commandCapabilities` 用于声明运行时实际支持的命令治理能力;命令声明了
|
|
222
281
|
`permission`、`audit` 或 `idempotency` 时,若对应能力关闭,编译器会失败。
|
|
223
282
|
|
|
283
|
+
## OpenAPI 与 Client Generator
|
|
284
|
+
|
|
285
|
+
编译器从同一份 `ApplicationGraph` 生成 `client.ts` 和 `openapi.ts`,不引入
|
|
286
|
+
反射或第二套路由注册。路由装饰器中显式声明的 TypeBox `body`、`params`、
|
|
287
|
+
`query`、`response` schema 会被静态导入;没有 schema 的字段保持为
|
|
288
|
+
`unknown`,不会从 TypeScript 类型推断出未经验证的运行时协议。
|
|
289
|
+
|
|
290
|
+
`client.ts` 提供路由方法、路径参数检查、请求类型和 `API_ROUTES`。已声明
|
|
291
|
+
响应 schema 的方法不传 decoder 也会按 HTTP status 自动选择并校验内置 schema;
|
|
292
|
+
传入 `ResponseDecoder<T>` 时,decoder 接收已经通过 schema 校验/规范化的值,
|
|
293
|
+
可安全做日期、金额等业务转换。没有响应 schema 的方法仍返回原始 `unknown`,
|
|
294
|
+
除非调用方显式提供 decoder。
|
|
295
|
+
|
|
296
|
+
`openapi.ts` 导出 `OPENAPI_DOCUMENT`、`OPENAPI_JSON` 和
|
|
297
|
+
`createOpenApiDocument()`。它包含 OpenAPI 3.1 路径、参数、请求体、响应、
|
|
298
|
+
错误协议、默认 bearer security scheme,以及 `x-supacloud` 中的模块、命令、
|
|
299
|
+
权限和静态 contract 元数据。文档只描述编译器发现的 HTTP routes;文件和
|
|
300
|
+
流式响应仍由宿主运行时负责传输。
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
# 导出可提交或交给文档工具的 JSON
|
|
304
|
+
bunx supacloud-compiler openapi-export generated/openapi.ts openapi.json
|
|
305
|
+
|
|
306
|
+
# 在 CI 中阻止破坏性 contract 变更
|
|
307
|
+
bunx supacloud-compiler openapi-diff openapi-baseline.json openapi.json --json
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
`openapi-diff` 会检查路径/操作、参数必填性、请求体、响应状态和 schema 的
|
|
311
|
+
枚举、属性与 required 变化;命令失败时返回非零退出码。基线文件由应用
|
|
312
|
+
负责版本管理,生成的 `openapi.ts` 则由普通 `compile`/`check` 漂移检查维护。
|
|
313
|
+
|
|
224
314
|
## API
|
|
225
315
|
|
|
226
316
|
```ts
|
|
@@ -319,9 +409,88 @@ IDE 和 AI agent 做状态机漂移检查。
|
|
|
319
409
|
- AOP 只支持静态边界:`ModuleOptions.aspects`、`RouteOptions.aspects`、`CommandOptions.aspects` 和 `JobOptions.aspects` 必须是显式数组字面量,元素必须是可解析的函数标识符。生成器会直接 import aspect 并生成固定顺序的 onion chain,不使用 Proxy、Reflect 扫描、动态 pointcut 或运行时注册。
|
|
320
410
|
- 执行顺序为 `module -> route -> command -> commandGovernance -> handler`;Job 使用 `module -> job -> executor -> run/execute`,并在 finally 中销毁 job scope。
|
|
321
411
|
- services 对象的 key 为 token 名的 camelCase:`CaseService → caseService`、`CASE_REPOSITORY → caseRepository`、`LOGGER → logger`。
|
|
322
|
-
- controller 描述静态给出:`{ path, serviceKey, scope, routes: [{ method, path, handler, body?, params?, query?, response? }] }`,schema 直接引用 import 进来的对象。
|
|
412
|
+
- controller 描述静态给出:`{ path, serviceKey, scope, routes: [{ method, path, handler, body?, params?, query?, headers?, cookie?, response?, responses? }] }`,schema 直接引用 import 进来的对象。
|
|
413
|
+
- `client.ts` 在启用 `generateClient` 时生成:包含 `API_ROUTES`、`API_SCHEMAS`、类型化请求选项和显式响应 decoder 入口。
|
|
414
|
+
- `openapi.ts` 在启用 `generateOpenApi` 时生成:包含 OpenAPI 3.1 文档模块和可序列化 JSON;`check` 会将它纳入生成物漂移检查。
|
|
323
415
|
- 严格生成模式会对 `application.ts`、可选的 `client.ts` 和 `permissions.ts` 做 AST 扫描,禁止生成 `any`。
|
|
324
416
|
|
|
417
|
+
`<outDir>/client.ts` 提供按 Controller 分组的 Fetch client。路径参数会从
|
|
418
|
+
controller 和 route 的完整路径合并推导;声明了 `response` 或 `responses` 的
|
|
419
|
+
route 会自动按 HTTP status 执行内置 response decoder,并返回 schema 推导的
|
|
420
|
+
类型。显式 decoder 仍可用于覆盖自定义转换;没有响应 schema 的 route 返回
|
|
421
|
+
`unknown`。`headers`、`cookie` 和多状态 `responses` 会同步进入客户端和
|
|
422
|
+
OpenAPI。`buildRouteUrl` 和 `createApiClient` 可直接复用,也支持动态 headers
|
|
423
|
+
和请求拦截器。
|
|
424
|
+
|
|
425
|
+
### Migration from manual decoders
|
|
426
|
+
|
|
427
|
+
旧版本要求调用方为每个有响应 schema 的 route 传入 decoder。升级后删除该
|
|
428
|
+
decoder 即可;需要保留自定义转换时,将它作为第二个参数传入。旧的单一
|
|
429
|
+
`response: Schema` 当前作为迁移桥接仍可编译,但新代码必须迁移到
|
|
430
|
+
`responses: { 200: Schema }` 或实际的状态映射;该桥接字段不保证在下一次破坏性
|
|
431
|
+
版本继续保留。Management API 的契约注册表
|
|
432
|
+
由实际 Elysia `app.routes` 投影生成,不应再维护平行的路由清单。
|
|
433
|
+
|
|
434
|
+
完整的破坏性升级步骤(包括 headers、cookie、客户端 decoder、OpenAPI 和生成物
|
|
435
|
+
刷新)见 [route contract migration guide](../../docs/route-contract-migration.md)。
|
|
436
|
+
|
|
437
|
+
`<outDir>/openapi.ts` 是无额外运行时依赖的 OpenAPI 3.1 module,导出
|
|
438
|
+
`OPENAPI_DOCUMENT`、`OPENAPI_JSON`、`createOpenApiDocument` 和
|
|
439
|
+
`serializeOpenApiDocument`。它在运行时读取同一组 TypeBox schema,生成 paths、
|
|
440
|
+
parameters、requestBody、responses、securitySchemes 以及 `x-supacloud` 路由元数据,
|
|
441
|
+
因此不会维护第二份 API contract。默认包含 bearer JWT scheme;项目可在
|
|
442
|
+
`openApi` 配置中补充文档信息、servers 和其他显式 security schemes。
|
|
443
|
+
|
|
444
|
+
`OPENAPI_JSON` 是运行时快照;需要提交独立 `openapi.json` 时,在应用已经能加载
|
|
445
|
+
生成模块的运行时调用 `exportGeneratedOpenApiJson()` 或直接写出该字符串。编译器
|
|
446
|
+
不会为了生成 JSON 执行应用 schema。`readOpenApiJson()` 和
|
|
447
|
+
`diffOpenApiDocuments()` 可用于构建发布门禁:
|
|
448
|
+
|
|
449
|
+
```ts
|
|
450
|
+
import {
|
|
451
|
+
exportGeneratedOpenApiJson,
|
|
452
|
+
diffOpenApiDocuments,
|
|
453
|
+
readOpenApiJson,
|
|
454
|
+
} from "@supacloud/compiler";
|
|
455
|
+
|
|
456
|
+
await exportGeneratedOpenApiJson({
|
|
457
|
+
modulePath: "./generated/openapi.ts",
|
|
458
|
+
outputPath: "./generated/openapi.json",
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
const diff = diffOpenApiDocuments(
|
|
462
|
+
await readOpenApiJson("./contracts/openapi.base.json"),
|
|
463
|
+
await readOpenApiJson("./generated/openapi.json"),
|
|
464
|
+
);
|
|
465
|
+
if (!diff.ok) throw new Error("OpenAPI breaking change");
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
也可以直接在 CI 中运行:
|
|
469
|
+
|
|
470
|
+
```bash
|
|
471
|
+
supacloud-compiler openapi-export ./generated/openapi.ts ./generated/openapi.json
|
|
472
|
+
supacloud-compiler openapi-diff ./contracts/openapi.base.json ./generated/openapi.json --json
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
`openapi-export` 在运行时加载生成的 `openapi.ts` 并原子地写出独立 JSON;它不会在
|
|
476
|
+
编译阶段执行应用 schema。可用 `--space 0` 到 `--space 10` 控制缩进,重复执行不会
|
|
477
|
+
改写内容不变的文件。当前只承诺 JSON 输出,YAML 转换由发布流水线按需处理。
|
|
478
|
+
|
|
479
|
+
diff 默认阻止路径/操作/参数/响应删除、请求约束收紧、响应字段收窄或安全要求新增;
|
|
480
|
+
新增可选参数、路径、响应和组件会标记为 non-breaking。它是保守的合同门禁,不替代
|
|
481
|
+
应用端的业务兼容性测试。
|
|
482
|
+
|
|
483
|
+
```ts
|
|
484
|
+
export default defineSupacloudConfig({
|
|
485
|
+
generateClient: true,
|
|
486
|
+
generateOpenApi: true,
|
|
487
|
+
openApi: { title: "Orders API", version: "1.0.0" },
|
|
488
|
+
});
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
用 `--no-client` 或 `--no-openapi` 关闭对应产物;`compile` 和 `check` 会同时检查
|
|
492
|
+
已生成的 `client.ts`、`openapi.ts` 是否与当前 ApplicationGraph 漂移。
|
|
493
|
+
|
|
325
494
|
`<outDir>/app.manifest.json`:`{ version: 1, modules, externalTokens }`,供 CLI graph/explain 使用。
|
|
326
495
|
|
|
327
496
|
## 诊断码
|
|
@@ -432,8 +601,8 @@ bun run build
|
|
|
432
601
|
|
|
433
602
|
## Route Contract Policy
|
|
434
603
|
|
|
435
|
-
|
|
436
|
-
`CompileOptions` to report `route-contract-required` errors in both compile and
|
|
604
|
+
Project configuration defaults to `requireRouteContracts: true`. Low-level
|
|
605
|
+
`CompileOptions` callers can set it explicitly to report `route-contract-required` errors in both compile and
|
|
437
606
|
check (including JSON diagnostics). Changing this option invalidates incremental
|
|
438
607
|
results. Combine it with `writeOnError: false` when programmatic compilation must
|
|
439
608
|
not emit files on errors.
|
|
@@ -443,10 +612,20 @@ query, and response declarations. Required inputs are detected from handler
|
|
|
443
612
|
bindings and controller/route path parameters. Responses always require an
|
|
444
613
|
explicit declaration, including intentional void contracts.
|
|
445
614
|
|
|
446
|
-
This checks declaration coverage
|
|
615
|
+
This checks declaration coverage and rejects known opaque schemas, not full schema quality, handler/schema type
|
|
447
616
|
equivalence, or database authorization. It deliberately does not auto-fix missing
|
|
448
617
|
schemas with `unknown` placeholders. Consumers must define the actual contracts
|
|
449
|
-
and test decoding separately.
|
|
618
|
+
and test decoding separately. Native output must be classified; delegated
|
|
619
|
+
validation and native transports require a `contract.evidence` test reference.
|
|
620
|
+
The report still sets `verified: false`, since a reference does not prove execution.
|
|
621
|
+
|
|
622
|
+
The source type gate now includes TypeScript syntactic/semantic diagnostics and
|
|
623
|
+
rejects production `@ts-ignore`, `@ts-nocheck` and `@ts-expect-error`. A source-directory root resolves
|
|
624
|
+
the enclosing tsconfig. When this gate is enabled, incremental compilation
|
|
625
|
+
rechecks types instead of returning an unchecked cached result.
|
|
626
|
+
|
|
627
|
+
Generated route calls require all path parameters and a decoder for typed
|
|
628
|
+
responses. See [type safety and migration](../../docs/type-safety.md).
|
|
450
629
|
|
|
451
630
|
## License
|
|
452
631
|
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface CompilerBenchmarkResult {
|
|
2
|
+
fixtureFiles: number;
|
|
3
|
+
coldCompileMs: number;
|
|
4
|
+
incrementalCompileMs: number;
|
|
5
|
+
dependencyInvalidationMs: number;
|
|
6
|
+
generatedBytes: number;
|
|
7
|
+
reusedModules: string[];
|
|
8
|
+
reanalyzedModules: string[];
|
|
9
|
+
}
|
|
10
|
+
export declare function runCompilerBenchmark(): Promise<CompilerBenchmarkResult>;
|
package/dist/cli.d.ts
ADDED