ts-procedures 5.16.0 → 6.0.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/README.md +2 -0
- package/agent_config/claude-code/agents/ts-procedures-architect.md +13 -6
- package/agent_config/claude-code/skills/ts-procedures/SKILL.md +26 -4
- package/agent_config/claude-code/skills/ts-procedures/anti-patterns.md +87 -19
- package/agent_config/claude-code/skills/ts-procedures/api-reference.md +162 -16
- package/agent_config/claude-code/skills/ts-procedures/patterns.md +179 -16
- package/agent_config/claude-code/skills/ts-procedures-review/SKILL.md +1 -1
- package/agent_config/claude-code/skills/ts-procedures-review/checklist.md +20 -12
- package/agent_config/claude-code/skills/ts-procedures-scaffold/SKILL.md +2 -1
- package/agent_config/claude-code/skills/ts-procedures-scaffold/templates/client.md +22 -15
- package/agent_config/claude-code/skills/ts-procedures-scaffold/templates/express-rpc.md +20 -17
- package/agent_config/claude-code/skills/ts-procedures-scaffold/templates/hono-api.md +20 -16
- package/agent_config/claude-code/skills/ts-procedures-scaffold/templates/hono-rpc.md +20 -17
- package/agent_config/claude-code/skills/ts-procedures-scaffold/templates/hono-stream.md +16 -3
- package/agent_config/copilot/copilot-instructions.md +78 -12
- package/agent_config/cursor/cursorrules +78 -12
- package/build/client/call.d.ts +2 -1
- package/build/client/call.js +9 -1
- package/build/client/call.js.map +1 -1
- package/build/client/error-dispatch.d.ts +13 -0
- package/build/client/error-dispatch.js +26 -0
- package/build/client/error-dispatch.js.map +1 -0
- package/build/client/error-dispatch.test.d.ts +1 -0
- package/build/client/error-dispatch.test.js +56 -0
- package/build/client/error-dispatch.test.js.map +1 -0
- package/build/client/fetch-adapter.js +10 -4
- package/build/client/fetch-adapter.js.map +1 -1
- package/build/client/index.d.ts +2 -1
- package/build/client/index.js +5 -1
- package/build/client/index.js.map +1 -1
- package/build/client/stream.d.ts +2 -1
- package/build/client/stream.js +13 -3
- package/build/client/stream.js.map +1 -1
- package/build/client/typed-error-dispatch.test.d.ts +1 -0
- package/build/client/typed-error-dispatch.test.js +168 -0
- package/build/client/typed-error-dispatch.test.js.map +1 -0
- package/build/client/types.d.ts +37 -0
- package/build/codegen/e2e.test.js +9 -4
- package/build/codegen/e2e.test.js.map +1 -1
- package/build/codegen/emit-client-runtime.js +4 -0
- package/build/codegen/emit-client-runtime.js.map +1 -1
- package/build/codegen/emit-errors.d.ts +17 -6
- package/build/codegen/emit-errors.integration.test.d.ts +1 -0
- package/build/codegen/emit-errors.integration.test.js +162 -0
- package/build/codegen/emit-errors.integration.test.js.map +1 -0
- package/build/codegen/emit-errors.js +50 -39
- package/build/codegen/emit-errors.js.map +1 -1
- package/build/codegen/emit-errors.test.js +75 -78
- package/build/codegen/emit-errors.test.js.map +1 -1
- package/build/codegen/emit-index.d.ts +7 -0
- package/build/codegen/emit-index.js +26 -4
- package/build/codegen/emit-index.js.map +1 -1
- package/build/codegen/emit-index.test.js +55 -23
- package/build/codegen/emit-index.test.js.map +1 -1
- package/build/codegen/emit-scope.d.ts +8 -0
- package/build/codegen/emit-scope.js +82 -7
- package/build/codegen/emit-scope.js.map +1 -1
- package/build/codegen/pipeline.js +22 -2
- package/build/codegen/pipeline.js.map +1 -1
- package/build/implementations/http/doc-registry.d.ts +17 -1
- package/build/implementations/http/doc-registry.js +47 -79
- package/build/implementations/http/doc-registry.js.map +1 -1
- package/build/implementations/http/doc-registry.test.js +149 -16
- package/build/implementations/http/doc-registry.test.js.map +1 -1
- 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 +39 -8
- package/build/implementations/http/express-rpc/index.js +39 -8
- package/build/implementations/http/express-rpc/index.js.map +1 -1
- 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 +38 -1
- package/build/implementations/http/hono-api/index.js +32 -0
- package/build/implementations/http/hono-api/index.js.map +1 -1
- 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 +34 -7
- package/build/implementations/http/hono-rpc/index.js +31 -4
- package/build/implementations/http/hono-rpc/index.js.map +1 -1
- package/build/implementations/http/hono-stream/error-taxonomy.test.d.ts +1 -0
- package/build/implementations/http/hono-stream/error-taxonomy.test.js +87 -0
- package/build/implementations/http/hono-stream/error-taxonomy.test.js.map +1 -0
- package/build/implementations/http/hono-stream/index.d.ts +40 -3
- package/build/implementations/http/hono-stream/index.js +37 -10
- package/build/implementations/http/hono-stream/index.js.map +1 -1
- package/build/implementations/http/hono-stream/index.test.js +45 -18
- package/build/implementations/http/hono-stream/index.test.js.map +1 -1
- 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 +43 -3
- package/docs/client-and-codegen.md +105 -12
- package/docs/core.md +14 -5
- package/docs/http-integrations.md +138 -5
- package/docs/streaming.md +3 -1
- package/docs/superpowers/plans/2026-04-24-doc-registry-simplification.md +886 -0
- package/package.json +7 -2
- package/src/client/call.ts +10 -1
- package/src/client/error-dispatch.test.ts +72 -0
- package/src/client/error-dispatch.ts +27 -0
- package/src/client/fetch-adapter.ts +11 -5
- package/src/client/index.ts +9 -0
- package/src/client/stream.ts +14 -3
- package/src/client/typed-error-dispatch.test.ts +211 -0
- package/src/client/types.ts +42 -0
- package/src/codegen/e2e.test.ts +9 -4
- package/src/codegen/emit-client-runtime.ts +4 -0
- package/src/codegen/emit-errors.integration.test.ts +183 -0
- package/src/codegen/emit-errors.test.ts +91 -87
- package/src/codegen/emit-errors.ts +123 -41
- package/src/codegen/emit-index.test.ts +68 -24
- package/src/codegen/emit-index.ts +66 -4
- package/src/codegen/emit-scope.ts +124 -7
- package/src/codegen/pipeline.ts +25 -2
- package/src/implementations/http/README.md +21 -7
- package/src/implementations/http/doc-registry.test.ts +164 -16
- package/src/implementations/http/doc-registry.ts +58 -82
- package/src/implementations/http/error-taxonomy.test.ts +438 -0
- package/src/implementations/http/error-taxonomy.ts +361 -0
- package/src/implementations/http/express-rpc/README.md +23 -24
- package/src/implementations/http/express-rpc/error-taxonomy.test.ts +103 -0
- package/src/implementations/http/express-rpc/index.ts +75 -14
- package/src/implementations/http/hono-api/README.md +284 -0
- package/src/implementations/http/hono-api/error-taxonomy.test.ts +179 -0
- package/src/implementations/http/hono-api/index.ts +76 -1
- package/src/implementations/http/hono-rpc/README.md +20 -21
- package/src/implementations/http/hono-rpc/error-taxonomy.test.ts +82 -0
- package/src/implementations/http/hono-rpc/index.ts +65 -9
- package/src/implementations/http/hono-stream/README.md +44 -25
- package/src/implementations/http/hono-stream/error-taxonomy.test.ts +98 -0
- package/src/implementations/http/hono-stream/index.test.ts +54 -18
- package/src/implementations/http/hono-stream/index.ts +83 -13
- package/src/implementations/http/on-request-error.test.ts +201 -0
- package/src/implementations/http/route-errors.test.ts +176 -0
- package/src/implementations/types.ts +43 -3
|
@@ -196,24 +196,90 @@ const app = new HonoAPIAppBuilder({ pathPrefix: '/api' })
|
|
|
196
196
|
|
|
197
197
|
| Error Class | Trigger | HTTP Status |
|
|
198
198
|
|-------------|---------|-------------|
|
|
199
|
-
| `ProcedureValidationError` | Schema params validation failure | 400 |
|
|
200
|
-
| `ProcedureError` | `ctx.error()` or unhandled handler exception |
|
|
199
|
+
| `ProcedureValidationError` | Schema params validation failure | 400 (auto — default taxonomy) |
|
|
200
|
+
| `ProcedureError` | `ctx.error()` or unhandled handler exception | 500 (auto — default taxonomy) |
|
|
201
201
|
| `ProcedureYieldValidationError` | Yield validation failure (validateYields: true) | N/A (mid-stream) |
|
|
202
202
|
| `ProcedureRegistrationError` | Invalid schema or duplicate name at registration | N/A (startup) |
|
|
203
203
|
|
|
204
|
+
### Error Taxonomy (required for custom errors)
|
|
205
|
+
|
|
206
|
+
`defineErrorTaxonomy` maps error classes to HTTP responses declaratively. Works with every HTTP builder (`hono-api`, `hono-rpc`, `express-rpc`, `hono-stream` pre-stream).
|
|
207
|
+
|
|
208
|
+
Do NOT write `onError` `instanceof` ladders — that's anti-pattern #20. Use the taxonomy instead:
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
import { defineErrorTaxonomy } from 'ts-procedures/http-errors'
|
|
212
|
+
|
|
213
|
+
class UseCaseError extends Error {
|
|
214
|
+
constructor(readonly externalMsg: string, readonly internalMsg: string) {
|
|
215
|
+
super(externalMsg); this.name = 'UseCaseError'
|
|
216
|
+
Object.setPrototypeOf(this, UseCaseError.prototype)
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const appErrors = defineErrorTaxonomy({
|
|
221
|
+
// class: entries are topologically sorted (subclasses checked first) automatically.
|
|
222
|
+
// Predicate (match:) entries keep declared order — put narrower predicates first.
|
|
223
|
+
UseCaseError: {
|
|
224
|
+
class: UseCaseError,
|
|
225
|
+
statusCode: 422,
|
|
226
|
+
toResponse: (err) => ({ name: 'UseCaseError', message: err.externalMsg }),
|
|
227
|
+
onCatch: (err) => logger.error(err.internalMsg), // internal logs only
|
|
228
|
+
},
|
|
229
|
+
MongoDuplicateKey: {
|
|
230
|
+
match: (err): err is Error => err instanceof Error && (err as any).code === 11000,
|
|
231
|
+
statusCode: 409,
|
|
232
|
+
toResponse: () => ({ name: 'Conflict', message: 'Resource already exists' }),
|
|
233
|
+
},
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
new HonoAPIAppBuilder({
|
|
237
|
+
errors: appErrors,
|
|
238
|
+
unknownError: { statusCode: 500, toResponse: () => ({ name: 'InternalServerError' }) },
|
|
239
|
+
})
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Handlers throw the error classes directly — the builder auto-serializes. `onError` is the first-class imperative peer when you want to handle errors in one callback instead (both modes coexist). In v6 `HonoStreamAppBuilder.onPreStreamError` was renamed to `onError`. Cross-cutting `onRequestError` observer fires for every caught error.
|
|
243
|
+
|
|
244
|
+
### Per-route errors (typed)
|
|
245
|
+
|
|
246
|
+
`APIConfig` and `RPCConfig` are generic over `TErrorKey extends string = string`. Narrow to your taxonomy for compile-time typo protection and route-level error doc entries:
|
|
247
|
+
|
|
204
248
|
```typescript
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
249
|
+
import { APIConfig } from 'ts-procedures/http'
|
|
250
|
+
import { DocRegistry } from 'ts-procedures/http-docs'
|
|
251
|
+
|
|
252
|
+
type MyAPIConfig = APIConfig<keyof typeof appErrors & string>
|
|
253
|
+
const API = Procedures<Ctx, MyAPIConfig>()
|
|
254
|
+
|
|
255
|
+
API.Create('GetUser', { path: '/users/:id', method: 'get', errors: ['UseCaseError'], /* ... */ }, ...)
|
|
256
|
+
|
|
257
|
+
// Seed envelope errors from the taxonomy + framework defaults in one call
|
|
258
|
+
const envelope = new DocRegistry({ errors: appErrors, basePath: '/api' }).from(apiApp).toJSON()
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Client-side typed catch blocks (via codegen)
|
|
262
|
+
|
|
263
|
+
The generated `_errors.ts` emits real runtime classes extending a shared `${Service}ProcedureError` base. The generated `createApiClient` wires an error registry so non-2xx responses arrive as typed class instances:
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
import { createApiClient, ApiErrors, createFetchAdapter } from './generated'
|
|
267
|
+
|
|
268
|
+
const api = createApiClient({ adapter: createFetchAdapter({ /* ... */ }), basePath: '...' })
|
|
269
|
+
|
|
270
|
+
try {
|
|
271
|
+
await api.users.getUser({ pathParams: { id: 'x' } })
|
|
272
|
+
} catch (err) {
|
|
273
|
+
if (err instanceof ApiErrors.UseCaseError) {
|
|
274
|
+
// err.body typed; err.status, err.procedureName, err.scope available
|
|
275
|
+
} else if (err instanceof ApiErrors.ApiProcedureError) {
|
|
276
|
+
// Catch-all for any service error
|
|
213
277
|
}
|
|
214
278
|
}
|
|
215
279
|
```
|
|
216
280
|
|
|
281
|
+
Per-route error unions: routes with `errors: [...]` get an `Errors` type in their namespace (e.g. `Users.GetUser.Errors = ApiErrors.UseCaseError | ApiErrors.AuthError`).
|
|
282
|
+
|
|
217
283
|
## Lifecycle Hook Order
|
|
218
284
|
|
|
219
285
|
### Standard RPC
|
|
@@ -225,7 +291,7 @@ onRequestStart → factoryContext() → handler() → onSuccess → onRequestEnd
|
|
|
225
291
|
### Streaming
|
|
226
292
|
```
|
|
227
293
|
onRequestStart → factoryContext() → validation → onStreamStart → handler yields → onStreamEnd → onRequestEnd
|
|
228
|
-
→
|
|
294
|
+
→ onError (or taxonomy) → onRequestEnd
|
|
229
295
|
→ onMidStreamError → onStreamEnd → onRequestEnd
|
|
230
296
|
```
|
|
231
297
|
|
|
@@ -320,7 +386,7 @@ npx ts-procedures-codegen --url http://localhost:3000/docs --out ./src/generated
|
|
|
320
386
|
# --clean-out-dir # recursively wipe --out before writing (prunes stale scope files)
|
|
321
387
|
```
|
|
322
388
|
|
|
323
|
-
Generates one `.ts` file per scope plus a root `index.ts` that imports each scope as a namespace and exports a `create${ServiceName}Bindings` factory (defaults to `createApiBindings`; pass `--service-name <Name>` to rename). When namespace mode is on (the default), `index.ts` also wraps every scope namespace in an outer `export namespace ${ServiceName} { ... }` block so types are reachable as `Api.Users.GetUser.Params`, `Api.Errors.
|
|
389
|
+
Generates one `.ts` file per scope plus a root `index.ts` that imports each scope as a namespace and exports a `create${ServiceName}Bindings(client)` factory AND a `create${ServiceName}Client(config)` convenience factory that pre-wires the error registry (defaults to `createApiBindings` / `createApiClient`; pass `--service-name <Name>` to rename). When namespace mode is on (the default), `index.ts` also wraps every scope namespace in an outer `export namespace ${ServiceName} { ... }` block so types are reachable as `Api.Users.GetUser.Params`, `Api.Errors.UseCaseError`, etc. The errors file (`_errors.ts`) emits runtime error classes extending a shared `${ServiceName}ProcedureError` base, each with `static fromResponse(body, meta)`, plus `${ServiceName}ErrorRegistry` (runtime dispatch map) and `${ServiceName}ProcedureErrorUnion` (type union). Defaults: `ApiErrors`, `ApiProcedureError`, `ApiErrorRegistry`, `ApiProcedureErrorUnion`.
|
|
324
390
|
By default, types are wrapped in nested TS namespaces (`Scope.Route.Params`), JSDoc comments are emitted, and output is self-contained (no runtime dependency on `ts-procedures`). Use `--no-namespace-types` to revert to flat type names (`RouteParams`); this also disables the outer service namespace in `index.ts` and skips importing `_errors` from there.
|
|
325
391
|
Note: ajsc formatting options (`--enum-style enum`, `--depluralize`, etc.) only take effect in namespace mode (the default). They are ignored with `--no-namespace-types`.
|
|
326
392
|
Supports config file: `ts-procedures-codegen.config.json` (auto-loaded from CWD) or `--config <path>`.
|
|
@@ -196,24 +196,90 @@ const app = new HonoAPIAppBuilder({ pathPrefix: '/api' })
|
|
|
196
196
|
|
|
197
197
|
| Error Class | Trigger | HTTP Status |
|
|
198
198
|
|-------------|---------|-------------|
|
|
199
|
-
| `ProcedureValidationError` | Schema params validation failure | 400 |
|
|
200
|
-
| `ProcedureError` | `ctx.error()` or unhandled handler exception |
|
|
199
|
+
| `ProcedureValidationError` | Schema params validation failure | 400 (auto — default taxonomy) |
|
|
200
|
+
| `ProcedureError` | `ctx.error()` or unhandled handler exception | 500 (auto — default taxonomy) |
|
|
201
201
|
| `ProcedureYieldValidationError` | Yield validation failure (validateYields: true) | N/A (mid-stream) |
|
|
202
202
|
| `ProcedureRegistrationError` | Invalid schema or duplicate name at registration | N/A (startup) |
|
|
203
203
|
|
|
204
|
+
### Error Taxonomy (required for custom errors)
|
|
205
|
+
|
|
206
|
+
`defineErrorTaxonomy` maps error classes to HTTP responses declaratively. Works with every HTTP builder (`hono-api`, `hono-rpc`, `express-rpc`, `hono-stream` pre-stream).
|
|
207
|
+
|
|
208
|
+
Do NOT write `onError` `instanceof` ladders — that's anti-pattern #20. Use the taxonomy instead:
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
import { defineErrorTaxonomy } from 'ts-procedures/http-errors'
|
|
212
|
+
|
|
213
|
+
class UseCaseError extends Error {
|
|
214
|
+
constructor(readonly externalMsg: string, readonly internalMsg: string) {
|
|
215
|
+
super(externalMsg); this.name = 'UseCaseError'
|
|
216
|
+
Object.setPrototypeOf(this, UseCaseError.prototype)
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const appErrors = defineErrorTaxonomy({
|
|
221
|
+
// class: entries are topologically sorted (subclasses checked first) automatically.
|
|
222
|
+
// Predicate (match:) entries keep declared order — put narrower predicates first.
|
|
223
|
+
UseCaseError: {
|
|
224
|
+
class: UseCaseError,
|
|
225
|
+
statusCode: 422,
|
|
226
|
+
toResponse: (err) => ({ name: 'UseCaseError', message: err.externalMsg }),
|
|
227
|
+
onCatch: (err) => logger.error(err.internalMsg), // internal logs only
|
|
228
|
+
},
|
|
229
|
+
MongoDuplicateKey: {
|
|
230
|
+
match: (err): err is Error => err instanceof Error && (err as any).code === 11000,
|
|
231
|
+
statusCode: 409,
|
|
232
|
+
toResponse: () => ({ name: 'Conflict', message: 'Resource already exists' }),
|
|
233
|
+
},
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
new HonoAPIAppBuilder({
|
|
237
|
+
errors: appErrors,
|
|
238
|
+
unknownError: { statusCode: 500, toResponse: () => ({ name: 'InternalServerError' }) },
|
|
239
|
+
})
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Handlers throw the error classes directly — the builder auto-serializes. `onError` is the first-class imperative peer when you want to handle errors in one callback instead (both modes coexist). In v6 `HonoStreamAppBuilder.onPreStreamError` was renamed to `onError`. Cross-cutting `onRequestError` observer fires for every caught error.
|
|
243
|
+
|
|
244
|
+
### Per-route errors (typed)
|
|
245
|
+
|
|
246
|
+
`APIConfig` and `RPCConfig` are generic over `TErrorKey extends string = string`. Narrow to your taxonomy for compile-time typo protection and route-level error doc entries:
|
|
247
|
+
|
|
204
248
|
```typescript
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
249
|
+
import { APIConfig } from 'ts-procedures/http'
|
|
250
|
+
import { DocRegistry } from 'ts-procedures/http-docs'
|
|
251
|
+
|
|
252
|
+
type MyAPIConfig = APIConfig<keyof typeof appErrors & string>
|
|
253
|
+
const API = Procedures<Ctx, MyAPIConfig>()
|
|
254
|
+
|
|
255
|
+
API.Create('GetUser', { path: '/users/:id', method: 'get', errors: ['UseCaseError'], /* ... */ }, ...)
|
|
256
|
+
|
|
257
|
+
// Seed envelope errors from the taxonomy + framework defaults in one call
|
|
258
|
+
const envelope = new DocRegistry({ errors: appErrors, basePath: '/api' }).from(apiApp).toJSON()
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Client-side typed catch blocks (via codegen)
|
|
262
|
+
|
|
263
|
+
The generated `_errors.ts` emits real runtime classes extending a shared `${Service}ProcedureError` base. The generated `createApiClient` wires an error registry so non-2xx responses arrive as typed class instances:
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
import { createApiClient, ApiErrors, createFetchAdapter } from './generated'
|
|
267
|
+
|
|
268
|
+
const api = createApiClient({ adapter: createFetchAdapter({ /* ... */ }), basePath: '...' })
|
|
269
|
+
|
|
270
|
+
try {
|
|
271
|
+
await api.users.getUser({ pathParams: { id: 'x' } })
|
|
272
|
+
} catch (err) {
|
|
273
|
+
if (err instanceof ApiErrors.UseCaseError) {
|
|
274
|
+
// err.body typed; err.status, err.procedureName, err.scope available
|
|
275
|
+
} else if (err instanceof ApiErrors.ApiProcedureError) {
|
|
276
|
+
// Catch-all for any service error
|
|
213
277
|
}
|
|
214
278
|
}
|
|
215
279
|
```
|
|
216
280
|
|
|
281
|
+
Per-route error unions: routes with `errors: [...]` get an `Errors` type in their namespace (e.g. `Users.GetUser.Errors = ApiErrors.UseCaseError | ApiErrors.AuthError`).
|
|
282
|
+
|
|
217
283
|
## Lifecycle Hook Order
|
|
218
284
|
|
|
219
285
|
### Standard RPC
|
|
@@ -225,7 +291,7 @@ onRequestStart → factoryContext() → handler() → onSuccess → onRequestEnd
|
|
|
225
291
|
### Streaming
|
|
226
292
|
```
|
|
227
293
|
onRequestStart → factoryContext() → validation → onStreamStart → handler yields → onStreamEnd → onRequestEnd
|
|
228
|
-
→
|
|
294
|
+
→ onError (or taxonomy) → onRequestEnd
|
|
229
295
|
→ onMidStreamError → onStreamEnd → onRequestEnd
|
|
230
296
|
```
|
|
231
297
|
|
|
@@ -320,7 +386,7 @@ npx ts-procedures-codegen --url http://localhost:3000/docs --out ./src/generated
|
|
|
320
386
|
# --clean-out-dir # recursively wipe --out before writing (prunes stale scope files)
|
|
321
387
|
```
|
|
322
388
|
|
|
323
|
-
Generates one `.ts` file per scope plus a root `index.ts` that imports each scope as a namespace and exports a `create${ServiceName}Bindings` factory (defaults to `createApiBindings`; pass `--service-name <Name>` to rename). When namespace mode is on (the default), `index.ts` also wraps every scope namespace in an outer `export namespace ${ServiceName} { ... }` block so types are reachable as `Api.Users.GetUser.Params`, `Api.Errors.
|
|
389
|
+
Generates one `.ts` file per scope plus a root `index.ts` that imports each scope as a namespace and exports a `create${ServiceName}Bindings(client)` factory AND a `create${ServiceName}Client(config)` convenience factory that pre-wires the error registry (defaults to `createApiBindings` / `createApiClient`; pass `--service-name <Name>` to rename). When namespace mode is on (the default), `index.ts` also wraps every scope namespace in an outer `export namespace ${ServiceName} { ... }` block so types are reachable as `Api.Users.GetUser.Params`, `Api.Errors.UseCaseError`, etc. The errors file (`_errors.ts`) emits runtime error classes extending a shared `${ServiceName}ProcedureError` base, each with `static fromResponse(body, meta)`, plus `${ServiceName}ErrorRegistry` (runtime dispatch map) and `${ServiceName}ProcedureErrorUnion` (type union). Defaults: `ApiErrors`, `ApiProcedureError`, `ApiErrorRegistry`, `ApiProcedureErrorUnion`.
|
|
324
390
|
By default, types are wrapped in nested TS namespaces (`Scope.Route.Params`), JSDoc comments are emitted, and output is self-contained (no runtime dependency on `ts-procedures`). Use `--no-namespace-types` to revert to flat type names (`RouteParams`); this also disables the outer service namespace in `index.ts` and skips importing `_errors` from there.
|
|
325
391
|
Note: ajsc formatting options (`--enum-style enum`, `--depluralize`, etc.) only take effect in namespace mode (the default). They are ignored with `--no-namespace-types`.
|
|
326
392
|
Supports config file: `ts-procedures-codegen.config.json` (auto-loaded from CWD) or `--config <path>`.
|
package/build/client/call.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ClientAdapter, ClientHooks, CallDescriptor, ProcedureCallDefaults, ProcedureCallOptions } from './types.js';
|
|
1
|
+
import type { ClientAdapter, ClientHooks, CallDescriptor, ErrorRegistry, ProcedureCallDefaults, ProcedureCallOptions } from './types.js';
|
|
2
2
|
export interface ExecuteCallConfig {
|
|
3
3
|
descriptor: CallDescriptor;
|
|
4
4
|
basePath: string;
|
|
@@ -6,6 +6,7 @@ export interface ExecuteCallConfig {
|
|
|
6
6
|
hooks: ClientHooks;
|
|
7
7
|
defaults?: ProcedureCallDefaults;
|
|
8
8
|
options?: ProcedureCallOptions;
|
|
9
|
+
errorRegistry?: ErrorRegistry;
|
|
9
10
|
}
|
|
10
11
|
/**
|
|
11
12
|
* Executes a single procedure call through the adapter.
|
package/build/client/call.js
CHANGED
|
@@ -2,6 +2,7 @@ import { buildAdapterRequest } from './request-builder.js';
|
|
|
2
2
|
import { runBeforeRequest, runAfterResponse, runOnError } from './hooks.js';
|
|
3
3
|
import { applyRequestOptions, resolveBasePath } from './resolve-options.js';
|
|
4
4
|
import { ClientRequestError } from './errors.js';
|
|
5
|
+
import { dispatchTypedError } from './error-dispatch.js';
|
|
5
6
|
/**
|
|
6
7
|
* Executes a single procedure call through the adapter.
|
|
7
8
|
*
|
|
@@ -16,7 +17,7 @@ import { ClientRequestError } from './errors.js';
|
|
|
16
17
|
* 8. Return response.body as TResponse
|
|
17
18
|
*/
|
|
18
19
|
export async function executeCall(config) {
|
|
19
|
-
const { descriptor, basePath, adapter, hooks, defaults, options } = config;
|
|
20
|
+
const { descriptor, basePath, adapter, hooks, defaults, options, errorRegistry } = config;
|
|
20
21
|
// 1. Build the initial request (path/query/body from descriptor)
|
|
21
22
|
const resolvedBasePath = resolveBasePath(defaults, options, basePath);
|
|
22
23
|
let request = buildAdapterRequest(descriptor, resolvedBasePath);
|
|
@@ -39,6 +40,13 @@ export async function executeCall(config) {
|
|
|
39
40
|
await runAfterResponse({ procedureName: descriptor.name, scope: descriptor.scope, request, response }, hooks, options);
|
|
40
41
|
// 7. Check status AFTER hooks (hooks may have swallowed the error by mutating status)
|
|
41
42
|
if (response.status < 200 || response.status >= 300) {
|
|
43
|
+
const typed = dispatchTypedError(errorRegistry, response.body, {
|
|
44
|
+
status: response.status,
|
|
45
|
+
procedureName: descriptor.name,
|
|
46
|
+
scope: descriptor.scope,
|
|
47
|
+
});
|
|
48
|
+
if (typed)
|
|
49
|
+
throw typed;
|
|
42
50
|
throw new ClientRequestError({
|
|
43
51
|
status: response.status,
|
|
44
52
|
headers: response.headers,
|
package/build/client/call.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"call.js","sourceRoot":"","sources":["../../src/client/call.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAC1D,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAC3E,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"call.js","sourceRoot":"","sources":["../../src/client/call.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAC1D,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAC3E,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAA;AAoBxD;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAY,MAAyB;IACpE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAE,GAAG,MAAM,CAAA;IAEzF,iEAAiE;IACjE,MAAM,gBAAgB,GAAG,eAAe,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAA;IACrE,IAAI,OAAO,GAAG,mBAAmB,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAA;IAE/D,kEAAkE;IAClE,OAAO,GAAG,mBAAmB,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAA;IAEzD,oEAAoE;IACpE,MAAM,SAAS,GAAG,MAAM,gBAAgB,CACtC,EAAE,aAAa,EAAE,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,EACpE,KAAK,EACL,OAAO,CACR,CAAA;IACD,OAAO,GAAG,SAAS,CAAC,OAAO,CAAA;IAE3B,sBAAsB;IACtB,IAAI,QAAQ,CAAA;IACZ,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;IAC3C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,iDAAiD;QACjD,MAAM,UAAU,CACd,EAAE,aAAa,EAAE,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,EAChF,KAAK,EACL,OAAO,CACR,CAAA;QACD,MAAM,GAAG,CAAA;IACX,CAAC;IAED,kFAAkF;IAClF,MAAM,gBAAgB,CACpB,EAAE,aAAa,EAAE,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,EAC9E,KAAK,EACL,OAAO,CACR,CAAA;IAED,sFAAsF;IACtF,IAAI,QAAQ,CAAC,MAAM,GAAG,GAAG,IAAI,QAAQ,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC;QACpD,MAAM,KAAK,GAAG,kBAAkB,CAAC,aAAa,EAAE,QAAQ,CAAC,IAAI,EAAE;YAC7D,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,aAAa,EAAE,UAAU,CAAC,IAAI;YAC9B,KAAK,EAAE,UAAU,CAAC,KAAK;SACxB,CAAC,CAAA;QACF,IAAI,KAAK;YAAE,MAAM,KAAK,CAAA;QACtB,MAAM,IAAI,kBAAkB,CAAC;YAC3B,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,OAAO,EAAE,QAAQ,CAAC,OAAO;YACzB,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,aAAa,EAAE,UAAU,CAAC,IAAI;YAC9B,KAAK,EAAE,UAAU,CAAC,KAAK;SACxB,CAAC,CAAA;IACJ,CAAC;IAED,qBAAqB;IACrB,OAAO,QAAQ,CAAC,IAAiB,CAAA;AACnC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ErrorRegistry, ErrorResponseMeta } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Attempts to construct a typed error from the response body using the
|
|
4
|
+
* registry. Returns `null` when:
|
|
5
|
+
* - no registry is configured,
|
|
6
|
+
* - the body is not a plain object with a `name` string,
|
|
7
|
+
* - no registry key matches the body's `name`, or
|
|
8
|
+
* - `fromResponse` returns a non-Error value (defensive — registry entries
|
|
9
|
+
* are expected to return `Error` subclasses).
|
|
10
|
+
*
|
|
11
|
+
* Callers fall back to `ClientRequestError` when this returns `null`.
|
|
12
|
+
*/
|
|
13
|
+
export declare function dispatchTypedError(registry: ErrorRegistry | undefined, body: unknown, meta: ErrorResponseMeta): Error | null;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Attempts to construct a typed error from the response body using the
|
|
3
|
+
* registry. Returns `null` when:
|
|
4
|
+
* - no registry is configured,
|
|
5
|
+
* - the body is not a plain object with a `name` string,
|
|
6
|
+
* - no registry key matches the body's `name`, or
|
|
7
|
+
* - `fromResponse` returns a non-Error value (defensive — registry entries
|
|
8
|
+
* are expected to return `Error` subclasses).
|
|
9
|
+
*
|
|
10
|
+
* Callers fall back to `ClientRequestError` when this returns `null`.
|
|
11
|
+
*/
|
|
12
|
+
export function dispatchTypedError(registry, body, meta) {
|
|
13
|
+
if (!registry)
|
|
14
|
+
return null;
|
|
15
|
+
if (!body || typeof body !== 'object')
|
|
16
|
+
return null;
|
|
17
|
+
const name = body.name;
|
|
18
|
+
if (typeof name !== 'string')
|
|
19
|
+
return null;
|
|
20
|
+
const factory = registry[name];
|
|
21
|
+
if (!factory?.fromResponse)
|
|
22
|
+
return null;
|
|
23
|
+
const result = factory.fromResponse(body, meta);
|
|
24
|
+
return result instanceof Error ? result : null;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=error-dispatch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-dispatch.js","sourceRoot":"","sources":["../../src/client/error-dispatch.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,MAAM,UAAU,kBAAkB,CAChC,QAAmC,EACnC,IAAa,EACb,IAAuB;IAEvB,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAA;IAC1B,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAA;IAClD,MAAM,IAAI,GAAI,IAA2B,CAAC,IAAI,CAAA;IAC9C,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAA;IACzC,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAA;IAC9B,IAAI,CAAC,OAAO,EAAE,YAAY;QAAE,OAAO,IAAI,CAAA;IACvC,MAAM,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;IAC/C,OAAO,MAAM,YAAY,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAA;AAChD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { describe, expect, test } from 'vitest';
|
|
2
|
+
import { dispatchTypedError } from './error-dispatch.js';
|
|
3
|
+
class SyntheticError extends Error {
|
|
4
|
+
props;
|
|
5
|
+
constructor(message, props) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.props = props;
|
|
8
|
+
this.name = 'SyntheticError';
|
|
9
|
+
Object.setPrototypeOf(this, SyntheticError.prototype);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
const meta = { status: 422, procedureName: 'Test', scope: 'users' };
|
|
13
|
+
function makeRegistry() {
|
|
14
|
+
return {
|
|
15
|
+
SyntheticError: {
|
|
16
|
+
fromResponse(body, m) {
|
|
17
|
+
const b = body;
|
|
18
|
+
return new SyntheticError(b.message, b.props);
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
describe('dispatchTypedError', () => {
|
|
24
|
+
test('returns a typed error when body.name matches a registry key', () => {
|
|
25
|
+
const err = dispatchTypedError(makeRegistry(), { name: 'SyntheticError', message: 'bad', props: ['x'] }, meta);
|
|
26
|
+
expect(err).toBeInstanceOf(SyntheticError);
|
|
27
|
+
expect(err).toBeInstanceOf(Error);
|
|
28
|
+
expect(err.props).toEqual(['x']);
|
|
29
|
+
});
|
|
30
|
+
test('returns null when no registry is provided', () => {
|
|
31
|
+
const err = dispatchTypedError(undefined, { name: 'SyntheticError' }, meta);
|
|
32
|
+
expect(err).toBeNull();
|
|
33
|
+
});
|
|
34
|
+
test('returns null when body is not an object', () => {
|
|
35
|
+
expect(dispatchTypedError(makeRegistry(), 'oops', meta)).toBeNull();
|
|
36
|
+
expect(dispatchTypedError(makeRegistry(), null, meta)).toBeNull();
|
|
37
|
+
expect(dispatchTypedError(makeRegistry(), 42, meta)).toBeNull();
|
|
38
|
+
});
|
|
39
|
+
test('returns null when body.name is missing or not a string', () => {
|
|
40
|
+
expect(dispatchTypedError(makeRegistry(), {}, meta)).toBeNull();
|
|
41
|
+
expect(dispatchTypedError(makeRegistry(), { name: 123 }, meta)).toBeNull();
|
|
42
|
+
});
|
|
43
|
+
test('returns null when body.name does not match any registry key', () => {
|
|
44
|
+
expect(dispatchTypedError(makeRegistry(), { name: 'UnregisteredError' }, meta)).toBeNull();
|
|
45
|
+
});
|
|
46
|
+
test('returns null when fromResponse returns a non-Error value', () => {
|
|
47
|
+
const registry = {
|
|
48
|
+
Broken: {
|
|
49
|
+
// Intentionally returns a non-Error — defensive guard in dispatch.
|
|
50
|
+
fromResponse: () => 'not an error',
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
expect(dispatchTypedError(registry, { name: 'Broken' }, meta)).toBeNull();
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
//# sourceMappingURL=error-dispatch.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-dispatch.test.js","sourceRoot":"","sources":["../../src/client/error-dispatch.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAA;AAGxD,MAAM,cAAe,SAAQ,KAAK;IAGrB;IAFX,YACE,OAAe,EACN,KAAe;QAExB,KAAK,CAAC,OAAO,CAAC,CAAA;QAFL,UAAK,GAAL,KAAK,CAAU;QAGxB,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAA;QAC5B,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,cAAc,CAAC,SAAS,CAAC,CAAA;IACvD,CAAC;CACF;AAED,MAAM,IAAI,GAAsB,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,CAAA;AAEtF,SAAS,YAAY;IACnB,OAAO;QACL,cAAc,EAAE;YACd,YAAY,CAAC,IAAI,EAAE,CAAC;gBAClB,MAAM,CAAC,GAAG,IAA4C,CAAA;gBACtD,OAAO,IAAI,cAAc,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAA;YAC/C,CAAC;SACF;KACF,CAAA;AACH,CAAC;AAED,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,IAAI,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACvE,MAAM,GAAG,GAAG,kBAAkB,CAC5B,YAAY,EAAE,EACd,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,EACxD,IAAI,CACL,CAAA;QACD,MAAM,CAAC,GAAG,CAAC,CAAC,cAAc,CAAC,cAAc,CAAC,CAAA;QAC1C,MAAM,CAAC,GAAG,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CAAA;QACjC,MAAM,CAAE,GAAsB,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;IACtD,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACrD,MAAM,GAAG,GAAG,kBAAkB,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,EAAE,IAAI,CAAC,CAAA;QAC3E,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAA;IACxB,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACnD,MAAM,CAAC,kBAAkB,CAAC,YAAY,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;QACnE,MAAM,CAAC,kBAAkB,CAAC,YAAY,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;QACjE,MAAM,CAAC,kBAAkB,CAAC,YAAY,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;IACjE,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAClE,MAAM,CAAC,kBAAkB,CAAC,YAAY,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;QAC/D,MAAM,CAAC,kBAAkB,CAAC,YAAY,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;IAC5E,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACvE,MAAM,CACJ,kBAAkB,CAAC,YAAY,EAAE,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,EAAE,IAAI,CAAC,CACxE,CAAC,QAAQ,EAAE,CAAA;IACd,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,0DAA0D,EAAE,GAAG,EAAE;QACpE,MAAM,QAAQ,GAAkB;YAC9B,MAAM,EAAE;gBACN,mEAAmE;gBACnE,YAAY,EAAE,GAAG,EAAE,CAAC,cAAkC;aACvD;SACF,CAAA;QACD,MAAM,CAAC,kBAAkB,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;IAC3E,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -141,11 +141,17 @@ export function createFetchAdapter(config) {
|
|
|
141
141
|
signal: req.signal,
|
|
142
142
|
});
|
|
143
143
|
const headers = extractHeaders(response);
|
|
144
|
+
const emptyBody = {
|
|
145
|
+
[Symbol.asyncIterator]: async function* () { },
|
|
146
|
+
};
|
|
147
|
+
// Non-2xx responses on a stream endpoint are JSON, not SSE. Parse the
|
|
148
|
+
// body eagerly and surface it via errorBody so the client can dispatch
|
|
149
|
+
// a typed error (or fall back to ClientRequestError with a real body).
|
|
150
|
+
if (response.status < 200 || response.status >= 300) {
|
|
151
|
+
const errorBody = await parseResponseBody(response);
|
|
152
|
+
return { status: response.status, headers, body: emptyBody, errorBody };
|
|
153
|
+
}
|
|
144
154
|
if (!response.body) {
|
|
145
|
-
// No body — return an empty async iterable
|
|
146
|
-
const emptyBody = {
|
|
147
|
-
[Symbol.asyncIterator]: async function* () { },
|
|
148
|
-
};
|
|
149
155
|
return { status: response.status, headers, body: emptyBody };
|
|
150
156
|
}
|
|
151
157
|
const body = parseSseStream(response.body);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-adapter.js","sourceRoot":"","sources":["../../src/client/fetch-adapter.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"fetch-adapter.js","sourceRoot":"","sources":["../../src/client/fetch-adapter.ts"],"names":[],"mappings":"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"}
|
package/build/client/index.d.ts
CHANGED
|
@@ -13,7 +13,8 @@ import type { CreateClientConfig } from './types.js';
|
|
|
13
13
|
* - The outer `.result` is wired up to the inner stream's `.result`.
|
|
14
14
|
*/
|
|
15
15
|
export declare function createClient<TScopes>(config: CreateClientConfig<TScopes>): TScopes;
|
|
16
|
-
export type { ClientAdapter, AdapterRequest, AdapterResponse, AdapterStreamResponse, ClientHooks, BeforeRequestContext, AfterResponseContext, ErrorContext, CallDescriptor, StreamDescriptor, TypedStream, ClientInstance, ProcedureCallDefaults, ProcedureCallOptions, CreateClientConfig, RequestMeta, } from './types.js';
|
|
16
|
+
export type { ClientAdapter, AdapterRequest, AdapterResponse, AdapterStreamResponse, ClientHooks, BeforeRequestContext, AfterResponseContext, ErrorContext, CallDescriptor, StreamDescriptor, TypedStream, ClientInstance, ProcedureCallDefaults, ProcedureCallOptions, CreateClientConfig, RequestMeta, ErrorRegistry, ErrorFactory, ErrorResponseMeta, } from './types.js';
|
|
17
|
+
export { dispatchTypedError } from './error-dispatch.js';
|
|
17
18
|
export { ClientRequestError, ClientPathParamError, ClientStreamError } from './errors.js';
|
|
18
19
|
export { createTypedStream } from './stream.js';
|
|
19
20
|
export { executeCall } from './call.js';
|
package/build/client/index.js
CHANGED
|
@@ -15,12 +15,13 @@ import { executeStream } from './stream.js';
|
|
|
15
15
|
* - The outer `.result` is wired up to the inner stream's `.result`.
|
|
16
16
|
*/
|
|
17
17
|
export function createClient(config) {
|
|
18
|
-
const { adapter, basePath, hooks: globalHooks = {}, defaults: globalDefaults = {}, scopes, } = config;
|
|
18
|
+
const { adapter, basePath, hooks: globalHooks = {}, defaults: globalDefaults = {}, errorRegistry, scopes, } = config;
|
|
19
19
|
const instance = {
|
|
20
20
|
basePath,
|
|
21
21
|
adapter,
|
|
22
22
|
hooks: globalHooks,
|
|
23
23
|
defaults: globalDefaults,
|
|
24
|
+
errorRegistry,
|
|
24
25
|
call(descriptor, options) {
|
|
25
26
|
return executeCall({
|
|
26
27
|
descriptor,
|
|
@@ -29,6 +30,7 @@ export function createClient(config) {
|
|
|
29
30
|
hooks: globalHooks,
|
|
30
31
|
defaults: globalDefaults,
|
|
31
32
|
options,
|
|
33
|
+
errorRegistry,
|
|
32
34
|
});
|
|
33
35
|
},
|
|
34
36
|
stream(descriptor, options) {
|
|
@@ -51,6 +53,7 @@ export function createClient(config) {
|
|
|
51
53
|
hooks: globalHooks,
|
|
52
54
|
defaults: globalDefaults,
|
|
53
55
|
options,
|
|
56
|
+
errorRegistry,
|
|
54
57
|
});
|
|
55
58
|
}
|
|
56
59
|
catch (err) {
|
|
@@ -74,6 +77,7 @@ export function createClient(config) {
|
|
|
74
77
|
};
|
|
75
78
|
return scopes(instance);
|
|
76
79
|
}
|
|
80
|
+
export { dispatchTypedError } from './error-dispatch.js';
|
|
77
81
|
export { ClientRequestError, ClientPathParamError, ClientStreamError } from './errors.js';
|
|
78
82
|
export { createTypedStream } from './stream.js';
|
|
79
83
|
export { executeCall } from './call.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AACvC,OAAO,EAAE,aAAa,EAAqB,MAAM,aAAa,CAAA;AAU9D,6DAA6D;AAE7D;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,YAAY,CAAU,MAAmC;IACvE,MAAM,EACJ,OAAO,EACP,QAAQ,EACR,KAAK,EAAE,WAAW,GAAG,EAAE,EACvB,QAAQ,EAAE,cAAc,GAAG,EAAE,EAC7B,MAAM,GACP,GAAG,MAAM,CAAA;IAEV,MAAM,QAAQ,GAAmB;QAC/B,QAAQ;QACR,OAAO;QACP,KAAK,EAAE,WAAW;QAClB,QAAQ,EAAE,cAAc;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AACvC,OAAO,EAAE,aAAa,EAAqB,MAAM,aAAa,CAAA;AAU9D,6DAA6D;AAE7D;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,YAAY,CAAU,MAAmC;IACvE,MAAM,EACJ,OAAO,EACP,QAAQ,EACR,KAAK,EAAE,WAAW,GAAG,EAAE,EACvB,QAAQ,EAAE,cAAc,GAAG,EAAE,EAC7B,aAAa,EACb,MAAM,GACP,GAAG,MAAM,CAAA;IAEV,MAAM,QAAQ,GAAmB;QAC/B,QAAQ;QACR,OAAO;QACP,KAAK,EAAE,WAAW;QAClB,QAAQ,EAAE,cAAc;QACxB,aAAa;QAEb,IAAI,CACF,UAA0B,EAC1B,OAA8B;YAE9B,OAAO,WAAW,CAAY;gBAC5B,UAAU;gBACV,QAAQ;gBACR,OAAO;gBACP,KAAK,EAAE,WAAW;gBAClB,QAAQ,EAAE,cAAc;gBACxB,OAAO;gBACP,aAAa;aACd,CAAC,CAAA;QACJ,CAAC;QAED,MAAM,CACJ,UAA4B,EAC5B,OAA8B;YAE9B,2DAA2D;YAC3D,yEAAyE;YAEzE,IAAI,aAAuC,CAAA;YAC3C,IAAI,YAAuC,CAAA;YAE3C,MAAM,aAAa,GAAG,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBAC7D,aAAa,GAAG,OAAO,CAAA;gBACvB,YAAY,GAAG,MAAM,CAAA;YACvB,CAAC,CAAC,CAAA;YAEF,oEAAoE;YACpE,KAAK,SAAS,CAAC,CAAC,iBAAiB;gBAC/B,IAAI,WAAyC,CAAA;gBAC7C,IAAI,CAAC;oBACH,WAAW,GAAG,MAAM,aAAa,CAAkB;wBACjD,UAAU;wBACV,QAAQ;wBACR,OAAO;wBACP,KAAK,EAAE,WAAW;wBAClB,QAAQ,EAAE,cAAc;wBACxB,OAAO;wBACP,aAAa;qBACd,CAAC,CAAA;gBACJ,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,YAAY,CAAC,GAAG,CAAC,CAAA;oBACjB,MAAM,GAAG,CAAA;gBACX,CAAC;gBAED,wCAAwC;gBACxC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,YAAY,CAAC,CAAA;gBAEpD,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;oBACrC,MAAM,IAAI,CAAA;gBACZ,CAAC;YACH,CAAC;YAED,MAAM,QAAQ,GAAG,iBAAiB,EAAE,CAAA;YAEpC,OAAO;gBACL,CAAC,MAAM,CAAC,aAAa,CAAC;oBACpB,OAAO,QAAQ,CAAA;gBACjB,CAAC;gBACD,MAAM,EAAE,aAAa;aACtB,CAAA;QACH,CAAC;KACF,CAAA;IAED,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAA;AACzB,CAAC;AA0BD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAA;AAExD,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAEzF,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA"}
|
package/build/client/stream.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ClientAdapter, ClientHooks, StreamDescriptor, TypedStream, ProcedureCallDefaults, ProcedureCallOptions } from './types.js';
|
|
1
|
+
import type { ClientAdapter, ClientHooks, ErrorRegistry, StreamDescriptor, TypedStream, ProcedureCallDefaults, ProcedureCallOptions } from './types.js';
|
|
2
2
|
/**
|
|
3
3
|
* Wraps an AsyncIterable into a TypedStream.
|
|
4
4
|
*
|
|
@@ -19,6 +19,7 @@ export interface ExecuteStreamConfig {
|
|
|
19
19
|
hooks: ClientHooks;
|
|
20
20
|
defaults?: ProcedureCallDefaults;
|
|
21
21
|
options?: ProcedureCallOptions;
|
|
22
|
+
errorRegistry?: ErrorRegistry;
|
|
22
23
|
}
|
|
23
24
|
/**
|
|
24
25
|
* Executes a streaming procedure call through the adapter.
|
package/build/client/stream.js
CHANGED
|
@@ -2,6 +2,7 @@ import { buildAdapterRequest } from './request-builder.js';
|
|
|
2
2
|
import { runBeforeRequest, runAfterResponse, runOnError } from './hooks.js';
|
|
3
3
|
import { applyRequestOptions, resolveBasePath } from './resolve-options.js';
|
|
4
4
|
import { ClientRequestError } from './errors.js';
|
|
5
|
+
import { dispatchTypedError } from './error-dispatch.js';
|
|
5
6
|
// ── createTypedStream ─────────────────────────────────────
|
|
6
7
|
/**
|
|
7
8
|
* Wraps an AsyncIterable into a TypedStream.
|
|
@@ -80,7 +81,7 @@ export function createTypedStream(source, streamMode) {
|
|
|
80
81
|
* 8. Return createTypedStream(streamResponse.body, descriptor.streamMode)
|
|
81
82
|
*/
|
|
82
83
|
export async function executeStream(config) {
|
|
83
|
-
const { descriptor, basePath, adapter, hooks, defaults, options } = config;
|
|
84
|
+
const { descriptor, basePath, adapter, hooks, defaults, options, errorRegistry } = config;
|
|
84
85
|
// 1. Build the initial request
|
|
85
86
|
const resolvedBasePath = resolveBasePath(defaults, options, basePath);
|
|
86
87
|
let request = buildAdapterRequest(descriptor, resolvedBasePath);
|
|
@@ -99,16 +100,25 @@ export async function executeStream(config) {
|
|
|
99
100
|
await runOnError({ procedureName: descriptor.name, scope: descriptor.scope, request, error: err }, hooks, options);
|
|
100
101
|
throw err;
|
|
101
102
|
}
|
|
102
|
-
// Build an AdapterResponse shape for the hooks
|
|
103
|
+
// Build an AdapterResponse shape for the hooks. For success the body is null
|
|
104
|
+
// (the actual data flows through the async iterable); for non-2xx the adapter
|
|
105
|
+
// eagerly parses the JSON response body and surfaces it via `errorBody`.
|
|
103
106
|
const responseForHooks = {
|
|
104
107
|
status: streamResponse.status,
|
|
105
108
|
headers: streamResponse.headers,
|
|
106
|
-
body: null,
|
|
109
|
+
body: streamResponse.errorBody ?? null,
|
|
107
110
|
};
|
|
108
111
|
// 6. Run after-response hooks immediately (before iteration)
|
|
109
112
|
await runAfterResponse({ procedureName: descriptor.name, scope: descriptor.scope, request, response: responseForHooks }, hooks, options);
|
|
110
113
|
// 7. Check status after hooks (hooks may mutate responseForHooks.status)
|
|
111
114
|
if (responseForHooks.status < 200 || responseForHooks.status >= 300) {
|
|
115
|
+
const typed = dispatchTypedError(errorRegistry, responseForHooks.body, {
|
|
116
|
+
status: responseForHooks.status,
|
|
117
|
+
procedureName: descriptor.name,
|
|
118
|
+
scope: descriptor.scope,
|
|
119
|
+
});
|
|
120
|
+
if (typed)
|
|
121
|
+
throw typed;
|
|
112
122
|
throw new ClientRequestError({
|
|
113
123
|
status: responseForHooks.status,
|
|
114
124
|
headers: responseForHooks.headers,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream.js","sourceRoot":"","sources":["../../src/client/stream.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAC1D,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAC3E,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"stream.js","sourceRoot":"","sources":["../../src/client/stream.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|