@sylphx/contract 0.2.0 → 0.3.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.
Files changed (125) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/endpoint.d.ts +13 -1
  3. package/dist/endpoint.d.ts.map +1 -1
  4. package/dist/endpoints/admin-ai-playground.d.ts +3 -3
  5. package/dist/endpoints/admin-ai-playground.js +6 -6
  6. package/dist/endpoints/admin-anomalies.d.ts +7 -7
  7. package/dist/endpoints/admin-anomalies.js +14 -14
  8. package/dist/endpoints/admin-apm.d.ts +6 -6
  9. package/dist/endpoints/admin-apm.js +12 -12
  10. package/dist/endpoints/admin-audit.d.ts +185 -52
  11. package/dist/endpoints/admin-audit.d.ts.map +1 -1
  12. package/dist/endpoints/admin-audit.js +113 -113
  13. package/dist/endpoints/admin-billing.d.ts +19 -19
  14. package/dist/endpoints/admin-billing.js +38 -38
  15. package/dist/endpoints/admin-bootstrap.d.ts +1 -1
  16. package/dist/endpoints/admin-bootstrap.js +2 -2
  17. package/dist/endpoints/admin-broadcasts.d.ts +5 -5
  18. package/dist/endpoints/admin-broadcasts.js +10 -10
  19. package/dist/endpoints/admin-builds.d.ts +1 -1
  20. package/dist/endpoints/admin-builds.js +2 -2
  21. package/dist/endpoints/admin-config.d.ts +11 -11
  22. package/dist/endpoints/admin-config.js +22 -22
  23. package/dist/endpoints/admin-consent.d.ts +38 -14
  24. package/dist/endpoints/admin-consent.d.ts.map +1 -1
  25. package/dist/endpoints/admin-consent.js +27 -27
  26. package/dist/endpoints/admin-env-services.d.ts +1 -1
  27. package/dist/endpoints/admin-env-services.js +2 -2
  28. package/dist/endpoints/admin-impersonation.d.ts +9 -9
  29. package/dist/endpoints/admin-impersonation.js +18 -18
  30. package/dist/endpoints/admin-invitations.d.ts +5 -5
  31. package/dist/endpoints/admin-invitations.js +10 -10
  32. package/dist/endpoints/admin-jwt-keys.d.ts +6 -6
  33. package/dist/endpoints/admin-jwt-keys.js +12 -12
  34. package/dist/endpoints/admin-logs.d.ts +7 -7
  35. package/dist/endpoints/admin-logs.js +14 -14
  36. package/dist/endpoints/admin-plans.d.ts +4 -4
  37. package/dist/endpoints/admin-plans.js +8 -8
  38. package/dist/endpoints/admin-project-users.d.ts +8 -8
  39. package/dist/endpoints/admin-project-users.js +16 -16
  40. package/dist/endpoints/admin-projects.d.ts +36 -7
  41. package/dist/endpoints/admin-projects.d.ts.map +1 -1
  42. package/dist/endpoints/admin-projects.js +44 -15
  43. package/dist/endpoints/admin-quotas.d.ts +6 -6
  44. package/dist/endpoints/admin-quotas.js +12 -12
  45. package/dist/endpoints/admin-rate-limits.d.ts +2 -2
  46. package/dist/endpoints/admin-rate-limits.js +4 -4
  47. package/dist/endpoints/admin-reconcile.d.ts +1 -1
  48. package/dist/endpoints/admin-reconcile.js +2 -2
  49. package/dist/endpoints/admin-resources.d.ts +2 -2
  50. package/dist/endpoints/admin-resources.js +4 -4
  51. package/dist/endpoints/admin-secrets.d.ts +2 -2
  52. package/dist/endpoints/admin-secrets.js +4 -4
  53. package/dist/endpoints/admin-services.d.ts +1 -1
  54. package/dist/endpoints/admin-services.js +2 -2
  55. package/dist/endpoints/admin-tasks.d.ts +6 -6
  56. package/dist/endpoints/admin-tasks.js +12 -12
  57. package/dist/endpoints/admin-tenants.d.ts +1 -1
  58. package/dist/endpoints/admin-tenants.js +2 -2
  59. package/dist/endpoints/admin-traces.d.ts +5 -5
  60. package/dist/endpoints/admin-traces.js +10 -10
  61. package/dist/endpoints/admin-users.d.ts +8 -8
  62. package/dist/endpoints/admin-users.js +16 -16
  63. package/dist/endpoints/admin-webhook-signature-versions.d.ts +3 -3
  64. package/dist/endpoints/admin-webhook-signature-versions.js +6 -6
  65. package/dist/endpoints/auth.d.ts +6 -0
  66. package/dist/endpoints/auth.d.ts.map +1 -1
  67. package/dist/endpoints/auth.js +12 -1
  68. package/dist/endpoints/branch-databases.d.ts +27 -28
  69. package/dist/endpoints/branch-databases.d.ts.map +1 -1
  70. package/dist/endpoints/branch-databases.js +7 -7
  71. package/dist/endpoints/databases.d.ts +253 -3
  72. package/dist/endpoints/databases.d.ts.map +1 -1
  73. package/dist/endpoints/databases.js +19 -12
  74. package/dist/endpoints/environments.d.ts +9 -0
  75. package/dist/endpoints/environments.d.ts.map +1 -1
  76. package/dist/endpoints/organizations.d.ts +11 -0
  77. package/dist/endpoints/organizations.d.ts.map +1 -1
  78. package/dist/endpoints/organizations.js +8 -1
  79. package/dist/endpoints/project-manifest.d.ts +42 -34
  80. package/dist/endpoints/project-manifest.d.ts.map +1 -1
  81. package/dist/endpoints/secrets.d.ts +6 -6
  82. package/dist/endpoints/secrets.d.ts.map +1 -1
  83. package/dist/endpoints/secrets.js +6 -5
  84. package/dist/endpoints/storage.d.ts +4 -6
  85. package/dist/endpoints/storage.d.ts.map +1 -1
  86. package/dist/endpoints/storage.js +1 -12
  87. package/dist/hono-app.d.ts +206 -0
  88. package/dist/hono-app.d.ts.map +1 -0
  89. package/dist/hono-app.js +62 -0
  90. package/dist/index.d.ts +503 -278
  91. package/dist/index.d.ts.map +1 -1
  92. package/dist/index.js +10 -4
  93. package/dist/schemas/admin-audit.d.ts +183 -0
  94. package/dist/schemas/admin-audit.d.ts.map +1 -1
  95. package/dist/schemas/admin-audit.js +144 -0
  96. package/dist/schemas/admin-consent.d.ts +32 -3
  97. package/dist/schemas/admin-consent.d.ts.map +1 -1
  98. package/dist/schemas/admin-consent.js +28 -1
  99. package/dist/schemas/admin-projects.d.ts +20 -0
  100. package/dist/schemas/admin-projects.d.ts.map +1 -1
  101. package/dist/schemas/admin-projects.js +17 -0
  102. package/dist/schemas/auth.d.ts +11 -0
  103. package/dist/schemas/auth.d.ts.map +1 -1
  104. package/dist/schemas/auth.js +10 -0
  105. package/dist/schemas/branch-database.d.ts +20 -19
  106. package/dist/schemas/branch-database.d.ts.map +1 -1
  107. package/dist/schemas/branch-database.js +9 -7
  108. package/dist/schemas/environment.d.ts +6 -0
  109. package/dist/schemas/environment.d.ts.map +1 -1
  110. package/dist/schemas/environment.js +2 -0
  111. package/dist/schemas/ids.d.ts +2 -0
  112. package/dist/schemas/ids.d.ts.map +1 -1
  113. package/dist/schemas/ids.js +1 -0
  114. package/dist/schemas/organization.d.ts +24 -2
  115. package/dist/schemas/organization.d.ts.map +1 -1
  116. package/dist/schemas/organization.js +13 -1
  117. package/dist/schemas/project-manifest.d.ts +59 -37
  118. package/dist/schemas/project-manifest.d.ts.map +1 -1
  119. package/dist/schemas/project-manifest.js +11 -3
  120. package/dist/schemas/secret.d.ts +1 -1
  121. package/dist/schemas/secret.js +2 -2
  122. package/dist/schemas/storage.d.ts +4 -5
  123. package/dist/schemas/storage.d.ts.map +1 -1
  124. package/dist/schemas/storage.js +5 -4
  125. package/package.json +16 -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":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4DG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AACpC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAChC,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAMxE,KAAK,cAAc,GAAG,OAAO,MAAM,EAAE,MAAM,CAAA;AAM3C;;;GAGG;AACH,KAAK,mBAAmB,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,OAAO,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI,GAAG,KAAK,CAAC,SAAS,CAClF,CAAC,EAAE,MAAM,CAAC,KACN,IAAI,GACN,CAAC,GACD,KAAK,CAAA;AAER;;;;;;;;;GASG;AACH,KAAK,YAAY,CAAC,CAAC,IAAI,CAAC,SAAS,IAAI,GAAG,MAAM,GAAG,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,GAC/E,CAAC,GACD,CAAC,SAAS,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GACvE,CAAC,GACD,CAAC,SAAS,aAAa,CAAC,MAAM,CAAC,CAAC,GAC/B,YAAY,CAAC,CAAC,CAAC,EAAE,GACjB,CAAC,SAAS,MAAM,GACf;IAAE,CAAC,UAAU,CAAC,IAAI,MAAM,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,GAChD,CAAC,CAAA;AAEP;;;;;;;;;;;;;;;;GAgBG;AACH,KAAK,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,MAAM,CAAC,MAAM,CAAC,YAAY,GACtD,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GACnC,KAAK,CAAA;AAER;;;;;;GAMG;AACH,KAAK,SAAS,CAAC,IAAI,SAAS,MAAM,EAAE,QAAQ,SAAS,MAAM,IAAI,QAAQ,SAAS,GAAG,GAChF,IAAI,GACJ,IAAI,SAAS,GAAG,QAAQ,GAAG,MAAM,IAAI,EAAE,GACtC,IAAI,SAAS,EAAE,GACd,GAAG,GACH,IAAI,GACL,IAAI,CAAA;AAMR;;;;;;;;;;;GAWG;AACH,KAAK,aAAa,CAAC,CAAC,SAAS,QAAQ,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,MAAM,CAAC,MAAM,CAAC,YAAY,GACrF;IAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;CAAE,GAEnC,EAAE,CAAC,GACJ,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,MAAM,CAAC,MAAM,CAAC,YAAY,GAC3C;IAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAA;CAAE,GAElC,EAAE,CAAC,GACL,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,MAAM,CAAC,MAAM,CAAC,YAAY,GAC1C;IAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;CAAE,GAEhC,EAAE,CAAC,CAAA;AAEN;;;;;;;;;GASG;AACH,KAAK,mBAAmB,CAAC,CAAC,SAAS,QAAQ,EAAE,QAAQ,SAAS,MAAM,IAAI;KACtE,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,GAAG;SACrC,CAAC,IAAI,IAAI,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG;YACpC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,CAAA;YACvB,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAA;YACjC,YAAY,EAAE,MAAM,CAAA;YACpB,MAAM,EAAE,GAAG,CAAA;SACX;KACD;CACD,CAAA;AAMD;;;;;;;;;;;;;GAaG;AACH,KAAK,eAAe,CAAC,CAAC,SAAS,aAAa,EAAE,QAAQ,SAAS,MAAM,IAAI,mBAAmB,CAC3F;KACE,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,QAAQ,GAClC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,GACnC,CAAC,CAAC,CAAC,CAAC,SAAS,aAAa,GACzB,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,GAC/B,KAAK;CACT,CAAC,MAAM,CAAC,CAAC,CACV,CAAA;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAOH,KAAK,YAAY,CAAC,CAAC,IAAI,CAAC,SAAS,cAAc,GAAG,CAAC,GAAG,KAAK,CAAA;AAE3D,MAAM,MAAM,oBAAoB,CAAC,CAAC,SAAS,aAAa,EAAE,QAAQ,SAAS,MAAM,GAAG,GAAG,IAAI,IAAI,CAC9F,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EACpB,YAAY,CAAC,eAAe,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,EAC1C,QAAQ,CACR,CAAA;AAMD,6EAA6E;AAC7E,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,UAAU,EAAE,CAAA"}
@@ -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 {};