ts-procedures 10.1.2 → 10.2.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 +26 -91
- package/README.md +2 -0
- package/agent_config/claude-code/skills/ts-procedures/anti-patterns.md +8 -0
- package/agent_config/claude-code/skills/ts-procedures/api-reference.md +25 -22
- package/agent_config/claude-code/skills/ts-procedures/patterns.md +24 -13
- package/agent_config/copilot/copilot-instructions.md +1 -1
- package/agent_config/cursor/cursorrules +1 -1
- package/build/adapters/hono/envelope-parity.test.js +6 -17
- package/build/adapters/hono/envelope-parity.test.js.map +1 -1
- package/build/adapters/hono/handlers/http-stream.d.ts +2 -1
- package/build/adapters/hono/handlers/http-stream.js +9 -2
- package/build/adapters/hono/handlers/http-stream.js.map +1 -1
- package/build/adapters/hono/handlers/http.d.ts +2 -1
- package/build/adapters/hono/handlers/http.js +9 -2
- package/build/adapters/hono/handlers/http.js.map +1 -1
- package/build/adapters/hono/handlers/rpc.d.ts +2 -1
- package/build/adapters/hono/handlers/rpc.js +9 -2
- package/build/adapters/hono/handlers/rpc.js.map +1 -1
- package/build/adapters/hono/handlers/stream.d.ts +2 -1
- package/build/adapters/hono/handlers/stream.js +9 -2
- package/build/adapters/hono/handlers/stream.js.map +1 -1
- package/build/adapters/hono/index.d.ts +14 -7
- package/build/adapters/hono/index.js +45 -5
- package/build/adapters/hono/index.js.map +1 -1
- package/build/adapters/hono/index.test.js +55 -0
- package/build/adapters/hono/index.test.js.map +1 -1
- package/build/adapters/hono/request.d.ts +7 -0
- package/build/adapters/hono/request.js +15 -0
- package/build/adapters/hono/request.js.map +1 -1
- package/build/adapters/hono/types.d.ts +31 -0
- package/build/adapters/hono/types.js.map +1 -1
- package/build/codegen/bin/cli.js +1 -1
- package/build/codegen/bin/cli.js.map +1 -1
- package/build/codegen/constants.js +2 -2
- package/build/codegen/constants.js.map +1 -1
- package/build/codegen/emit/api-route.js +1 -1
- package/build/codegen/emit/api-route.js.map +1 -1
- package/build/codegen/emit/scope-file.js +1 -1
- package/build/codegen/emit/scope-file.js.map +1 -1
- package/build/codegen/emit-errors.integration.test.js +2 -2
- package/build/codegen/emit-errors.integration.test.js.map +1 -1
- package/build/codegen/resolve-envelope.js +1 -1
- package/build/codegen/resolve-envelope.js.map +1 -1
- package/build/codegen/test-helpers/run-tsc.js +1 -1
- package/build/codegen/test-helpers/run-tsc.js.map +1 -1
- package/build/core/create-http-stream.d.ts +3 -14
- package/build/core/create-http-stream.js +4 -2
- package/build/core/create-http-stream.js.map +1 -1
- package/build/core/create-http.d.ts +2 -9
- package/build/core/create-http.js +3 -2
- package/build/core/create-http.js.map +1 -1
- package/build/core/create-http.test-d.js +104 -0
- package/build/core/create-http.test-d.js.map +1 -0
- package/build/core/create-stream.js +6 -2
- package/build/core/create-stream.js.map +1 -1
- package/build/core/create.js +5 -4
- package/build/core/create.js.map +1 -1
- package/build/core/create.test.js +63 -0
- package/build/core/create.test.js.map +1 -1
- package/build/core/internal.d.ts +16 -0
- package/build/core/internal.js +22 -0
- package/build/core/internal.js.map +1 -1
- package/build/core/procedures.d.ts +9 -16
- package/build/core/procedures.js +4 -0
- package/build/core/procedures.js.map +1 -1
- package/build/core/types.d.ts +85 -4
- package/build/errors.d.ts +33 -0
- package/build/errors.js +91 -0
- package/build/errors.js.map +1 -0
- package/build/errors.test.d.ts +1 -0
- package/build/errors.test.js +122 -0
- package/build/errors.test.js.map +1 -0
- package/build/exports.d.ts +1 -2
- package/build/exports.js +0 -4
- package/build/exports.js.map +1 -1
- package/build/implementations/http/doc-registry.d.ts +28 -0
- package/build/implementations/http/doc-registry.js +96 -0
- package/build/implementations/http/doc-registry.js.map +1 -0
- package/build/implementations/http/doc-registry.test.d.ts +1 -0
- package/build/implementations/http/doc-registry.test.js +516 -0
- package/build/implementations/http/doc-registry.test.js.map +1 -0
- package/build/implementations/http/error-taxonomy.d.ts +249 -0
- package/build/implementations/http/error-taxonomy.js +252 -0
- package/build/implementations/http/error-taxonomy.js.map +1 -0
- package/build/implementations/http/error-taxonomy.test.d.ts +1 -0
- package/build/implementations/http/error-taxonomy.test.js +399 -0
- package/build/implementations/http/error-taxonomy.test.js.map +1 -0
- package/build/implementations/http/express-rpc/error-taxonomy.test.d.ts +1 -0
- package/build/implementations/http/express-rpc/error-taxonomy.test.js +83 -0
- package/build/implementations/http/express-rpc/error-taxonomy.test.js.map +1 -0
- package/build/implementations/http/express-rpc/index.d.ts +125 -0
- package/build/implementations/http/express-rpc/index.js +216 -0
- package/build/implementations/http/express-rpc/index.js.map +1 -0
- package/build/implementations/http/express-rpc/index.test.d.ts +1 -0
- package/build/implementations/http/express-rpc/index.test.js +684 -0
- package/build/implementations/http/express-rpc/index.test.js.map +1 -0
- package/build/implementations/http/express-rpc/types.d.ts +11 -0
- package/build/implementations/http/express-rpc/types.js +2 -0
- package/build/implementations/http/express-rpc/types.js.map +1 -0
- package/build/implementations/http/hono-api/error-taxonomy.test.d.ts +1 -0
- package/build/implementations/http/hono-api/error-taxonomy.test.js +137 -0
- package/build/implementations/http/hono-api/error-taxonomy.test.js.map +1 -0
- package/build/implementations/http/hono-api/index.d.ts +151 -0
- package/build/implementations/http/hono-api/index.js +344 -0
- package/build/implementations/http/hono-api/index.js.map +1 -0
- package/build/implementations/http/hono-api/index.test.d.ts +1 -0
- package/build/implementations/http/hono-api/index.test.js +992 -0
- package/build/implementations/http/hono-api/index.test.js.map +1 -0
- package/build/implementations/http/hono-api/types.d.ts +13 -0
- package/build/implementations/http/hono-api/types.js +2 -0
- package/build/implementations/http/hono-api/types.js.map +1 -0
- package/build/implementations/http/hono-rpc/error-taxonomy.test.d.ts +1 -0
- package/build/implementations/http/hono-rpc/error-taxonomy.test.js +64 -0
- package/build/implementations/http/hono-rpc/error-taxonomy.test.js.map +1 -0
- package/build/implementations/http/hono-rpc/index.d.ts +130 -0
- package/build/implementations/http/hono-rpc/index.js +209 -0
- package/build/implementations/http/hono-rpc/index.js.map +1 -0
- package/build/implementations/http/hono-rpc/index.test.d.ts +1 -0
- package/build/implementations/http/hono-rpc/index.test.js +828 -0
- package/build/implementations/http/hono-rpc/index.test.js.map +1 -0
- package/build/implementations/http/hono-rpc/types.d.ts +11 -0
- package/build/implementations/http/hono-rpc/types.js +2 -0
- package/build/implementations/http/hono-rpc/types.js.map +1 -0
- package/build/implementations/http/hono-stream/error-taxonomy.test.d.ts +1 -0
- package/build/implementations/http/hono-stream/error-taxonomy.test.js +159 -0
- package/build/implementations/http/hono-stream/error-taxonomy.test.js.map +1 -0
- package/build/implementations/http/hono-stream/index.d.ts +171 -0
- package/build/implementations/http/hono-stream/index.js +415 -0
- package/build/implementations/http/hono-stream/index.js.map +1 -0
- package/build/implementations/http/hono-stream/index.test.d.ts +1 -0
- package/build/implementations/http/hono-stream/index.test.js +1383 -0
- package/build/implementations/http/hono-stream/index.test.js.map +1 -0
- package/build/implementations/http/hono-stream/types.d.ts +15 -0
- package/build/implementations/http/hono-stream/types.js +2 -0
- package/build/implementations/http/hono-stream/types.js.map +1 -0
- package/build/implementations/http/on-request-error.test.d.ts +1 -0
- package/build/implementations/http/on-request-error.test.js +173 -0
- package/build/implementations/http/on-request-error.test.js.map +1 -0
- package/build/implementations/http/route-errors.test.d.ts +1 -0
- package/build/implementations/http/route-errors.test.js +139 -0
- package/build/implementations/http/route-errors.test.js.map +1 -0
- package/build/implementations/types.d.ts +192 -0
- package/build/implementations/types.js +2 -0
- package/build/implementations/types.js.map +1 -0
- package/build/index.d.ts +165 -0
- package/build/index.js +258 -0
- package/build/index.js.map +1 -0
- package/build/index.test.d.ts +1 -0
- package/build/index.test.js +920 -0
- package/build/index.test.js.map +1 -0
- package/build/schema/compute-schema.js +1 -5
- package/build/schema/compute-schema.js.map +1 -1
- package/build/schema/compute-schema.test.js +0 -13
- package/build/schema/compute-schema.test.js.map +1 -1
- package/build/schema/extract-json-schema.d.ts +2 -0
- package/build/schema/extract-json-schema.js +12 -0
- package/build/schema/extract-json-schema.js.map +1 -0
- package/build/schema/extract-json-schema.test.d.ts +1 -0
- package/build/schema/extract-json-schema.test.js +23 -0
- package/build/schema/extract-json-schema.test.js.map +1 -0
- package/build/schema/parser.d.ts +28 -0
- package/build/schema/parser.js +170 -0
- package/build/schema/parser.js.map +1 -0
- package/build/schema/parser.test.d.ts +1 -0
- package/build/schema/parser.test.js +120 -0
- package/build/schema/parser.test.js.map +1 -0
- package/build/schema/resolve-schema-lib.d.ts +12 -0
- package/build/schema/resolve-schema-lib.js +11 -0
- package/build/schema/resolve-schema-lib.js.map +1 -0
- package/build/schema/resolve-schema-lib.test.d.ts +1 -0
- package/build/schema/resolve-schema-lib.test.js +17 -0
- package/build/schema/resolve-schema-lib.test.js.map +1 -0
- package/build/schema/typebox.d.ts +1 -1
- package/build/schema/typebox.js +2 -20
- package/build/schema/typebox.js.map +1 -1
- package/build/schema/typebox.test.js +0 -10
- package/build/schema/typebox.test.js.map +1 -1
- package/build/schema/types.d.ts +8 -0
- package/build/schema/types.js +2 -0
- package/build/schema/types.js.map +1 -0
- package/build/server/context.d.ts +12 -2
- package/build/server/context.js +49 -4
- package/build/server/context.js.map +1 -1
- package/build/server/context.test.js +32 -1
- package/build/server/context.test.js.map +1 -1
- package/build/server/doc-registry.js +0 -3
- package/build/server/doc-registry.js.map +1 -1
- package/build/server/doc-registry.test.js +0 -31
- package/build/server/doc-registry.test.js.map +1 -1
- package/build/server/index.d.ts +0 -1
- package/build/server/index.js +0 -1
- package/build/server/index.js.map +1 -1
- package/build/server/types.d.ts +6 -27
- package/build/stack-utils.d.ts +25 -0
- package/build/stack-utils.js +95 -0
- package/build/stack-utils.js.map +1 -0
- package/build/stack-utils.test.d.ts +1 -0
- package/build/stack-utils.test.js +80 -0
- package/build/stack-utils.test.js.map +1 -0
- package/docs/core.md +8 -0
- package/docs/http-integrations.md +41 -27
- package/package.json +8 -8
- package/src/adapters/astro/README.md +2 -0
- package/src/adapters/hono/envelope-parity.test.ts +6 -18
- package/src/adapters/hono/handlers/http-stream.ts +12 -3
- package/src/adapters/hono/handlers/http.ts +12 -3
- package/src/adapters/hono/handlers/rpc.ts +12 -3
- package/src/adapters/hono/handlers/stream.ts +12 -3
- package/src/adapters/hono/index.test.ts +70 -0
- package/src/adapters/hono/index.ts +53 -11
- package/src/adapters/hono/request.ts +18 -0
- package/src/adapters/hono/types.ts +37 -0
- package/src/codegen/bin/cli.ts +1 -1
- package/src/codegen/constants.ts +2 -2
- package/src/codegen/emit/api-route.ts +1 -1
- package/src/codegen/emit/scope-file.ts +1 -2
- package/src/codegen/emit-errors.integration.test.ts +2 -2
- package/src/codegen/resolve-envelope.ts +1 -1
- package/src/codegen/test-helpers/run-tsc.ts +0 -1
- package/src/core/create-http-stream.ts +20 -13
- package/src/core/create-http.test-d.ts +154 -0
- package/src/core/create-http.ts +19 -8
- package/src/core/create-stream.ts +12 -4
- package/src/core/create.test.ts +74 -0
- package/src/core/create.ts +10 -5
- package/src/core/internal.ts +35 -0
- package/src/core/procedures.ts +4 -0
- package/src/core/types.ts +99 -4
- package/src/exports.ts +6 -4
- package/src/schema/compute-schema.test.ts +0 -16
- package/src/schema/compute-schema.ts +1 -5
- package/src/schema/typebox.test.ts +0 -12
- package/src/schema/typebox.ts +2 -21
- package/src/server/context.test.ts +39 -1
- package/src/server/context.ts +54 -4
- package/src/server/doc-registry.test.ts +0 -34
- package/src/server/doc-registry.ts +0 -3
- package/src/server/index.ts +0 -1
- package/src/server/types.ts +8 -27
- package/build/schema/strip-internal-keywords.d.ts +0 -18
- package/build/schema/strip-internal-keywords.js +0 -33
- package/build/schema/strip-internal-keywords.js.map +0 -1
- package/build/schema/strip-internal-keywords.test.js +0 -38
- package/build/schema/strip-internal-keywords.test.js.map +0 -1
- package/build/server/spec-version.d.ts +0 -24
- package/build/server/spec-version.js +0 -26
- package/build/server/spec-version.js.map +0 -1
- package/build/version.d.ts +0 -9
- package/build/version.js +0 -11
- package/build/version.js.map +0 -1
- package/docs/doc-envelope-spec-v1.md +0 -296
- package/docs/doc-envelope-v1.schema.json +0 -253
- package/src/schema/strip-internal-keywords.test.ts +0 -43
- package/src/schema/strip-internal-keywords.ts +0 -36
- package/src/server/spec-version.ts +0 -27
- package/src/version.ts +0 -11
- /package/build/{schema/strip-internal-keywords.test.d.ts → core/create-http.test-d.d.ts} +0 -0
package/src/server/types.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* guarantees byte-identical generated output vs v8. Do not change field names,
|
|
7
7
|
* optionality, or nesting without re-validating the codegen goldens.
|
|
8
8
|
*/
|
|
9
|
-
import type { ProcedureKind } from '../core/types.js'
|
|
9
|
+
import type { ProcedureKind, THttpReqInput } from '../core/types.js'
|
|
10
10
|
import type { ErrorTaxonomy } from './errors/taxonomy.js'
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -97,6 +97,9 @@ export interface APIHttpRouteDoc {
|
|
|
97
97
|
* Constrains `schema.req` channel names to valid HTTP input sources.
|
|
98
98
|
* Use with `satisfies` to catch typos at compile time:
|
|
99
99
|
*
|
|
100
|
+
* The same shape also powers autocomplete inside `schema.req` when using
|
|
101
|
+
* CreateHttp / CreateHttpStream.
|
|
102
|
+
*
|
|
100
103
|
* @example
|
|
101
104
|
* schema: {
|
|
102
105
|
* req: {
|
|
@@ -105,17 +108,10 @@ export interface APIHttpRouteDoc {
|
|
|
105
108
|
* } satisfies APIInput
|
|
106
109
|
* }
|
|
107
110
|
*/
|
|
108
|
-
export type APIInput<T extends
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
headers?: unknown
|
|
113
|
-
} = {
|
|
114
|
-
pathParams?: unknown
|
|
115
|
-
query?: unknown
|
|
116
|
-
body?: unknown
|
|
117
|
-
headers?: unknown
|
|
118
|
-
}> = T
|
|
111
|
+
export type APIInput<T extends THttpReqInput = THttpReqInput> = T
|
|
112
|
+
|
|
113
|
+
// Re-export the canonical input shapes (useful for advanced typing or custom wrappers)
|
|
114
|
+
export type { THttpReqInput, THttpResInput } from '../core/types.js'
|
|
119
115
|
|
|
120
116
|
export interface StreamHttpRouteDoc extends RPCConfig {
|
|
121
117
|
kind: 'stream'
|
|
@@ -250,21 +246,6 @@ export interface DocRegistryOutputOptions<TEnvelope = DocEnvelope> {
|
|
|
250
246
|
}
|
|
251
247
|
|
|
252
248
|
export interface DocEnvelope {
|
|
253
|
-
/**
|
|
254
|
-
* Wire-format version of this envelope. Every envelope produced by
|
|
255
|
-
* `DocRegistry.toJSON()` / `builder.toDocEnvelope()` carries it. Downstream
|
|
256
|
-
* consumers branch on it to pick a parser; bumped only on envelope format
|
|
257
|
-
* changes, NOT on package releases. Optional on the type so hand-built
|
|
258
|
-
* envelopes and pre-existing documents remain valid — an absent value MUST be
|
|
259
|
-
* treated as spec version 1. See {@link DOC_ENVELOPE_SPEC_VERSION}.
|
|
260
|
-
*/
|
|
261
|
-
specVersion?: number
|
|
262
|
-
/**
|
|
263
|
-
* ts-procedures package version that produced this envelope (e.g. `"10.0.0"`).
|
|
264
|
-
* Informational only — do not use for parse-compatibility decisions (use
|
|
265
|
-
* {@link specVersion} for that). See {@link DOC_ENVELOPE_GENERATOR_VERSION}.
|
|
266
|
-
*/
|
|
267
|
-
generatorVersion?: string
|
|
268
249
|
basePath: string
|
|
269
250
|
headers: HeaderDoc[]
|
|
270
251
|
errors: ErrorDoc[]
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { TJSONSchema } from './json-schema.js';
|
|
2
|
-
/**
|
|
3
|
-
* Deep-removes TypeBox v1 internal markers (`~kind`, `~unsafe`, `~optional`, …)
|
|
4
|
-
* from an extracted JSON Schema, returning a fresh structure (never mutates the
|
|
5
|
-
* input).
|
|
6
|
-
*
|
|
7
|
-
* These markers are *usually* non-enumerable, so they stay out of JSON Schema on
|
|
8
|
-
* their own. But some compositions leak them as **enumerable** own properties —
|
|
9
|
-
* notably `Type.Optional(Type.Unsafe({...}))`, which emits `~unsafe`/`~optional`
|
|
10
|
-
* inline. Left in place those markers (a) pollute serialized docs/codegen output
|
|
11
|
-
* and (b) make strict AJV throw `unknown keyword: "~unsafe"` at registration.
|
|
12
|
-
*
|
|
13
|
-
* Stripping by the `~`-prefix convention (rather than a fixed name list) keeps
|
|
14
|
-
* this robust against future TypeBox markers — same convention the TypeBox
|
|
15
|
-
* adapter detects on.
|
|
16
|
-
*/
|
|
17
|
-
export declare function stripInternalKeywords<T>(schema: T): T;
|
|
18
|
-
export type { TJSONSchema };
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/** TypeBox v1 prefixes every internal marker key with `~`. */
|
|
2
|
-
const TILDE = '~';
|
|
3
|
-
/**
|
|
4
|
-
* Deep-removes TypeBox v1 internal markers (`~kind`, `~unsafe`, `~optional`, …)
|
|
5
|
-
* from an extracted JSON Schema, returning a fresh structure (never mutates the
|
|
6
|
-
* input).
|
|
7
|
-
*
|
|
8
|
-
* These markers are *usually* non-enumerable, so they stay out of JSON Schema on
|
|
9
|
-
* their own. But some compositions leak them as **enumerable** own properties —
|
|
10
|
-
* notably `Type.Optional(Type.Unsafe({...}))`, which emits `~unsafe`/`~optional`
|
|
11
|
-
* inline. Left in place those markers (a) pollute serialized docs/codegen output
|
|
12
|
-
* and (b) make strict AJV throw `unknown keyword: "~unsafe"` at registration.
|
|
13
|
-
*
|
|
14
|
-
* Stripping by the `~`-prefix convention (rather than a fixed name list) keeps
|
|
15
|
-
* this robust against future TypeBox markers — same convention the TypeBox
|
|
16
|
-
* adapter detects on.
|
|
17
|
-
*/
|
|
18
|
-
export function stripInternalKeywords(schema) {
|
|
19
|
-
if (Array.isArray(schema)) {
|
|
20
|
-
return schema.map((item) => stripInternalKeywords(item));
|
|
21
|
-
}
|
|
22
|
-
if (schema !== null && typeof schema === 'object') {
|
|
23
|
-
const out = {};
|
|
24
|
-
for (const [key, value] of Object.entries(schema)) {
|
|
25
|
-
if (key.startsWith(TILDE))
|
|
26
|
-
continue;
|
|
27
|
-
out[key] = stripInternalKeywords(value);
|
|
28
|
-
}
|
|
29
|
-
return out;
|
|
30
|
-
}
|
|
31
|
-
return schema;
|
|
32
|
-
}
|
|
33
|
-
//# sourceMappingURL=strip-internal-keywords.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"strip-internal-keywords.js","sourceRoot":"","sources":["../../src/schema/strip-internal-keywords.ts"],"names":[],"mappings":"AAEA,8DAA8D;AAC9D,MAAM,KAAK,GAAG,GAAG,CAAA;AAEjB;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,qBAAqB,CAAI,MAAS;IAChD,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAM,CAAA;IAC/D,CAAC;IACD,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAClD,MAAM,GAAG,GAA4B,EAAE,CAAA;QACvC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAClD,IAAI,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC;gBAAE,SAAQ;YACnC,GAAG,CAAC,GAAG,CAAC,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAA;QACzC,CAAC;QACD,OAAO,GAAQ,CAAA;IACjB,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC"}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from 'vitest';
|
|
2
|
-
import { Type } from 'typebox';
|
|
3
|
-
import { stripInternalKeywords } from './strip-internal-keywords.js';
|
|
4
|
-
describe('stripInternalKeywords', () => {
|
|
5
|
-
test('removes enumerable ~-prefixed markers leaked by Type.Optional(Type.Unsafe(...))', () => {
|
|
6
|
-
// This composition emits `~unsafe`/`~optional` as ENUMERABLE own props.
|
|
7
|
-
const leaky = Type.Optional(Type.Unsafe({ type: 'string' }));
|
|
8
|
-
expect(Object.keys(leaky).some((k) => k.startsWith('~'))).toBe(true);
|
|
9
|
-
const clean = stripInternalKeywords(leaky);
|
|
10
|
-
expect(clean).toEqual({ type: 'string' });
|
|
11
|
-
expect(Object.keys(clean).some((k) => k.startsWith('~'))).toBe(false);
|
|
12
|
-
});
|
|
13
|
-
test('strips markers nested inside object properties', () => {
|
|
14
|
-
const schema = Type.Object({ x: Type.Optional(Type.Unsafe({ type: 'string' })) });
|
|
15
|
-
const clean = stripInternalKeywords(schema);
|
|
16
|
-
expect(JSON.stringify(clean)).not.toMatch(/~/);
|
|
17
|
-
expect(clean.properties.x).toEqual({ type: 'string' });
|
|
18
|
-
});
|
|
19
|
-
test('strips markers inside arrays (e.g. anyOf members)', () => {
|
|
20
|
-
const schema = {
|
|
21
|
-
anyOf: [Type.Unsafe({ type: 'string' }), { type: 'number', '~optional': true }],
|
|
22
|
-
};
|
|
23
|
-
const clean = stripInternalKeywords(schema);
|
|
24
|
-
expect(clean.anyOf).toEqual([{ type: 'string' }, { type: 'number' }]);
|
|
25
|
-
});
|
|
26
|
-
test('leaves a clean schema structurally equal and does not mutate the input', () => {
|
|
27
|
-
const input = { type: 'object', properties: { a: { type: 'string' } } };
|
|
28
|
-
const clean = stripInternalKeywords(input);
|
|
29
|
-
expect(clean).toEqual(input);
|
|
30
|
-
expect(clean).not.toBe(input); // fresh structure
|
|
31
|
-
});
|
|
32
|
-
test('passes primitives through unchanged', () => {
|
|
33
|
-
expect(stripInternalKeywords('x')).toBe('x');
|
|
34
|
-
expect(stripInternalKeywords(5)).toBe(5);
|
|
35
|
-
expect(stripInternalKeywords(null)).toBe(null);
|
|
36
|
-
});
|
|
37
|
-
});
|
|
38
|
-
//# sourceMappingURL=strip-internal-keywords.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"strip-internal-keywords.test.js","sourceRoot":"","sources":["../../src/schema/strip-internal-keywords.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Spec version of the {@link DocEnvelope} wire format.
|
|
3
|
-
*
|
|
4
|
-
* Bump this ONLY when the envelope shape changes in a way downstream parsers
|
|
5
|
-
* must react to — field renames, nesting changes, or semantic changes. Do NOT
|
|
6
|
-
* bump it on ordinary package releases (dependency upgrades, bug fixes, new
|
|
7
|
-
* optional fields that older parsers can safely ignore). It is decoupled from
|
|
8
|
-
* the npm package version on purpose, so consumers get a small monotonic
|
|
9
|
-
* integer to branch on instead of having to interpret semver.
|
|
10
|
-
*
|
|
11
|
-
* Consumer contract: an envelope with no `specVersion` field predates this
|
|
12
|
-
* field and MUST be treated as spec version 1.
|
|
13
|
-
*/
|
|
14
|
-
export declare const DOC_ENVELOPE_SPEC_VERSION = 1;
|
|
15
|
-
/**
|
|
16
|
-
* The ts-procedures package version that produced an envelope (e.g. `"10.0.0"`).
|
|
17
|
-
* Populates the envelope's `generatorVersion` field.
|
|
18
|
-
*
|
|
19
|
-
* Informational only — for telemetry, debugging, and "which release served
|
|
20
|
-
* this?" questions. Do NOT use it to decide parse compatibility; it churns on
|
|
21
|
-
* every release regardless of whether the envelope format changed. Use
|
|
22
|
-
* {@link DOC_ENVELOPE_SPEC_VERSION} for compatibility decisions.
|
|
23
|
-
*/
|
|
24
|
-
export declare const DOC_ENVELOPE_GENERATOR_VERSION: string;
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { PACKAGE_VERSION } from '../version.js';
|
|
2
|
-
/**
|
|
3
|
-
* Spec version of the {@link DocEnvelope} wire format.
|
|
4
|
-
*
|
|
5
|
-
* Bump this ONLY when the envelope shape changes in a way downstream parsers
|
|
6
|
-
* must react to — field renames, nesting changes, or semantic changes. Do NOT
|
|
7
|
-
* bump it on ordinary package releases (dependency upgrades, bug fixes, new
|
|
8
|
-
* optional fields that older parsers can safely ignore). It is decoupled from
|
|
9
|
-
* the npm package version on purpose, so consumers get a small monotonic
|
|
10
|
-
* integer to branch on instead of having to interpret semver.
|
|
11
|
-
*
|
|
12
|
-
* Consumer contract: an envelope with no `specVersion` field predates this
|
|
13
|
-
* field and MUST be treated as spec version 1.
|
|
14
|
-
*/
|
|
15
|
-
export const DOC_ENVELOPE_SPEC_VERSION = 1;
|
|
16
|
-
/**
|
|
17
|
-
* The ts-procedures package version that produced an envelope (e.g. `"10.0.0"`).
|
|
18
|
-
* Populates the envelope's `generatorVersion` field.
|
|
19
|
-
*
|
|
20
|
-
* Informational only — for telemetry, debugging, and "which release served
|
|
21
|
-
* this?" questions. Do NOT use it to decide parse compatibility; it churns on
|
|
22
|
-
* every release regardless of whether the envelope format changed. Use
|
|
23
|
-
* {@link DOC_ENVELOPE_SPEC_VERSION} for compatibility decisions.
|
|
24
|
-
*/
|
|
25
|
-
export const DOC_ENVELOPE_GENERATOR_VERSION = PACKAGE_VERSION;
|
|
26
|
-
//# sourceMappingURL=spec-version.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"spec-version.js","sourceRoot":"","sources":["../../src/server/spec-version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAE/C;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAA;AAE1C;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAW,eAAe,CAAA"}
|
package/build/version.d.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The ts-procedures package version (e.g. `"10.0.0"`), read from `package.json`.
|
|
3
|
-
*
|
|
4
|
-
* Single source of truth for "which version is this build?" — consumed by the
|
|
5
|
-
* codegen file header and the doc-envelope `generatorVersion`. Import this
|
|
6
|
-
* rather than re-importing `package.json`, so there's one place the version
|
|
7
|
-
* enters the source tree.
|
|
8
|
-
*/
|
|
9
|
-
export declare const PACKAGE_VERSION: string;
|
package/build/version.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import pkg from '../package.json' with { type: 'json' };
|
|
2
|
-
/**
|
|
3
|
-
* The ts-procedures package version (e.g. `"10.0.0"`), read from `package.json`.
|
|
4
|
-
*
|
|
5
|
-
* Single source of truth for "which version is this build?" — consumed by the
|
|
6
|
-
* codegen file header and the doc-envelope `generatorVersion`. Import this
|
|
7
|
-
* rather than re-importing `package.json`, so there's one place the version
|
|
8
|
-
* enters the source tree.
|
|
9
|
-
*/
|
|
10
|
-
export const PACKAGE_VERSION = pkg.version;
|
|
11
|
-
//# sourceMappingURL=version.js.map
|
package/build/version.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,iBAAiB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAA;AAEvD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,eAAe,GAAW,GAAG,CAAC,OAAO,CAAA"}
|
|
@@ -1,296 +0,0 @@
|
|
|
1
|
-
# ts-procedures DocEnvelope — Consumer Spec (`specVersion: 1`)
|
|
2
|
-
|
|
3
|
-
> **This document describes DocEnvelope `specVersion: 1`.** The filename is
|
|
4
|
-
> pinned to the spec version (`-v1`) so future format changes land as a sibling
|
|
5
|
-
> (`doc-envelope-spec-v2.md`) and the differences stay diffable. Check the
|
|
6
|
-
> envelope's `specVersion` field (absent ⇒ `1`) to know which spec applies.
|
|
7
|
-
|
|
8
|
-
A spec for a GUI that fetches a `DocEnvelope` JSON document from a ts-procedures
|
|
9
|
-
server URL and renders it. This is the **stable wire contract** between a
|
|
10
|
-
ts-procedures server and any documentation/codegen consumer. It is a *frozen*
|
|
11
|
-
contract in the framework (changing field names/nesting breaks codegen goldens),
|
|
12
|
-
so you can build against it confidently.
|
|
13
|
-
|
|
14
|
-
Companion file: `doc-envelope-v1.schema.json` (JSON Schema Draft-07) — validate
|
|
15
|
-
fetched documents against it.
|
|
16
|
-
|
|
17
|
-
---
|
|
18
|
-
|
|
19
|
-
## 1. How you get the document
|
|
20
|
-
|
|
21
|
-
There is **no built-in endpoint**. A server author calls
|
|
22
|
-
`builder.toDocEnvelope()` (or `DocRegistry.toJSON()`) and exposes the resulting
|
|
23
|
-
JSON at a route of their choosing (e.g. `GET /api/docs`, `/openapi`, a static
|
|
24
|
-
`.json` file, etc.).
|
|
25
|
-
|
|
26
|
-
So your website's "paste a URL" flow should:
|
|
27
|
-
|
|
28
|
-
1. `fetch(url)` the user-supplied URL.
|
|
29
|
-
2. Expect `Content-Type` ~ JSON; `JSON.parse` the body.
|
|
30
|
-
3. Validate that it is an object with a `routes` **array**. That single check is
|
|
31
|
-
what the official codegen uses as its "is this an envelope?" gate. If
|
|
32
|
-
`routes` is missing/not-an-array, show a clear "not a ts-procedures docs
|
|
33
|
-
document" error.
|
|
34
|
-
4. Optionally validate fully against `doc-envelope-v1.schema.json`.
|
|
35
|
-
|
|
36
|
-
CORS: the server must allow your origin, or you'll need a proxy. Worth surfacing
|
|
37
|
-
as a distinct error from "bad JSON".
|
|
38
|
-
|
|
39
|
-
---
|
|
40
|
-
|
|
41
|
-
## 2. Top-level shape
|
|
42
|
-
|
|
43
|
-
```ts
|
|
44
|
-
interface DocEnvelope {
|
|
45
|
-
specVersion?: number // envelope wire-format version; absent ⇒ treat as 1
|
|
46
|
-
generatorVersion?: string // producing ts-procedures version, e.g. "10.0.0" (informational)
|
|
47
|
-
basePath: string // e.g. "/api" (may be "")
|
|
48
|
-
headers: HeaderDoc[] // global headers (often [])
|
|
49
|
-
errors: ErrorDoc[] // the error catalog
|
|
50
|
-
routes: AnyRouteDoc[] // every procedure/route
|
|
51
|
-
}
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
The authoritative producer (`DocRegistry.toJSON`) emits these six keys.
|
|
55
|
-
Resilience notes:
|
|
56
|
-
|
|
57
|
-
- **`specVersion`** is your compatibility signal — a small monotonic integer
|
|
58
|
-
that increments **only** when the envelope format changes (never on routine
|
|
59
|
-
package releases). **Branch your parser on this.** Treat a **missing**
|
|
60
|
-
`specVersion` as `1` (documents predating the field). Refuse / warn on a
|
|
61
|
-
`specVersion` higher than your GUI knows about. Current value: `1`.
|
|
62
|
-
- **`generatorVersion`** is the producing ts-procedures package version (e.g.
|
|
63
|
-
`"10.0.0"`). **Informational only** — show it in a footer/tooltip, but do
|
|
64
|
-
**not** use it to decide how to parse; it changes every release regardless of
|
|
65
|
-
format. (Note: one internal codegen *input* fixture carries an unrelated
|
|
66
|
-
top-level `"version"` string and uppercase methods — that's a loose
|
|
67
|
-
hand-authored fixture, not server output; ignore `version` if you ever see it.)
|
|
68
|
-
- Be tolerant of **extra top-level keys** — treat unknown keys as opaque.
|
|
69
|
-
- `headers` and `errors` are commonly empty arrays. Render gracefully.
|
|
70
|
-
|
|
71
|
-
---
|
|
72
|
-
|
|
73
|
-
## 3. The error catalog (`errors`)
|
|
74
|
-
|
|
75
|
-
```ts
|
|
76
|
-
interface ErrorDoc {
|
|
77
|
-
name: string // unique; routes reference it by this name
|
|
78
|
-
statusCode: number // HTTP status, e.g. 400, 404, 418, 500
|
|
79
|
-
description: string
|
|
80
|
-
schema?: Record<string, unknown> // JSON Schema of the error body (optional)
|
|
81
|
-
}
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
Framework defaults are auto-merged and always present unless opted out:
|
|
85
|
-
`ProcedureValidationError` (400), `ProcedureYieldValidationError` (500),
|
|
86
|
-
`ProcedureError` (500), `ProcedureRegistrationError` (500). User taxonomy errors
|
|
87
|
-
(e.g. `NotFound` 404, `Teapot` 418) appear alongside them.
|
|
88
|
-
|
|
89
|
-
**GUI tip:** build a `Map<name, ErrorDoc>`. Each route's `errors: string[]` is a
|
|
90
|
-
list of these names — render them as links/badges that resolve to the catalog
|
|
91
|
-
entry (status code + description + body schema).
|
|
92
|
-
|
|
93
|
-
---
|
|
94
|
-
|
|
95
|
-
## 4. Global headers (`headers`)
|
|
96
|
-
|
|
97
|
-
```ts
|
|
98
|
-
interface HeaderDoc {
|
|
99
|
-
name: string
|
|
100
|
-
description?: string
|
|
101
|
-
required?: boolean
|
|
102
|
-
example?: string
|
|
103
|
-
}
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
Simple list; render as a small table. Often empty.
|
|
107
|
-
|
|
108
|
-
---
|
|
109
|
-
|
|
110
|
-
## 5. Routes — discriminated union on `kind`
|
|
111
|
-
|
|
112
|
-
`routes[]` mixes four kinds. **Always switch on `route.kind`.** Every route has a
|
|
113
|
-
`name` and a `jsonSchema` object; the rest varies by kind.
|
|
114
|
-
|
|
115
|
-
| `kind` | Transport | Path field(s) | Method field | Payload schema keys |
|
|
116
|
-
|-----------------|----------------------|----------------------|---------------------|----------------------------------------------|
|
|
117
|
-
| `rpc` | JSON-RPC (POST) | `path` | `method: "post"` | `body`, `response` |
|
|
118
|
-
| `stream` | RPC stream (SSE/text)| `path` | `methods: string[]` | `params`, `yieldType`, `returnType` |
|
|
119
|
-
| `api` | REST | `path?`, `fullPath` | `method` | `req.{pathParams,query,body,headers}`, `res.{body,headers}` |
|
|
120
|
-
| `http-stream` | REST stream (SSE) | `path?`, `fullPath` | `method` | `req.{...}`, `res.{headers}`, `yield`, `returnType` |
|
|
121
|
-
|
|
122
|
-
Common fields: `name` (string), `errors?` (string[] → catalog names),
|
|
123
|
-
`scope` (grouping; `string | string[]` for rpc/stream, `string` for api/http-stream).
|
|
124
|
-
|
|
125
|
-
> **No per-route `description`.** A `description` passed at procedure-definition
|
|
126
|
-
> time is **not** carried into the route doc. Don't build UI that depends on it.
|
|
127
|
-
|
|
128
|
-
### 5.1 `rpc`
|
|
129
|
-
|
|
130
|
-
```jsonc
|
|
131
|
-
{
|
|
132
|
-
"kind": "rpc",
|
|
133
|
-
"name": "GetUser",
|
|
134
|
-
"version": 1,
|
|
135
|
-
"scope": "users",
|
|
136
|
-
"path": "/api/users/get-user/1", // full path; embeds scope + version
|
|
137
|
-
"method": "post",
|
|
138
|
-
"jsonSchema": {
|
|
139
|
-
"body": { "type": "object", "required": ["id"], "properties": { "id": { "type": "string" } } },
|
|
140
|
-
"response": { "type": "object", "required": ["id","name"], "properties": { "id":{"type":"string"}, "name":{"type":"string"} } }
|
|
141
|
-
},
|
|
142
|
-
"errors": ["Teapot"]
|
|
143
|
-
}
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
- `jsonSchema.body` = request input (runtime-validated).
|
|
147
|
-
- `jsonSchema.response` = response shape (documentation only).
|
|
148
|
-
- Both are optional (a no-arg/no-return procedure yields `jsonSchema: {}`).
|
|
149
|
-
|
|
150
|
-
### 5.2 `stream` (RPC stream)
|
|
151
|
-
|
|
152
|
-
```jsonc
|
|
153
|
-
{
|
|
154
|
-
"kind": "stream",
|
|
155
|
-
"name": "WatchUser",
|
|
156
|
-
"version": 2,
|
|
157
|
-
"scope": ["users", "live"],
|
|
158
|
-
"path": "/api/users/live/watch-user/2",
|
|
159
|
-
"methods": ["post", "get"],
|
|
160
|
-
"streamMode": "sse", // "sse" | "text"
|
|
161
|
-
"jsonSchema": {
|
|
162
|
-
"params": { "type": "object", "required": ["id"], "properties": { "id": { "type": "string" } } },
|
|
163
|
-
"yieldType": { /* see note */ },
|
|
164
|
-
"returnType": { "type": "object", "required": ["total"], "properties": { "total": { "type": "number" } } }
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
- `params` = input (query params for GET, body for POST).
|
|
170
|
-
- **`yieldType` in `sse` mode is the SSE envelope**, not the bare value:
|
|
171
|
-
```jsonc
|
|
172
|
-
{
|
|
173
|
-
"type": "object",
|
|
174
|
-
"description": "SSE message envelope. The data field contains the procedure yield value.",
|
|
175
|
-
"required": ["data", "event", "id"],
|
|
176
|
-
"properties": {
|
|
177
|
-
"data": { /* the actual per-yield value schema */ },
|
|
178
|
-
"event": { "type": "string" },
|
|
179
|
-
"id": { "type": "string" },
|
|
180
|
-
"retry": { "type": "number" }
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
```
|
|
184
|
-
In `text` mode `yieldType` is the bare value schema. **GUI tip:** to show "what
|
|
185
|
-
each event carries", detect the SSE envelope (object with `data`/`event`/`id`)
|
|
186
|
-
and surface `properties.data`; otherwise show `yieldType` directly.
|
|
187
|
-
- `returnType` = value delivered on stream completion (carried by the `return`
|
|
188
|
-
SSE event). Optional.
|
|
189
|
-
- `errors` here are pre-stream errors only.
|
|
190
|
-
|
|
191
|
-
### 5.3 `api` (REST)
|
|
192
|
-
|
|
193
|
-
```jsonc
|
|
194
|
-
{
|
|
195
|
-
"kind": "api",
|
|
196
|
-
"name": "UpdateUser",
|
|
197
|
-
"scope": "users",
|
|
198
|
-
"path": "/users/:id", // as registered (may have :params)
|
|
199
|
-
"method": "put",
|
|
200
|
-
"fullPath": "/api/users/:id", // resolved, incl. basePath — prefer this for display
|
|
201
|
-
"successStatus": 200, // optional; defaults POST→201, DELETE→204, else 200
|
|
202
|
-
"jsonSchema": {
|
|
203
|
-
"req": {
|
|
204
|
-
"pathParams": { "type":"object", "required":["id"], "properties":{"id":{"type":"string"}} },
|
|
205
|
-
"query": { "type":"object", "properties":{"dryRun":{"type":"boolean"}} },
|
|
206
|
-
"body": { "type":"object", "required":["name"], "properties":{"name":{"type":"string"}} }
|
|
207
|
-
// "headers" also possible
|
|
208
|
-
},
|
|
209
|
-
"res": {
|
|
210
|
-
"body": { "type":"object", "required":["id","name"], "properties":{"id":{"type":"string"},"name":{"type":"string"}} },
|
|
211
|
-
"headers": { "type":"object", "required":["x-rev"], "properties":{"x-rev":{"type":"string"}} }
|
|
212
|
-
}
|
|
213
|
-
},
|
|
214
|
-
"errors": ["Teapot"]
|
|
215
|
-
}
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
- `req` channels: any of `pathParams`, `query`, `body`, `headers` (all optional).
|
|
219
|
-
- `res` channels: `body`, `headers` (both optional).
|
|
220
|
-
- `jsonSchema.req`/`res` may be `{}` or absent for trivial endpoints.
|
|
221
|
-
- Prefer `fullPath` for the displayed URL; `path` may be omitted in some
|
|
222
|
-
envelopes.
|
|
223
|
-
|
|
224
|
-
### 5.4 `http-stream` (REST stream)
|
|
225
|
-
|
|
226
|
-
```jsonc
|
|
227
|
-
{
|
|
228
|
-
"kind": "http-stream",
|
|
229
|
-
"name": "TailUser",
|
|
230
|
-
"scope": "users",
|
|
231
|
-
"path": "/users/:id/tail",
|
|
232
|
-
"method": "get",
|
|
233
|
-
"fullPath": "/api/users/:id/tail",
|
|
234
|
-
"streamMode": "sse",
|
|
235
|
-
"jsonSchema": {
|
|
236
|
-
"req": { "pathParams": { "type":"object", "required":["id"], "properties":{"id":{"type":"string"}} } },
|
|
237
|
-
"res": { "headers": { /* optional response headers schema */ } },
|
|
238
|
-
"yield": { "type":"object", "required":["line"], "properties":{"line":{"type":"string"}} },
|
|
239
|
-
"returnType": { "type":"object", "required":["lines"], "properties":{"lines":{"type":"number"}} }
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
- Same `req` channels as `api`.
|
|
245
|
-
- `res` has **`headers` only** (no `body` — streaming responses have no single body).
|
|
246
|
-
- `yield` = per-event value schema, **raw** (NOT wrapped in an SSE envelope,
|
|
247
|
-
unlike `kind: "stream"`).
|
|
248
|
-
- `returnType` = completion value. Optional.
|
|
249
|
-
|
|
250
|
-
---
|
|
251
|
-
|
|
252
|
-
## 6. Embedded payload schemas
|
|
253
|
-
|
|
254
|
-
Every `jsonSchema.*` leaf (`body`, `response`, `params`, `yield`, `req.query`,
|
|
255
|
-
error `schema`, …) is a plain **JSON Schema (Draft-07)** object as produced by
|
|
256
|
-
the server's schema layer (TypeBox → JSON Schema). Expect standard keywords:
|
|
257
|
-
`type`, `properties`, `required`, `items`, `enum`, `const`, `format`, `oneOf`,
|
|
258
|
-
nested objects/arrays, etc.
|
|
259
|
-
|
|
260
|
-
**Render these with a generic JSON-Schema viewer.** Don't hard-code field lists.
|
|
261
|
-
Useful libraries: `@apidevtools/json-schema-ref-parser` (deref `$ref` if any),
|
|
262
|
-
or any JSON-Schema-to-table/form renderer. They are validation-grade schemas, so
|
|
263
|
-
you can also drive a "try it" form or example generator from them.
|
|
264
|
-
|
|
265
|
-
---
|
|
266
|
-
|
|
267
|
-
## 7. Suggested rendering model
|
|
268
|
-
|
|
269
|
-
1. **Header:** `basePath`, route count, kind breakdown.
|
|
270
|
-
2. **Sidebar:** group routes by `scope` (join array scopes with `/`), then by
|
|
271
|
-
`kind`. Label each with `name` + method/path.
|
|
272
|
-
3. **Route detail:**
|
|
273
|
-
- Title: `name`; badge: `kind`; method(s); display path (`fullPath` ?? `path`).
|
|
274
|
-
- For `rpc`/`stream`: also show `version`.
|
|
275
|
-
- **Request** section from `body`/`params`/`req.*`.
|
|
276
|
-
- **Response** section from `response`/`res.*`; for streams, a **Stream**
|
|
277
|
-
section from `yield`/`yieldType` (+ `returnType`).
|
|
278
|
-
- **Errors** section: resolve each `errors[]` name against the catalog and
|
|
279
|
-
show status + description + body schema.
|
|
280
|
-
4. **Errors page:** full `errors[]` catalog.
|
|
281
|
-
5. **Headers page:** `headers[]` table.
|
|
282
|
-
|
|
283
|
-
---
|
|
284
|
-
|
|
285
|
-
## 8. Defensive checklist for the GUI
|
|
286
|
-
|
|
287
|
-
- Validate `routes` is an array before anything else; otherwise it's not an envelope.
|
|
288
|
-
- Switch on `kind`; render unknown `kind` values generically (future-proofing).
|
|
289
|
-
- Treat HTTP methods case-insensitively (canonical output is lowercase, but
|
|
290
|
-
normalize anyway).
|
|
291
|
-
- Tolerate empty/absent `headers`, `errors`, `jsonSchema`, `req`, `res`.
|
|
292
|
-
- Tolerate extra/unknown properties at every level.
|
|
293
|
-
- Read `specVersion` first (default 1 if absent) and branch parsing on it; warn on unknown-higher.
|
|
294
|
-
- Don't expect a per-route `description`. `generatorVersion` is display-only, never a parse signal.
|
|
295
|
-
- Prefer `fullPath` over `path` for `api`/`http-stream` display.
|
|
296
|
-
- Unwrap the SSE envelope for `stream` `yieldType.data` when showing "event payload".
|