@sylphx/contract 0.2.0 → 0.2.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/dist/endpoint.d.ts +7 -1
- package/dist/endpoint.d.ts.map +1 -1
- package/dist/endpoints/admin-ai-playground.d.ts +3 -3
- package/dist/endpoints/admin-ai-playground.js +6 -6
- package/dist/endpoints/admin-anomalies.d.ts +7 -7
- package/dist/endpoints/admin-anomalies.js +14 -14
- package/dist/endpoints/admin-apm.d.ts +6 -6
- package/dist/endpoints/admin-apm.js +12 -12
- package/dist/endpoints/admin-audit.d.ts +185 -52
- package/dist/endpoints/admin-audit.d.ts.map +1 -1
- package/dist/endpoints/admin-audit.js +113 -113
- package/dist/endpoints/admin-billing.d.ts +19 -19
- package/dist/endpoints/admin-billing.js +38 -38
- package/dist/endpoints/admin-bootstrap.d.ts +1 -1
- package/dist/endpoints/admin-bootstrap.js +2 -2
- package/dist/endpoints/admin-broadcasts.d.ts +5 -5
- package/dist/endpoints/admin-broadcasts.js +10 -10
- package/dist/endpoints/admin-builds.d.ts +1 -1
- package/dist/endpoints/admin-builds.js +2 -2
- package/dist/endpoints/admin-config.d.ts +11 -11
- package/dist/endpoints/admin-config.js +22 -22
- package/dist/endpoints/admin-consent.d.ts +38 -14
- package/dist/endpoints/admin-consent.d.ts.map +1 -1
- package/dist/endpoints/admin-consent.js +27 -27
- package/dist/endpoints/admin-env-services.d.ts +1 -1
- package/dist/endpoints/admin-env-services.js +2 -2
- package/dist/endpoints/admin-impersonation.d.ts +9 -9
- package/dist/endpoints/admin-impersonation.js +18 -18
- package/dist/endpoints/admin-invitations.d.ts +5 -5
- package/dist/endpoints/admin-invitations.js +10 -10
- package/dist/endpoints/admin-jwt-keys.d.ts +6 -6
- package/dist/endpoints/admin-jwt-keys.js +12 -12
- package/dist/endpoints/admin-logs.d.ts +7 -7
- package/dist/endpoints/admin-logs.js +14 -14
- package/dist/endpoints/admin-plans.d.ts +4 -4
- package/dist/endpoints/admin-plans.js +8 -8
- package/dist/endpoints/admin-project-users.d.ts +8 -8
- package/dist/endpoints/admin-project-users.js +16 -16
- package/dist/endpoints/admin-projects.d.ts +7 -7
- package/dist/endpoints/admin-projects.js +14 -14
- package/dist/endpoints/admin-quotas.d.ts +6 -6
- package/dist/endpoints/admin-quotas.js +12 -12
- package/dist/endpoints/admin-rate-limits.d.ts +2 -2
- package/dist/endpoints/admin-rate-limits.js +4 -4
- package/dist/endpoints/admin-reconcile.d.ts +1 -1
- package/dist/endpoints/admin-reconcile.js +2 -2
- package/dist/endpoints/admin-resources.d.ts +2 -2
- package/dist/endpoints/admin-resources.js +4 -4
- package/dist/endpoints/admin-secrets.d.ts +2 -2
- package/dist/endpoints/admin-secrets.js +4 -4
- package/dist/endpoints/admin-services.d.ts +1 -1
- package/dist/endpoints/admin-services.js +2 -2
- package/dist/endpoints/admin-tasks.d.ts +6 -6
- package/dist/endpoints/admin-tasks.js +12 -12
- package/dist/endpoints/admin-tenants.d.ts +1 -1
- package/dist/endpoints/admin-tenants.js +2 -2
- package/dist/endpoints/admin-traces.d.ts +5 -5
- package/dist/endpoints/admin-traces.js +10 -10
- package/dist/endpoints/admin-users.d.ts +8 -8
- package/dist/endpoints/admin-users.js +16 -16
- package/dist/endpoints/admin-webhook-signature-versions.d.ts +3 -3
- package/dist/endpoints/admin-webhook-signature-versions.js +6 -6
- package/dist/endpoints/environments.d.ts +9 -0
- package/dist/endpoints/environments.d.ts.map +1 -1
- package/dist/endpoints/project-manifest.d.ts +16 -16
- package/dist/endpoints/storage.d.ts +4 -6
- package/dist/endpoints/storage.d.ts.map +1 -1
- package/dist/endpoints/storage.js +1 -12
- package/dist/hono-app.d.ts +206 -0
- package/dist/hono-app.d.ts.map +1 -0
- package/dist/hono-app.js +62 -0
- package/dist/index.d.ts +399 -228
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -3
- package/dist/schemas/admin-audit.d.ts +183 -0
- package/dist/schemas/admin-audit.d.ts.map +1 -1
- package/dist/schemas/admin-audit.js +144 -0
- package/dist/schemas/admin-consent.d.ts +32 -3
- package/dist/schemas/admin-consent.d.ts.map +1 -1
- package/dist/schemas/admin-consent.js +28 -1
- package/dist/schemas/environment.d.ts +6 -0
- package/dist/schemas/environment.d.ts.map +1 -1
- package/dist/schemas/environment.js +2 -0
- package/dist/schemas/project-manifest.d.ts +16 -16
- package/dist/schemas/storage.d.ts +4 -0
- package/dist/schemas/storage.d.ts.map +1 -1
- package/dist/schemas/storage.js +5 -0
- package/package.json +12 -2
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `HonoAppFromEndpoints<G, BasePath>` — derive a Hono RPC-compatible app
|
|
3
|
+
* type purely from an `EndpointGroup`.
|
|
4
|
+
*
|
|
5
|
+
* ## Why this exists
|
|
6
|
+
*
|
|
7
|
+
* Pre-2026-05-03 the platform used `@sylphx/api-types` to re-export route
|
|
8
|
+
* types DIRECTLY from `apps/api/src/server/...`:
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* // packages/api-types/src/routes/admin-billing.ts (OLD)
|
|
12
|
+
* export type * from '@/server/platform/routes/admin-billing'
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* That re-export forced `apps/web`'s typecheck to traverse the entire
|
|
16
|
+
* backend implementation graph (`@sylphx/core/lib/db/effect`, the K8s
|
|
17
|
+
* reconciler, audit pipeline, …). Every backend type bug cascaded into
|
|
18
|
+
* a Web build failure — 24+ hours of consecutive web build failures
|
|
19
|
+
* on 2026-05-03. SoC violation at the package boundary; ADR-084
|
|
20
|
+
* contract-first violated.
|
|
21
|
+
*
|
|
22
|
+
* The SOTA fix (this file): synthesise the Hono RPC type purely from
|
|
23
|
+
* `@sylphx/contract` endpoint definitions. Web depends only on
|
|
24
|
+
* Effect Schema + Hono types — never on backend code.
|
|
25
|
+
*
|
|
26
|
+
* ## How it composes
|
|
27
|
+
*
|
|
28
|
+
* Hono's RPC client `hc<T>(baseUrl)` accepts a `Hono<E, Schema, BasePath>`
|
|
29
|
+
* type and produces a typed proxy where each path segment is a property
|
|
30
|
+
* and each HTTP method is a `$method` key. The Schema shape (verified
|
|
31
|
+
* from `node_modules/hono/dist/types/types/types.d.ts`) is:
|
|
32
|
+
*
|
|
33
|
+
* ```ts
|
|
34
|
+
* type Schema = {
|
|
35
|
+
* [Path: string]: {
|
|
36
|
+
* [`$${Lowercase<HttpMethod>}`]: {
|
|
37
|
+
* input: { json?, query?, param?, header?, form? }
|
|
38
|
+
* output: ResponseBodyType
|
|
39
|
+
* outputFormat: 'json' | 'text' | …
|
|
40
|
+
* status: StatusCode
|
|
41
|
+
* }
|
|
42
|
+
* }
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* `HonoAppFromEndpoints<G>` constructs exactly that Schema by recursively
|
|
47
|
+
* walking each `Endpoint` in the group to one entry, then intersecting them.
|
|
48
|
+
*
|
|
49
|
+
* ## BasePath / StripPrefix
|
|
50
|
+
*
|
|
51
|
+
* Each contract endpoint carries the FULL public path (e.g.
|
|
52
|
+
* `/operator/billing/overview`). The web's hc-client historically mounts
|
|
53
|
+
* at the parent prefix (e.g. `${PLATFORM_BASE_PATH}/operator/billing`)
|
|
54
|
+
* and accesses `.overview` — so the type's path keys must be RELATIVE
|
|
55
|
+
* to the mount. `StripPrefix<G, BP>` rewrites each endpoint path to
|
|
56
|
+
* remove the leading `BP`, preserving the existing client structure
|
|
57
|
+
* with zero consumer churn.
|
|
58
|
+
*
|
|
59
|
+
* @see ADR-084 — Effect Schema contract-first
|
|
60
|
+
* @see docs/audit/2026-05-03-e2e-run/SSOT.md — E-25 (web build chronic failure)
|
|
61
|
+
*/
|
|
62
|
+
import type { Schema } from 'effect';
|
|
63
|
+
import type { Hono } from 'hono';
|
|
64
|
+
import type { Endpoint, EndpointGroup, HttpMethod } from './endpoint.js';
|
|
65
|
+
type HonoBaseSchema = import('hono').Schema;
|
|
66
|
+
/**
|
|
67
|
+
* Distribute a union into a function-parameter position then re-extract,
|
|
68
|
+
* collapsing it to an intersection. Standard TypeScript trick.
|
|
69
|
+
*/
|
|
70
|
+
type UnionToIntersection<U> = (U extends unknown ? (x: U) => void : never) extends (x: infer I) => void ? I : never;
|
|
71
|
+
/**
|
|
72
|
+
* Recursively strip `readonly` from objects and arrays. Effect Schema
|
|
73
|
+
* `Type<S>` produces deeply-readonly shapes; consumer code in `apps/web`
|
|
74
|
+
* (and downstream React libraries) historically receives mutable
|
|
75
|
+
* arrays — preserve assignability by unwrapping.
|
|
76
|
+
*
|
|
77
|
+
* Skips Date / function / class instances (they're not plain objects);
|
|
78
|
+
* `T extends T` distributes over unions so `string | readonly string[]`
|
|
79
|
+
* is processed branch-by-branch.
|
|
80
|
+
*/
|
|
81
|
+
type WritableDeep<T> = T extends Date | RegExp | ((...args: unknown[]) => unknown) ? T : T extends string | number | boolean | bigint | symbol | null | undefined ? T : T extends ReadonlyArray<infer E> ? WritableDeep<E>[] : T extends object ? {
|
|
82
|
+
-readonly [K in keyof T]: WritableDeep<T[K]>;
|
|
83
|
+
} : T;
|
|
84
|
+
/**
|
|
85
|
+
* Extract the runtime TypeScript type `A` from an Effect `Schema<A, I, R>`,
|
|
86
|
+
* then strip deeply-nested `readonly` modifiers so consumer assignment
|
|
87
|
+
* targets (mutable arrays, mutable objects) typecheck.
|
|
88
|
+
*
|
|
89
|
+
* Returns `never` when the input isn't a recognised schema (so the
|
|
90
|
+
* conditional in `EndpointInput` cleanly omits the key).
|
|
91
|
+
*
|
|
92
|
+
* IMPORTANT: we must NOT constrain the encoded `I` to `unknown` — most
|
|
93
|
+
* struct schemas have `I` being a structurally-distinct encoded shape,
|
|
94
|
+
* not `unknown`. Using `Schema.Schema.AnyNoContext` matches any schema
|
|
95
|
+
* with `R = never` regardless of `I`, which is what we want for response
|
|
96
|
+
* type extraction. Pre-2026-05-04 the constraint was `Schema.Schema<infer
|
|
97
|
+
* A, unknown, never>` which failed to match struct schemas — every
|
|
98
|
+
* endpoint resolved to `never` and `apps/web` consumers saw
|
|
99
|
+
* `anomaly.status → Property does not exist on type 'never'`.
|
|
100
|
+
*/
|
|
101
|
+
type SchemaType<S> = S extends Schema.Schema.AnyNoContext ? WritableDeep<Schema.Schema.Type<S>> : never;
|
|
102
|
+
/**
|
|
103
|
+
* Strip a leading prefix from a literal string type.
|
|
104
|
+
*
|
|
105
|
+
* StripBase<'/operator/billing/overview', '/operator/billing'> → '/overview'
|
|
106
|
+
* StripBase<'/operator/billing', '/operator/billing'> → '/'
|
|
107
|
+
* StripBase<'/foo', '/operator/billing'> → '/foo' (no match — passthrough)
|
|
108
|
+
*/
|
|
109
|
+
type StripBase<Path extends string, BasePath extends string> = BasePath extends '/' ? Path : Path extends `${BasePath}${infer Rest}` ? Rest extends '' ? '/' : Rest : Path;
|
|
110
|
+
/**
|
|
111
|
+
* Build the Hono `input` shape from a contract endpoint.
|
|
112
|
+
*
|
|
113
|
+
* Hono's validation targets are `param` (path), `query`, `json` (body),
|
|
114
|
+
* `header`, `form`. Our contract uses `params`, `query`, `body` — map
|
|
115
|
+
* `params → param` and `body → json`.
|
|
116
|
+
*
|
|
117
|
+
* The schema entry stores the validation targets at the TOP level of
|
|
118
|
+
* `input` (matching what `@hono/zod-validator`-style middlewares produce
|
|
119
|
+
* after running). Hono's `hc<T>(...)` proxy reads this shape directly to
|
|
120
|
+
* type-check the `client[path].$method(<args>)` call argument.
|
|
121
|
+
*/
|
|
122
|
+
type EndpointInput<E extends Endpoint> = (E['params'] extends Schema.Schema.AnyNoContext ? {
|
|
123
|
+
param: SchemaType<E['params']>;
|
|
124
|
+
} : {}) & (E['query'] extends Schema.Schema.AnyNoContext ? {
|
|
125
|
+
query: SchemaType<E['query']>;
|
|
126
|
+
} : {}) & (E['body'] extends Schema.Schema.AnyNoContext ? {
|
|
127
|
+
json: SchemaType<E['body']>;
|
|
128
|
+
} : {});
|
|
129
|
+
/**
|
|
130
|
+
* Build a single Hono Schema entry for one endpoint after BasePath stripping.
|
|
131
|
+
*
|
|
132
|
+
* The `$method` key uses lowercase + `$` prefix per Hono's `AddDollar<T>`.
|
|
133
|
+
* Output collapses to `status: 200` + `outputFormat: 'json'` because that
|
|
134
|
+
* is the success path of every public endpoint we emit. Multi-status
|
|
135
|
+
* differentiation (e.g. 202 vs 200) can be added later by reading
|
|
136
|
+
* `endpoint.errors` and projecting per-status entries — out of scope for
|
|
137
|
+
* the chronic-build-failure fix.
|
|
138
|
+
*/
|
|
139
|
+
type EndpointToHonoEntry<E extends Endpoint, BasePath extends string> = {
|
|
140
|
+
[P in StripBase<E['path'], BasePath>]: {
|
|
141
|
+
[M in `$${Lowercase<E['method']>}`]: {
|
|
142
|
+
input: EndpointInput<E>;
|
|
143
|
+
output: SchemaType<E['response']>;
|
|
144
|
+
outputFormat: 'json';
|
|
145
|
+
status: 200;
|
|
146
|
+
};
|
|
147
|
+
};
|
|
148
|
+
};
|
|
149
|
+
/**
|
|
150
|
+
* Walk every endpoint in `G`, recursively flatten nested endpoint groups,
|
|
151
|
+
* build per-endpoint Hono entries with BasePath stripped, then intersect them
|
|
152
|
+
* into one Schema object.
|
|
153
|
+
*
|
|
154
|
+
* NOTE: we intentionally do NOT intersect with `HonoSchema` here. That
|
|
155
|
+
* outer index signature `{[Path: string]: {[Method]: Endpoint}}` would
|
|
156
|
+
* widen the precise per-endpoint entries we just built — Hono's hc<T>
|
|
157
|
+
* proxy navigates by literal property keys, and the index-signature
|
|
158
|
+
* intersection causes TS to infer everything as the loose Endpoint
|
|
159
|
+
* fallback (`output: any` etc.), which then fails to match
|
|
160
|
+
* `ClientResponse<infer Body, 200, 'json'>` in `serverFetch`'s
|
|
161
|
+
* ExtractSuccessBody and resolves to `never`.
|
|
162
|
+
*/
|
|
163
|
+
type SchemaFromGroup<G extends EndpointGroup, BasePath extends string> = UnionToIntersection<{
|
|
164
|
+
[K in keyof G]: G[K] extends Endpoint ? EndpointToHonoEntry<G[K], BasePath> : G[K] extends EndpointGroup ? SchemaFromGroup<G[K], BasePath> : never;
|
|
165
|
+
}[keyof G]>;
|
|
166
|
+
/**
|
|
167
|
+
* Synthesise a Hono RPC-compatible app type from a contract endpoint group.
|
|
168
|
+
*
|
|
169
|
+
* @template G — a `Record<string, Endpoint>` exported from `@sylphx/contract`
|
|
170
|
+
* (e.g. `typeof adminBillingEndpoints`).
|
|
171
|
+
* @template BasePath — the URL prefix at which the Hono app will be mounted
|
|
172
|
+
* on the production API. Each endpoint path that starts with this prefix
|
|
173
|
+
* has the prefix stripped before being added to the Schema. Defaults to
|
|
174
|
+
* `'/'` (no stripping — paths are kept verbatim from the contract).
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```ts
|
|
178
|
+
* import type { HonoAppFromEndpoints } from '@sylphx/contract/hono-app'
|
|
179
|
+
* import type { adminBillingEndpoints } from '@sylphx/contract'
|
|
180
|
+
* import { hc } from 'hono/client'
|
|
181
|
+
*
|
|
182
|
+
* // Mount path strips '/operator/billing' from contract paths so that
|
|
183
|
+
* // `client.overview.$get({})` lands at `/v1/operator/billing/overview`
|
|
184
|
+
* // when the client is constructed with `baseUrl = '/v1/operator/billing'`.
|
|
185
|
+
* export type AdminBillingRoutes = HonoAppFromEndpoints<
|
|
186
|
+
* typeof adminBillingEndpoints,
|
|
187
|
+
* '/operator/billing'
|
|
188
|
+
* >
|
|
189
|
+
*
|
|
190
|
+
* const client = hc<AdminBillingRoutes>('/v1/operator/billing')
|
|
191
|
+
* const res = await client.overview.$get({})
|
|
192
|
+
* ```
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* ```ts
|
|
196
|
+
* // Or — mount at root, paths kept verbatim:
|
|
197
|
+
* export type ProjectsRoutes = HonoAppFromEndpoints<typeof projectsEndpoints>
|
|
198
|
+
* const client = hc<ProjectsRoutes>('/v1')
|
|
199
|
+
* const res = await client.projects.$get({})
|
|
200
|
+
* ```
|
|
201
|
+
*/
|
|
202
|
+
type AsHonoSchema<T> = T extends HonoBaseSchema ? T : never;
|
|
203
|
+
export type HonoAppFromEndpoints<G extends EndpointGroup, BasePath extends string = '/'> = Hono<Record<never, never>, AsHonoSchema<SchemaFromGroup<G, BasePath>>, BasePath>;
|
|
204
|
+
/** Re-export so consumers don't need a second import for endpoint typing. */
|
|
205
|
+
export type { Endpoint, EndpointGroup, HttpMethod };
|
|
206
|
+
//# sourceMappingURL=hono-app.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hono-app.d.ts","sourceRoot":"","sources":["../src/hono-app.ts"],"names":[],"mappings":"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"}
|
package/dist/hono-app.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `HonoAppFromEndpoints<G, BasePath>` — derive a Hono RPC-compatible app
|
|
3
|
+
* type purely from an `EndpointGroup`.
|
|
4
|
+
*
|
|
5
|
+
* ## Why this exists
|
|
6
|
+
*
|
|
7
|
+
* Pre-2026-05-03 the platform used `@sylphx/api-types` to re-export route
|
|
8
|
+
* types DIRECTLY from `apps/api/src/server/...`:
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* // packages/api-types/src/routes/admin-billing.ts (OLD)
|
|
12
|
+
* export type * from '@/server/platform/routes/admin-billing'
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* That re-export forced `apps/web`'s typecheck to traverse the entire
|
|
16
|
+
* backend implementation graph (`@sylphx/core/lib/db/effect`, the K8s
|
|
17
|
+
* reconciler, audit pipeline, …). Every backend type bug cascaded into
|
|
18
|
+
* a Web build failure — 24+ hours of consecutive web build failures
|
|
19
|
+
* on 2026-05-03. SoC violation at the package boundary; ADR-084
|
|
20
|
+
* contract-first violated.
|
|
21
|
+
*
|
|
22
|
+
* The SOTA fix (this file): synthesise the Hono RPC type purely from
|
|
23
|
+
* `@sylphx/contract` endpoint definitions. Web depends only on
|
|
24
|
+
* Effect Schema + Hono types — never on backend code.
|
|
25
|
+
*
|
|
26
|
+
* ## How it composes
|
|
27
|
+
*
|
|
28
|
+
* Hono's RPC client `hc<T>(baseUrl)` accepts a `Hono<E, Schema, BasePath>`
|
|
29
|
+
* type and produces a typed proxy where each path segment is a property
|
|
30
|
+
* and each HTTP method is a `$method` key. The Schema shape (verified
|
|
31
|
+
* from `node_modules/hono/dist/types/types/types.d.ts`) is:
|
|
32
|
+
*
|
|
33
|
+
* ```ts
|
|
34
|
+
* type Schema = {
|
|
35
|
+
* [Path: string]: {
|
|
36
|
+
* [`$${Lowercase<HttpMethod>}`]: {
|
|
37
|
+
* input: { json?, query?, param?, header?, form? }
|
|
38
|
+
* output: ResponseBodyType
|
|
39
|
+
* outputFormat: 'json' | 'text' | …
|
|
40
|
+
* status: StatusCode
|
|
41
|
+
* }
|
|
42
|
+
* }
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* `HonoAppFromEndpoints<G>` constructs exactly that Schema by recursively
|
|
47
|
+
* walking each `Endpoint` in the group to one entry, then intersecting them.
|
|
48
|
+
*
|
|
49
|
+
* ## BasePath / StripPrefix
|
|
50
|
+
*
|
|
51
|
+
* Each contract endpoint carries the FULL public path (e.g.
|
|
52
|
+
* `/operator/billing/overview`). The web's hc-client historically mounts
|
|
53
|
+
* at the parent prefix (e.g. `${PLATFORM_BASE_PATH}/operator/billing`)
|
|
54
|
+
* and accesses `.overview` — so the type's path keys must be RELATIVE
|
|
55
|
+
* to the mount. `StripPrefix<G, BP>` rewrites each endpoint path to
|
|
56
|
+
* remove the leading `BP`, preserving the existing client structure
|
|
57
|
+
* with zero consumer churn.
|
|
58
|
+
*
|
|
59
|
+
* @see ADR-084 — Effect Schema contract-first
|
|
60
|
+
* @see docs/audit/2026-05-03-e2e-run/SSOT.md — E-25 (web build chronic failure)
|
|
61
|
+
*/
|
|
62
|
+
export {};
|