@substrat-run/vertical-host 0.74.0 → 0.75.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.
|
@@ -13,6 +13,13 @@
|
|
|
13
13
|
* **Scope.** It mounts the operations THIS module declares. A composed engine's
|
|
14
14
|
* operations carry no `http` — the engine is entity-agnostic and does not own a
|
|
15
15
|
* URL shape, so the vertical decides theirs and mounts them itself.
|
|
16
|
+
*
|
|
17
|
+
* Two things a hand-written table did for free, and this derivation therefore
|
|
18
|
+
* has to do deliberately: a query string carries no types (§ `queryCoercers`),
|
|
19
|
+
* and registration ORDER decides which of two overlapping paths wins
|
|
20
|
+
* (§ `comparePaths`). Both were found by a production vertical with 195
|
|
21
|
+
* declared routes that could not switch to this mount without the first — 29 of
|
|
22
|
+
* its 81 reads carried a `limit` the model declares as a number (#785).
|
|
16
23
|
*/
|
|
17
24
|
import type { Context, Hono } from 'hono';
|
|
18
25
|
import type { ScopeStub } from '@substrat-run/kernel';
|
|
@@ -35,6 +42,9 @@ export interface MountOperationsOptions {
|
|
|
35
42
|
* Mount one route per declared operation. Returns what it mounted — a caller
|
|
36
43
|
* can assert on it, and a test that expects N routes fails loudly at zero
|
|
37
44
|
* rather than passing over an empty table.
|
|
45
|
+
*
|
|
46
|
+
* The returned table is in registration order, which is the order that decides
|
|
47
|
+
* dispatch: read it to see which of two overlapping paths wins.
|
|
38
48
|
*/
|
|
39
49
|
export declare function mountOperations(app: Hono<any, any, any>, operations: Readonly<Record<string, object>>, resolveStub: ResolveStub, options?: MountOperationsOptions): {
|
|
40
50
|
operation: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"operations-routes.d.ts","sourceRoot":"","sources":["../src/operations-routes.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"operations-routes.d.ts","sourceRoot":"","sources":["../src/operations-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC1C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEtD,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;AAmI7D,MAAM,WAAW,sBAAsB;IACrC,4EAA4E;IAC5E,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;;;;;OAQG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;CAC7C;AAuFD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAE7B,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EACxB,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAC5C,WAAW,EAAE,WAAW,EACxB,OAAO,GAAE,sBAA2B,GACnC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,CAgFvD"}
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read a schema's definition without `instanceof`, which fails across duplicate
|
|
3
|
+
* copies of the library — the same reason the rest of this file reads Zod
|
|
4
|
+
* structurally.
|
|
5
|
+
*/
|
|
6
|
+
function defOf(schema) {
|
|
7
|
+
return (schema?._zod?.def ??
|
|
8
|
+
schema?._def);
|
|
9
|
+
}
|
|
1
10
|
/**
|
|
2
11
|
* Input fields the model pins to a single value — supplied by the route rather
|
|
3
12
|
* than by the caller.
|
|
@@ -9,9 +18,6 @@
|
|
|
9
18
|
* it here removes a whole category of "route that cannot be derived" without
|
|
10
19
|
* adding any vocabulary, which is the better kind of fix: the model was not
|
|
11
20
|
* missing information, the emitter was not listening.
|
|
12
|
-
*
|
|
13
|
-
* Read structurally across Zod's internal layouts rather than with `instanceof`,
|
|
14
|
-
* which fails across duplicate copies of the library.
|
|
15
21
|
*/
|
|
16
22
|
function pinnedFields(input) {
|
|
17
23
|
const shape = input?.shape;
|
|
@@ -19,8 +25,7 @@ function pinnedFields(input) {
|
|
|
19
25
|
return {};
|
|
20
26
|
const out = {};
|
|
21
27
|
for (const [field, schema] of Object.entries(shape)) {
|
|
22
|
-
const def = (schema
|
|
23
|
-
schema._def);
|
|
28
|
+
const def = defOf(schema);
|
|
24
29
|
if (def?.type !== 'literal')
|
|
25
30
|
continue;
|
|
26
31
|
// Zod 4 carries `values` (a literal may name several); older layouts carry
|
|
@@ -31,6 +36,78 @@ function pinnedFields(input) {
|
|
|
31
36
|
}
|
|
32
37
|
return out;
|
|
33
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* A URL carries no types: `?limit=100` arrives as the string `'100'`, and an
|
|
41
|
+
* operation declaring `limit: z.number().int().optional()` rejects it with
|
|
42
|
+
* "expected number, received string". Every read with a non-string field is
|
|
43
|
+
* affected — in a production vertical that was most paged reads, plus every
|
|
44
|
+
* year/month filter (#785).
|
|
45
|
+
*
|
|
46
|
+
* The fix reads the declared shape and coerces only the fields whose declared
|
|
47
|
+
* type cannot be a string: number, boolean, bigint. That is deliberately
|
|
48
|
+
* narrower than coercing by JSON grammar, which would have to guess — `?q=123`
|
|
49
|
+
* is a number to the grammar and a search term to the caller — and narrower
|
|
50
|
+
* than telling verticals to declare `z.coerce.number()`, which pushes an HTTP
|
|
51
|
+
* transport detail into a model that has to stay transport-agnostic (the same
|
|
52
|
+
* schema the handler parses).
|
|
53
|
+
*
|
|
54
|
+
* A value the declared type cannot accept is passed through UNCHANGED, so the
|
|
55
|
+
* error the caller reads still names what they actually sent.
|
|
56
|
+
*
|
|
57
|
+
* Unions are skipped: `z.union([z.number(), z.string()])` has no single answer,
|
|
58
|
+
* and guessing is what this function exists to avoid.
|
|
59
|
+
*/
|
|
60
|
+
function queryCoercers(input) {
|
|
61
|
+
const shape = input?.shape;
|
|
62
|
+
if (!shape)
|
|
63
|
+
return {};
|
|
64
|
+
const out = {};
|
|
65
|
+
for (const [field, schema] of Object.entries(shape)) {
|
|
66
|
+
const coerce = coercerFor(schema);
|
|
67
|
+
if (coerce)
|
|
68
|
+
out[field] = coerce;
|
|
69
|
+
}
|
|
70
|
+
return out;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* The coercion a declared field wants, looking through the wrappers that do not
|
|
74
|
+
* change its type — `optional`, `nullable`, `default`, `catch`, `readonly`, and
|
|
75
|
+
* a pipe's input side (`z.coerce.number()` is one, and coercing ahead of it is
|
|
76
|
+
* idempotent rather than wrong).
|
|
77
|
+
*/
|
|
78
|
+
function coercerFor(schema, depth = 0) {
|
|
79
|
+
if (depth > 8)
|
|
80
|
+
return undefined; // a cycle cannot happen in a Zod schema, but a bound is cheap
|
|
81
|
+
const def = defOf(schema);
|
|
82
|
+
switch (def?.type) {
|
|
83
|
+
case 'number':
|
|
84
|
+
return (raw) => {
|
|
85
|
+
if (raw.trim() === '')
|
|
86
|
+
return raw;
|
|
87
|
+
const n = Number(raw);
|
|
88
|
+
return Number.isFinite(n) ? n : raw;
|
|
89
|
+
};
|
|
90
|
+
case 'bigint':
|
|
91
|
+
return (raw) => (/^[+-]?\d+$/.test(raw.trim()) ? BigInt(raw.trim()) : raw);
|
|
92
|
+
case 'boolean':
|
|
93
|
+
// Only the two spellings a URL can mean unambiguously. `?flag` with no
|
|
94
|
+
// value arrives as '' and stays '' — "present" is not "true" here.
|
|
95
|
+
return (raw) => (raw === 'true' ? true : raw === 'false' ? false : raw);
|
|
96
|
+
case 'optional':
|
|
97
|
+
case 'nullable':
|
|
98
|
+
case 'nullish':
|
|
99
|
+
case 'default':
|
|
100
|
+
case 'prefault':
|
|
101
|
+
case 'catch':
|
|
102
|
+
case 'readonly':
|
|
103
|
+
case 'nonoptional':
|
|
104
|
+
return coercerFor(def.innerType, depth + 1);
|
|
105
|
+
case 'pipe':
|
|
106
|
+
return coercerFor(def.in, depth + 1);
|
|
107
|
+
default:
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
34
111
|
/** `{listId}` in the model is `:listId` to Hono. */
|
|
35
112
|
function toHonoPath(path) {
|
|
36
113
|
return path.replace(/\{(\w+)\}/g, ':$1');
|
|
@@ -39,10 +116,85 @@ function toHonoPath(path) {
|
|
|
39
116
|
function pathParams(path) {
|
|
40
117
|
return [...path.matchAll(/\{(\w+)\}/g)].map((m) => m[1]);
|
|
41
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* Order two declared paths so the more specific one is registered first.
|
|
121
|
+
*
|
|
122
|
+
* Hono dispatches in REGISTRATION order, so `/users/{id}` registered before
|
|
123
|
+
* `/users/invites` answers `/users/invites` with `id: 'invites'` and the static
|
|
124
|
+
* route is unreachable — no error, no warning, just an endpoint that silently
|
|
125
|
+
* belongs to its neighbour. Registering in alphabetical OPERATION order (what
|
|
126
|
+
* this did until #785) decides that by a name that has nothing to do with
|
|
127
|
+
* routing: `support/get` sorts before `support/list-mine`, and a live
|
|
128
|
+
* `GET /support/issues/mine` disappeared behind `GET /support/issues/{id}`.
|
|
129
|
+
*
|
|
130
|
+
* So compare the paths instead, segment by segment, static before parameter —
|
|
131
|
+
* a lexicographic order over the key `[isParam, text]` per segment, which makes
|
|
132
|
+
* it a real total order (transitive, and the same table every time) rather than
|
|
133
|
+
* a pile of pairwise special cases. Paths that cannot overlap are unaffected;
|
|
134
|
+
* paths that can, resolve the way a reader of the URLs expects.
|
|
135
|
+
*
|
|
136
|
+
* **Why order rather than refuse.** #785 argued for detecting the collision and
|
|
137
|
+
* refusing to mount, on the grounds that the silence is the real defect and the
|
|
138
|
+
* vertical should decide. The silence is the defect — but a reserved word in an
|
|
139
|
+
* id slot has one correct reading, not an ambiguous one, and it is the reading
|
|
140
|
+
* every path-template spec already writes down: OpenAPI resolves a concrete
|
|
141
|
+
* path ahead of a templated one for exactly this case. Refusing would make a
|
|
142
|
+
* soluble collision a boot failure and force live URLs to be renamed to satisfy
|
|
143
|
+
* a router that had the whole table in front of it. What ordering CANNOT
|
|
144
|
+
* resolve still throws (`assertNoUnreachable`), so nothing stays silent.
|
|
145
|
+
*/
|
|
146
|
+
function comparePaths(a, b) {
|
|
147
|
+
const as = a.split('/');
|
|
148
|
+
const bs = b.split('/');
|
|
149
|
+
for (let i = 0; i < Math.min(as.length, bs.length); i++) {
|
|
150
|
+
const x = as[i];
|
|
151
|
+
const y = bs[i];
|
|
152
|
+
if (x === y)
|
|
153
|
+
continue;
|
|
154
|
+
const xParam = x.startsWith('{');
|
|
155
|
+
const yParam = y.startsWith('{');
|
|
156
|
+
if (xParam !== yParam)
|
|
157
|
+
return xParam ? 1 : -1;
|
|
158
|
+
return x < y ? -1 : 1;
|
|
159
|
+
}
|
|
160
|
+
return as.length - bs.length;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* The shape a path DISPATCHES as: parameter names are internal to the handler,
|
|
164
|
+
* so `/users/{id}` and `/users/{slug}` are one route to any router.
|
|
165
|
+
*/
|
|
166
|
+
function dispatchShape(path) {
|
|
167
|
+
return path.replace(/\{\w+\}/g, '{}');
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Refuse a table where one operation can never be reached.
|
|
171
|
+
*
|
|
172
|
+
* Ordering resolves a static path against its parameter sibling (§
|
|
173
|
+
* `comparePaths`). What it cannot resolve is two declarations that dispatch
|
|
174
|
+
* IDENTICALLY — same method, same shape, different parameter names — because
|
|
175
|
+
* there is no reading under which both are live. That is the case #785 is
|
|
176
|
+
* really about: an endpoint that quietly stops existing. Here it fails at
|
|
177
|
+
* mount, naming both operations, rather than at the first request nobody makes.
|
|
178
|
+
*/
|
|
179
|
+
function assertNoUnreachable(declared) {
|
|
180
|
+
const claimed = new Map();
|
|
181
|
+
for (const [name, op] of declared) {
|
|
182
|
+
const key = `${op.http.method} ${dispatchShape(op.http.path)}`;
|
|
183
|
+
const first = claimed.get(key);
|
|
184
|
+
if (first !== undefined) {
|
|
185
|
+
throw new Error(`mountOperations: '${first}' and '${name}' both declare ${key} — they dispatch ` +
|
|
186
|
+
'identically, so one of them can never be reached; give one a distinct path');
|
|
187
|
+
}
|
|
188
|
+
claimed.set(key, name);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
42
191
|
/**
|
|
43
192
|
* Mount one route per declared operation. Returns what it mounted — a caller
|
|
44
193
|
* can assert on it, and a test that expects N routes fails loudly at zero
|
|
45
194
|
* rather than passing over an empty table.
|
|
195
|
+
*
|
|
196
|
+
* The returned table is in registration order, which is the order that decides
|
|
197
|
+
* dispatch: read it to see which of two overlapping paths wins.
|
|
46
198
|
*/
|
|
47
199
|
export function mountOperations(
|
|
48
200
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -50,10 +202,16 @@ app, operations, resolveStub, options = {}) {
|
|
|
50
202
|
const base = options.basePath ?? '/api';
|
|
51
203
|
const known = options.knownOperations ? new Set(options.knownOperations) : undefined;
|
|
52
204
|
const mounted = [];
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
205
|
+
const declared = Object.keys(operations)
|
|
206
|
+
.map((name) => [name, operations[name]])
|
|
207
|
+
.filter((entry) => Boolean(entry[1]?.http))
|
|
208
|
+
// Path specificity decides dispatch; method and name only keep the table
|
|
209
|
+
// deterministic for two operations that share a path (`GET`/`POST /lists`).
|
|
210
|
+
.sort(([aName, a], [bName, b]) => comparePaths(a.http.path, b.http.path) ||
|
|
211
|
+
(a.http.method < b.http.method ? -1 : a.http.method > b.http.method ? 1 : 0) ||
|
|
212
|
+
(aName < bName ? -1 : aName > bName ? 1 : 0));
|
|
213
|
+
assertNoUnreachable(declared);
|
|
214
|
+
for (const [name, op] of declared) {
|
|
57
215
|
if (known && !known.has(name)) {
|
|
58
216
|
throw new Error(`mountOperations: '${name}' is bound to ${op.http.method} ${op.http.path} but no ` +
|
|
59
217
|
'registered module provides it — check the name against the engine that owns it');
|
|
@@ -63,6 +221,16 @@ app, operations, resolveStub, options = {}) {
|
|
|
63
221
|
const full = `${base}${toHonoPath(path)}`;
|
|
64
222
|
const takesBody = method === 'POST' || method === 'PUT' || method === 'PATCH';
|
|
65
223
|
const pinned = pinnedFields(op.input);
|
|
224
|
+
const coercers = queryCoercers(op.input);
|
|
225
|
+
/** Types the values a URL hands over as strings, per the declared shape. */
|
|
226
|
+
const typed = (values) => {
|
|
227
|
+
const out = {};
|
|
228
|
+
for (const [field, raw] of Object.entries(values)) {
|
|
229
|
+
const coerce = coercers[field];
|
|
230
|
+
out[field] = coerce && raw !== undefined ? coerce(raw) : raw;
|
|
231
|
+
}
|
|
232
|
+
return out;
|
|
233
|
+
};
|
|
66
234
|
const handler = async (c) => {
|
|
67
235
|
const stub = await resolveStub(c);
|
|
68
236
|
const fromPath = {};
|
|
@@ -78,11 +246,11 @@ app, operations, resolveStub, options = {}) {
|
|
|
78
246
|
if (takesBody) {
|
|
79
247
|
const raw = await c.req.text();
|
|
80
248
|
const body = raw ? JSON.parse(raw) : {};
|
|
81
|
-
|
|
249
|
+
// A body is JSON and already typed; only the URL's own values need it.
|
|
250
|
+
payload = { ...body, ...pinned, ...typed(fromPath) };
|
|
82
251
|
}
|
|
83
252
|
else {
|
|
84
|
-
|
|
85
|
-
payload = { ...query, ...pinned, ...fromPath };
|
|
253
|
+
payload = { ...typed(c.req.query()), ...pinned, ...typed(fromPath) };
|
|
86
254
|
}
|
|
87
255
|
if (!op.input && params.length === 0)
|
|
88
256
|
payload = undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"operations-routes.js","sourceRoot":"","sources":["../src/operations-routes.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"operations-routes.js","sourceRoot":"","sources":["../src/operations-routes.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@substrat-run/vertical-host",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.75.0",
|
|
4
4
|
"description": "The platform's /internal/* surface + error envelope, authored once — mount it in a vertical worker instead of re-copying the control-plane contract",
|
|
5
5
|
"license": "AGPL-3.0-only",
|
|
6
6
|
"repository": {
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"hono": "^4.6.0",
|
|
26
|
-
"@substrat-run/contracts": "^0.
|
|
27
|
-
"@substrat-run/kernel": "^0.
|
|
26
|
+
"@substrat-run/contracts": "^0.75.0",
|
|
27
|
+
"@substrat-run/kernel": "^0.75.0"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"typescript": "^7.0.0",
|