ts-procedures 5.14.0 → 5.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent_config/claude-code/skills/ts-procedures/SKILL.md +1 -1
- package/agent_config/claude-code/skills/ts-procedures/api-reference.md +59 -4
- package/agent_config/claude-code/skills/ts-procedures/patterns.md +103 -3
- package/agent_config/claude-code/skills/ts-procedures-scaffold/templates/client.md +36 -5
- package/agent_config/copilot/copilot-instructions.md +56 -7
- package/agent_config/cursor/cursorrules +56 -7
- package/build/client/call.d.ts +18 -9
- package/build/client/call.js +25 -19
- package/build/client/call.js.map +1 -1
- package/build/client/call.test.js +167 -17
- package/build/client/call.test.js.map +1 -1
- package/build/client/index.d.ts +1 -1
- package/build/client/index.js +18 -3
- package/build/client/index.js.map +1 -1
- package/build/client/index.test.js +104 -0
- package/build/client/index.test.js.map +1 -1
- package/build/client/resolve-options.d.ts +45 -0
- package/build/client/resolve-options.js +82 -0
- package/build/client/resolve-options.js.map +1 -0
- package/build/client/resolve-options.test.js +158 -0
- package/build/client/resolve-options.test.js.map +1 -0
- package/build/client/stream.d.ts +18 -9
- package/build/client/stream.js +24 -19
- package/build/client/stream.js.map +1 -1
- package/build/client/stream.test.js +102 -46
- package/build/client/stream.test.js.map +1 -1
- package/build/client/types.d.ts +68 -1
- package/build/client/types.js +1 -1
- package/build/codegen/bin/cli.d.ts +2 -0
- package/build/codegen/bin/cli.js +11 -0
- package/build/codegen/bin/cli.js.map +1 -1
- package/build/codegen/bin/cli.test.js +30 -0
- package/build/codegen/bin/cli.test.js.map +1 -1
- package/build/codegen/e2e.test.js +141 -0
- package/build/codegen/e2e.test.js.map +1 -1
- package/build/codegen/emit-client-runtime.js +3 -0
- package/build/codegen/emit-client-runtime.js.map +1 -1
- package/build/codegen/index.d.ts +1 -0
- package/build/codegen/index.js +1 -0
- package/build/codegen/index.js.map +1 -1
- package/build/codegen/pipeline.d.ts +1 -0
- package/build/codegen/pipeline.js +8 -2
- package/build/codegen/pipeline.js.map +1 -1
- package/build/codegen/pipeline.test.js +34 -1
- package/build/codegen/pipeline.test.js.map +1 -1
- package/docs/client-and-codegen.md +125 -2
- package/package.json +1 -1
- package/src/client/call.test.ts +202 -29
- package/src/client/call.ts +41 -28
- package/src/client/index.test.ts +117 -0
- package/src/client/index.ts +25 -8
- package/src/client/resolve-options.test.ts +205 -0
- package/src/client/resolve-options.ts +113 -0
- package/src/client/stream.test.ts +132 -107
- package/src/client/stream.ts +40 -25
- package/src/client/types.ts +74 -2
- package/src/codegen/bin/cli.test.ts +35 -0
- package/src/codegen/bin/cli.ts +11 -0
- package/src/codegen/e2e.test.ts +151 -0
- package/src/codegen/emit-client-runtime.ts +3 -0
- package/src/codegen/index.ts +2 -0
- package/src/codegen/pipeline.test.ts +46 -1
- package/src/codegen/pipeline.ts +9 -2
- package/src/implementations/http/README.md +11 -1
- package/build/src/client/call.d.ts +0 -14
- package/build/src/client/call.js +0 -47
- package/build/src/client/call.js.map +0 -1
- package/build/src/client/call.test.js +0 -124
- package/build/src/client/call.test.js.map +0 -1
- package/build/src/client/errors.d.ts +0 -25
- package/build/src/client/errors.js +0 -33
- package/build/src/client/errors.js.map +0 -1
- package/build/src/client/errors.test.d.ts +0 -1
- package/build/src/client/errors.test.js +0 -41
- package/build/src/client/errors.test.js.map +0 -1
- package/build/src/client/fetch-adapter.d.ts +0 -12
- package/build/src/client/fetch-adapter.js +0 -156
- package/build/src/client/fetch-adapter.js.map +0 -1
- package/build/src/client/fetch-adapter.test.d.ts +0 -1
- package/build/src/client/fetch-adapter.test.js +0 -271
- package/build/src/client/fetch-adapter.test.js.map +0 -1
- package/build/src/client/hooks.d.ts +0 -17
- package/build/src/client/hooks.js +0 -40
- package/build/src/client/hooks.js.map +0 -1
- package/build/src/client/hooks.test.d.ts +0 -1
- package/build/src/client/hooks.test.js +0 -163
- package/build/src/client/hooks.test.js.map +0 -1
- package/build/src/client/index.d.ts +0 -22
- package/build/src/client/index.js +0 -67
- package/build/src/client/index.js.map +0 -1
- package/build/src/client/index.test.d.ts +0 -1
- package/build/src/client/index.test.js +0 -231
- package/build/src/client/index.test.js.map +0 -1
- package/build/src/client/request-builder.d.ts +0 -13
- package/build/src/client/request-builder.js +0 -53
- package/build/src/client/request-builder.js.map +0 -1
- package/build/src/client/request-builder.test.d.ts +0 -1
- package/build/src/client/request-builder.test.js +0 -160
- package/build/src/client/request-builder.test.js.map +0 -1
- package/build/src/client/stream.d.ts +0 -27
- package/build/src/client/stream.js +0 -118
- package/build/src/client/stream.js.map +0 -1
- package/build/src/client/stream.test.d.ts +0 -1
- package/build/src/client/stream.test.js +0 -228
- package/build/src/client/stream.test.js.map +0 -1
- package/build/src/client/types.d.ts +0 -78
- package/build/src/client/types.js +0 -3
- package/build/src/client/types.js.map +0 -1
- package/build/src/codegen/bin/cli.d.ts +0 -45
- package/build/src/codegen/bin/cli.js +0 -246
- package/build/src/codegen/bin/cli.js.map +0 -1
- package/build/src/codegen/bin/cli.test.d.ts +0 -1
- package/build/src/codegen/bin/cli.test.js +0 -220
- package/build/src/codegen/bin/cli.test.js.map +0 -1
- package/build/src/codegen/constants.d.ts +0 -1
- package/build/src/codegen/constants.js +0 -2
- package/build/src/codegen/constants.js.map +0 -1
- package/build/src/codegen/e2e.test.d.ts +0 -1
- package/build/src/codegen/e2e.test.js +0 -464
- package/build/src/codegen/e2e.test.js.map +0 -1
- package/build/src/codegen/emit-client-runtime.d.ts +0 -9
- package/build/src/codegen/emit-client-runtime.js +0 -99
- package/build/src/codegen/emit-client-runtime.js.map +0 -1
- package/build/src/codegen/emit-client-runtime.test.d.ts +0 -1
- package/build/src/codegen/emit-client-runtime.test.js +0 -78
- package/build/src/codegen/emit-client-runtime.test.js.map +0 -1
- package/build/src/codegen/emit-client-types.d.ts +0 -8
- package/build/src/codegen/emit-client-types.js +0 -25
- package/build/src/codegen/emit-client-types.js.map +0 -1
- package/build/src/codegen/emit-client-types.test.d.ts +0 -1
- package/build/src/codegen/emit-client-types.test.js +0 -33
- package/build/src/codegen/emit-client-types.test.js.map +0 -1
- package/build/src/codegen/emit-errors.d.ts +0 -19
- package/build/src/codegen/emit-errors.js +0 -59
- package/build/src/codegen/emit-errors.js.map +0 -1
- package/build/src/codegen/emit-errors.test.d.ts +0 -1
- package/build/src/codegen/emit-errors.test.js +0 -175
- package/build/src/codegen/emit-errors.test.js.map +0 -1
- package/build/src/codegen/emit-index.d.ts +0 -12
- package/build/src/codegen/emit-index.js +0 -41
- package/build/src/codegen/emit-index.js.map +0 -1
- package/build/src/codegen/emit-index.test.d.ts +0 -1
- package/build/src/codegen/emit-index.test.js +0 -106
- package/build/src/codegen/emit-index.test.js.map +0 -1
- package/build/src/codegen/emit-scope.d.ts +0 -15
- package/build/src/codegen/emit-scope.js +0 -299
- package/build/src/codegen/emit-scope.js.map +0 -1
- package/build/src/codegen/emit-scope.test.d.ts +0 -1
- package/build/src/codegen/emit-scope.test.js +0 -559
- package/build/src/codegen/emit-scope.test.js.map +0 -1
- package/build/src/codegen/emit-types.d.ts +0 -43
- package/build/src/codegen/emit-types.js +0 -111
- package/build/src/codegen/emit-types.js.map +0 -1
- package/build/src/codegen/emit-types.test.d.ts +0 -1
- package/build/src/codegen/emit-types.test.js +0 -184
- package/build/src/codegen/emit-types.test.js.map +0 -1
- package/build/src/codegen/group-routes.d.ts +0 -23
- package/build/src/codegen/group-routes.js +0 -46
- package/build/src/codegen/group-routes.js.map +0 -1
- package/build/src/codegen/group-routes.test.d.ts +0 -1
- package/build/src/codegen/group-routes.test.js +0 -131
- package/build/src/codegen/group-routes.test.js.map +0 -1
- package/build/src/codegen/index.d.ts +0 -15
- package/build/src/codegen/index.js +0 -16
- package/build/src/codegen/index.js.map +0 -1
- package/build/src/codegen/naming.d.ts +0 -7
- package/build/src/codegen/naming.js +0 -21
- package/build/src/codegen/naming.js.map +0 -1
- package/build/src/codegen/naming.test.d.ts +0 -1
- package/build/src/codegen/naming.test.js +0 -40
- package/build/src/codegen/naming.test.js.map +0 -1
- package/build/src/codegen/pipeline.d.ts +0 -17
- package/build/src/codegen/pipeline.js +0 -78
- package/build/src/codegen/pipeline.js.map +0 -1
- package/build/src/codegen/pipeline.test.d.ts +0 -1
- package/build/src/codegen/pipeline.test.js +0 -269
- package/build/src/codegen/pipeline.test.js.map +0 -1
- package/build/src/codegen/resolve-envelope.d.ts +0 -7
- package/build/src/codegen/resolve-envelope.js +0 -46
- package/build/src/codegen/resolve-envelope.js.map +0 -1
- package/build/src/codegen/resolve-envelope.test.d.ts +0 -1
- package/build/src/codegen/resolve-envelope.test.js +0 -69
- package/build/src/codegen/resolve-envelope.test.js.map +0 -1
- package/build/src/errors.d.ts +0 -33
- package/build/src/errors.js +0 -91
- package/build/src/errors.js.map +0 -1
- package/build/src/errors.test.d.ts +0 -1
- package/build/src/errors.test.js +0 -122
- package/build/src/errors.test.js.map +0 -1
- package/build/src/exports.d.ts +0 -7
- package/build/src/exports.js +0 -8
- package/build/src/exports.js.map +0 -1
- package/build/src/implementations/http/doc-registry.d.ts +0 -12
- package/build/src/implementations/http/doc-registry.js +0 -114
- package/build/src/implementations/http/doc-registry.js.map +0 -1
- package/build/src/implementations/http/doc-registry.test.d.ts +0 -1
- package/build/src/implementations/http/doc-registry.test.js +0 -347
- package/build/src/implementations/http/doc-registry.test.js.map +0 -1
- package/build/src/implementations/http/express-rpc/index.d.ts +0 -94
- package/build/src/implementations/http/express-rpc/index.js +0 -185
- package/build/src/implementations/http/express-rpc/index.js.map +0 -1
- package/build/src/implementations/http/express-rpc/index.test.d.ts +0 -1
- package/build/src/implementations/http/express-rpc/index.test.js +0 -684
- package/build/src/implementations/http/express-rpc/index.test.js.map +0 -1
- package/build/src/implementations/http/express-rpc/types.d.ts +0 -11
- package/build/src/implementations/http/express-rpc/types.js +0 -2
- package/build/src/implementations/http/express-rpc/types.js.map +0 -1
- package/build/src/implementations/http/hono-api/index.d.ts +0 -102
- package/build/src/implementations/http/hono-api/index.js +0 -341
- package/build/src/implementations/http/hono-api/index.js.map +0 -1
- package/build/src/implementations/http/hono-api/index.test.d.ts +0 -1
- package/build/src/implementations/http/hono-api/index.test.js +0 -992
- package/build/src/implementations/http/hono-api/index.test.js.map +0 -1
- package/build/src/implementations/http/hono-api/types.d.ts +0 -13
- package/build/src/implementations/http/hono-api/types.js +0 -2
- package/build/src/implementations/http/hono-api/types.js.map +0 -1
- package/build/src/implementations/http/hono-rpc/index.d.ts +0 -92
- package/build/src/implementations/http/hono-rpc/index.js +0 -161
- package/build/src/implementations/http/hono-rpc/index.js.map +0 -1
- package/build/src/implementations/http/hono-rpc/index.test.d.ts +0 -1
- package/build/src/implementations/http/hono-rpc/index.test.js +0 -803
- package/build/src/implementations/http/hono-rpc/index.test.js.map +0 -1
- package/build/src/implementations/http/hono-rpc/types.d.ts +0 -11
- package/build/src/implementations/http/hono-rpc/types.js +0 -2
- package/build/src/implementations/http/hono-rpc/types.js.map +0 -1
- package/build/src/implementations/http/hono-stream/index.d.ts +0 -120
- package/build/src/implementations/http/hono-stream/index.js +0 -309
- package/build/src/implementations/http/hono-stream/index.js.map +0 -1
- package/build/src/implementations/http/hono-stream/index.test.d.ts +0 -1
- package/build/src/implementations/http/hono-stream/index.test.js +0 -1356
- package/build/src/implementations/http/hono-stream/index.test.js.map +0 -1
- package/build/src/implementations/http/hono-stream/types.d.ts +0 -15
- package/build/src/implementations/http/hono-stream/types.js +0 -2
- package/build/src/implementations/http/hono-stream/types.js.map +0 -1
- package/build/src/implementations/types.d.ts +0 -142
- package/build/src/implementations/types.js +0 -2
- package/build/src/implementations/types.js.map +0 -1
- package/build/src/index.d.ts +0 -165
- package/build/src/index.js +0 -253
- package/build/src/index.js.map +0 -1
- package/build/src/index.test.d.ts +0 -1
- package/build/src/index.test.js +0 -890
- package/build/src/index.test.js.map +0 -1
- package/build/src/schema/compute-schema.d.ts +0 -35
- package/build/src/schema/compute-schema.js +0 -41
- package/build/src/schema/compute-schema.js.map +0 -1
- package/build/src/schema/compute-schema.test.d.ts +0 -1
- package/build/src/schema/compute-schema.test.js +0 -107
- package/build/src/schema/compute-schema.test.js.map +0 -1
- package/build/src/schema/extract-json-schema.d.ts +0 -2
- package/build/src/schema/extract-json-schema.js +0 -12
- package/build/src/schema/extract-json-schema.js.map +0 -1
- package/build/src/schema/extract-json-schema.test.d.ts +0 -1
- package/build/src/schema/extract-json-schema.test.js +0 -23
- package/build/src/schema/extract-json-schema.test.js.map +0 -1
- package/build/src/schema/parser.d.ts +0 -28
- package/build/src/schema/parser.js +0 -170
- package/build/src/schema/parser.js.map +0 -1
- package/build/src/schema/parser.test.d.ts +0 -1
- package/build/src/schema/parser.test.js +0 -120
- package/build/src/schema/parser.test.js.map +0 -1
- package/build/src/schema/resolve-schema-lib.d.ts +0 -12
- package/build/src/schema/resolve-schema-lib.js +0 -11
- package/build/src/schema/resolve-schema-lib.js.map +0 -1
- package/build/src/schema/resolve-schema-lib.test.d.ts +0 -1
- package/build/src/schema/resolve-schema-lib.test.js +0 -17
- package/build/src/schema/resolve-schema-lib.test.js.map +0 -1
- package/build/src/schema/types.d.ts +0 -8
- package/build/src/schema/types.js +0 -2
- package/build/src/schema/types.js.map +0 -1
- package/build/src/stack-utils.d.ts +0 -25
- package/build/src/stack-utils.js +0 -95
- package/build/src/stack-utils.js.map +0 -1
- package/build/src/stack-utils.test.d.ts +0 -1
- package/build/src/stack-utils.test.js +0 -80
- package/build/src/stack-utils.test.js.map +0 -1
- /package/build/{src/client/call.test.d.ts → client/resolve-options.test.d.ts} +0 -0
|
@@ -151,7 +151,7 @@ The npm package ships user-facing documentation with narrative explanations and
|
|
|
151
151
|
| `docs/core.md` | Procedures factory, Create, CreateStream, schema.input, error handling |
|
|
152
152
|
| `docs/streaming.md` | Streaming procedures, AbortSignal, SSE patterns |
|
|
153
153
|
| `docs/http-integrations.md` | Express RPC, Hono RPC/Stream/API builders, DocRegistry |
|
|
154
|
-
| `docs/client-and-codegen.md` | Client code generation, createClient, CLI options |
|
|
154
|
+
| `docs/client-and-codegen.md` | Client code generation, createClient, per-call options (timeout/signal/headers/basePath/meta), client-level defaults, typed RequestMeta augmentation, CLI options |
|
|
155
155
|
|
|
156
156
|
## Workflow
|
|
157
157
|
|
|
@@ -732,6 +732,7 @@ function createClient<TScopes>(config: {
|
|
|
732
732
|
basePath: string
|
|
733
733
|
scopes: (client: ClientInstance) => TScopes
|
|
734
734
|
hooks?: ClientHooks
|
|
735
|
+
defaults?: ProcedureCallDefaults
|
|
735
736
|
}): TScopes
|
|
736
737
|
```
|
|
737
738
|
|
|
@@ -740,7 +741,8 @@ function createClient<TScopes>(config: {
|
|
|
740
741
|
- `config.adapter` — Transport adapter implementing `ClientAdapter`. Use `createFetchAdapter()` for fetch-based transport.
|
|
741
742
|
- `config.basePath` — Base URL prepended to all request paths (e.g., `'http://localhost:3000'`).
|
|
742
743
|
- `config.scopes` — Factory function that receives a raw `ClientInstance` and returns the typed scope object. The generated `create${ServiceName}Bindings` export (defaults to `createApiBindings`; pass `--service-name <Name>` to rename).
|
|
743
|
-
- `config.hooks` — Optional global hooks applied to every call.
|
|
744
|
+
- `config.hooks` — Optional global hooks applied to every call. Per-call hooks (passed via the options bag) run *after* global hooks — they stack, not replace.
|
|
745
|
+
- `config.defaults` — Optional default request options (timeout, signal, headers, basePath) applied to every call. Overridden by per-call options.
|
|
744
746
|
|
|
745
747
|
### Return Value
|
|
746
748
|
|
|
@@ -750,11 +752,51 @@ Returns the result of `config.scopes(clientInstance)` — a typed object where e
|
|
|
750
752
|
|
|
751
753
|
```typescript
|
|
752
754
|
interface ClientHooks {
|
|
753
|
-
onBeforeRequest?: (ctx:
|
|
754
|
-
onAfterResponse?: (ctx:
|
|
755
|
+
onBeforeRequest?: (ctx: BeforeRequestContext) => BeforeRequestContext | Promise<BeforeRequestContext>
|
|
756
|
+
onAfterResponse?: (ctx: AfterResponseContext) => void | Promise<void>
|
|
757
|
+
onError?: (ctx: ErrorContext) => void | Promise<void>
|
|
755
758
|
}
|
|
756
759
|
```
|
|
757
760
|
|
|
761
|
+
### ProcedureCallDefaults / ProcedureCallOptions
|
|
762
|
+
|
|
763
|
+
`ProcedureCallDefaults` is the shape used at `config.defaults` and is a strict subset of `ProcedureCallOptions` (per-call options). `ProcedureCallOptions` additionally includes the `ClientHooks` fields so a single options bag covers both request config and hooks.
|
|
764
|
+
|
|
765
|
+
```typescript
|
|
766
|
+
interface ProcedureCallDefaults {
|
|
767
|
+
signal?: AbortSignal // cancel signal (combined with per-call via AbortSignal.any)
|
|
768
|
+
timeout?: number // ms — per-call timeout:0 disables an inherited default
|
|
769
|
+
headers?: Record<string, string> // merged (per-call keys win)
|
|
770
|
+
basePath?: string // per-call > default > config.basePath
|
|
771
|
+
meta?: RequestMeta // typed per-request metadata (see RequestMeta below)
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
interface ProcedureCallOptions extends ProcedureCallDefaults, ClientHooks {}
|
|
775
|
+
```
|
|
776
|
+
|
|
777
|
+
### RequestMeta (typed per-request metadata)
|
|
778
|
+
|
|
779
|
+
`RequestMeta` is an empty interface designed for TypeScript declaration merging. Augment it in your project to type the `meta` field end-to-end (per-call options, hook contexts, and the adapter).
|
|
780
|
+
|
|
781
|
+
```typescript
|
|
782
|
+
// Self-contained (code-generated) client
|
|
783
|
+
declare module './generated/_types' {
|
|
784
|
+
interface RequestMeta {
|
|
785
|
+
traceId: string
|
|
786
|
+
priority?: 'high' | 'low'
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
// Or when using ts-procedures/client directly
|
|
791
|
+
declare module 'ts-procedures/client' {
|
|
792
|
+
interface RequestMeta {
|
|
793
|
+
traceId: string
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
```
|
|
797
|
+
|
|
798
|
+
After augmentation, `request.meta` is typed in adapters, hooks, defaults, and per-call options. If `RequestMeta` declares required fields, supply them via `defaults.meta` or per-call `options.meta` — the merged shape must satisfy them at runtime.
|
|
799
|
+
|
|
758
800
|
### Example
|
|
759
801
|
|
|
760
802
|
```typescript
|
|
@@ -765,6 +807,7 @@ const client = createClient({
|
|
|
765
807
|
adapter: createFetchAdapter(),
|
|
766
808
|
basePath: 'http://localhost:3000',
|
|
767
809
|
scopes: createApiBindings,
|
|
810
|
+
defaults: { timeout: 30_000, headers: { 'X-Client-Version': '1.0.0' } },
|
|
768
811
|
hooks: {
|
|
769
812
|
onBeforeRequest(ctx) {
|
|
770
813
|
ctx.request.headers = { ...ctx.request.headers, Authorization: `Bearer ${getToken()}` }
|
|
@@ -773,7 +816,17 @@ const client = createClient({
|
|
|
773
816
|
},
|
|
774
817
|
})
|
|
775
818
|
|
|
776
|
-
|
|
819
|
+
// Per-call timeout + signal + hooks — all in one options bag
|
|
820
|
+
const controller = new AbortController()
|
|
821
|
+
const user = await client.users.GetUser(
|
|
822
|
+
{ pathParams: { id: '123' } },
|
|
823
|
+
{
|
|
824
|
+
timeout: 5000,
|
|
825
|
+
signal: controller.signal,
|
|
826
|
+
headers: { 'X-Request-Id': crypto.randomUUID() },
|
|
827
|
+
onAfterResponse(ctx) { log(ctx) },
|
|
828
|
+
},
|
|
829
|
+
)
|
|
777
830
|
|
|
778
831
|
// Reach types via the namespace: Api.Users.GetUser.Params, Api.Errors.ProcedureError
|
|
779
832
|
```
|
|
@@ -832,6 +885,7 @@ async function generateClient(options: {
|
|
|
832
885
|
namespaceTypes?: boolean
|
|
833
886
|
selfContained?: boolean
|
|
834
887
|
serviceName?: string
|
|
888
|
+
cleanOutDir?: boolean
|
|
835
889
|
}): Promise<GeneratedFile[]>
|
|
836
890
|
```
|
|
837
891
|
|
|
@@ -858,6 +912,7 @@ async function generateClient(options: {
|
|
|
858
912
|
| `--array-item-naming <value>` | Postfix for array item type names (ignored with `--no-namespace-types`) |
|
|
859
913
|
| `--uncountable-words <list>` | Comma-separated words to skip singularization (ignored with `--no-namespace-types`) |
|
|
860
914
|
| `--service-name <name>` | Names the service namespace and binding factory (e.g., `Auth` → `export namespace Auth { ... }` + `createAuthBindings`). Also prefixes `${Name}Errors` and `${Name}ProcedureErrorUnion` in `_errors.ts`. **Default: `Api`.** |
|
|
915
|
+
| `--clean-out-dir` / `--no-clean-out-dir` | Recursively remove `--out <dir>` before writing so stale scope files (e.g. from removed scopes) are pruned. Skipped under `--dry-run`. **Default: off.** |
|
|
861
916
|
|
|
862
917
|
### Generated Output
|
|
863
918
|
|
|
@@ -782,6 +782,7 @@ app.get('/docs', (c) => c.json(docs.toJSON()))
|
|
|
782
782
|
// npx ts-procedures-codegen --url http://localhost:3000/docs --out ./src/generated/api
|
|
783
783
|
// Defaults: --self-contained --namespace-types --jsdoc
|
|
784
784
|
// Optional: --service-name Auth --depluralize --enum-style union
|
|
785
|
+
// --clean-out-dir // wipe --out before writing (prunes stale scope files)
|
|
785
786
|
// Opt-out: --no-self-contained --no-namespace-types --no-jsdoc
|
|
786
787
|
```
|
|
787
788
|
|
|
@@ -840,10 +841,11 @@ const result = await stream.result // Typed as WatchNotificationsReturn
|
|
|
840
841
|
|
|
841
842
|
---
|
|
842
843
|
|
|
843
|
-
## Per-Procedure
|
|
844
|
+
## Per-Procedure Hooks
|
|
845
|
+
|
|
846
|
+
Per-call hooks run *after* global hooks (they don't replace them). They live in the same options bag as `timeout`, `signal`, `headers`, etc.
|
|
844
847
|
|
|
845
848
|
```typescript
|
|
846
|
-
// Override hooks for a specific call
|
|
847
849
|
await client.users.GetUser({ pathParams: { id: '123' } }, {
|
|
848
850
|
onAfterResponse(ctx) {
|
|
849
851
|
const rateLimit = ctx.response.headers['x-rate-limit-remaining']
|
|
@@ -854,6 +856,102 @@ await client.users.GetUser({ pathParams: { id: '123' } }, {
|
|
|
854
856
|
|
|
855
857
|
---
|
|
856
858
|
|
|
859
|
+
## Per-Call Request Options (timeout, signal, headers, basePath)
|
|
860
|
+
|
|
861
|
+
Every generated callable takes an optional second argument for per-call config. The options bag covers both request-level config and hooks.
|
|
862
|
+
|
|
863
|
+
```typescript
|
|
864
|
+
// Timeout — aborts the request after 5 seconds
|
|
865
|
+
const user = await client.users.GetUser({ pathParams: { id: '123' } }, { timeout: 5000 })
|
|
866
|
+
|
|
867
|
+
// Cancellation — supply your own AbortSignal
|
|
868
|
+
const controller = new AbortController()
|
|
869
|
+
const user = await client.users.GetUser(
|
|
870
|
+
{ pathParams: { id: '123' } },
|
|
871
|
+
{ signal: controller.signal },
|
|
872
|
+
)
|
|
873
|
+
|
|
874
|
+
// Extra per-call headers
|
|
875
|
+
await client.users.GetUser(
|
|
876
|
+
{ pathParams: { id: '123' } },
|
|
877
|
+
{ headers: { 'X-Request-Id': crypto.randomUUID() } },
|
|
878
|
+
)
|
|
879
|
+
|
|
880
|
+
// Override base path for a single call (multi-region, dev/prod switching)
|
|
881
|
+
await client.users.GetUser(
|
|
882
|
+
{ pathParams: { id: '123' } },
|
|
883
|
+
{ basePath: 'https://api-eu.example.com' },
|
|
884
|
+
)
|
|
885
|
+
```
|
|
886
|
+
|
|
887
|
+
---
|
|
888
|
+
|
|
889
|
+
## Client-Level Defaults
|
|
890
|
+
|
|
891
|
+
Set defaults via `config.defaults` — applied to every call, overridden by per-call options. Headers merge (per-call keys win); `signal` combines via `AbortSignal.any` (whichever aborts first wins); per-call `timeout: 0` disables an inherited default timeout.
|
|
892
|
+
|
|
893
|
+
```typescript
|
|
894
|
+
const client = createClient({
|
|
895
|
+
adapter: createFetchAdapter(),
|
|
896
|
+
basePath: 'http://localhost:3000',
|
|
897
|
+
scopes: createApiBindings,
|
|
898
|
+
defaults: {
|
|
899
|
+
timeout: 30_000,
|
|
900
|
+
headers: { 'X-Client-Version': '1.0.0' },
|
|
901
|
+
},
|
|
902
|
+
})
|
|
903
|
+
```
|
|
904
|
+
|
|
905
|
+
---
|
|
906
|
+
|
|
907
|
+
## Typed Per-Request Meta (RequestMeta Augmentation)
|
|
908
|
+
|
|
909
|
+
`AdapterRequest.meta` is typed via the `RequestMeta` interface — declared empty so developers augment it via TypeScript declaration merging. Augmented fields are then typed end-to-end: per-call options, hook contexts, and adapter.
|
|
910
|
+
|
|
911
|
+
```typescript
|
|
912
|
+
// Self-contained (code-generated) client
|
|
913
|
+
declare module './generated/_types' {
|
|
914
|
+
interface RequestMeta {
|
|
915
|
+
traceId: string
|
|
916
|
+
priority?: 'high' | 'low'
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
// Or, when using ts-procedures/client directly
|
|
921
|
+
declare module 'ts-procedures/client' {
|
|
922
|
+
interface RequestMeta {
|
|
923
|
+
traceId: string
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
// After augmentation, meta is typed everywhere:
|
|
928
|
+
await client.users.GetUser(
|
|
929
|
+
{ pathParams: { id: '123' } },
|
|
930
|
+
{ meta: { traceId: 'req-abc', priority: 'high' } }, // typed
|
|
931
|
+
)
|
|
932
|
+
|
|
933
|
+
// Typed in hooks
|
|
934
|
+
hooks: {
|
|
935
|
+
onBeforeRequest(ctx) {
|
|
936
|
+
const trace = ctx.request.meta?.traceId // string | undefined
|
|
937
|
+
return ctx
|
|
938
|
+
},
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
// Typed in adapters
|
|
942
|
+
const adapter: ClientAdapter = {
|
|
943
|
+
async request(req) {
|
|
944
|
+
const priority = req.meta?.priority // 'high' | 'low' | undefined
|
|
945
|
+
return { status: 200, headers: {}, body: {} }
|
|
946
|
+
},
|
|
947
|
+
async stream(req) { /* ... */ },
|
|
948
|
+
}
|
|
949
|
+
```
|
|
950
|
+
|
|
951
|
+
If `RequestMeta` declares required fields, supply them in `defaults.meta` or per-call `options.meta` — the merged shape must contain them at runtime.
|
|
952
|
+
|
|
953
|
+
---
|
|
954
|
+
|
|
857
955
|
## Custom Client Adapter (Axios)
|
|
858
956
|
|
|
859
957
|
```typescript
|
|
@@ -861,7 +959,9 @@ import type { ClientAdapter } from 'ts-procedures/client'
|
|
|
861
959
|
import axios from 'axios'
|
|
862
960
|
|
|
863
961
|
const axiosAdapter: ClientAdapter = {
|
|
864
|
-
async request({ url, method, headers, body, signal }) {
|
|
962
|
+
async request({ url, method, headers, body, signal, meta }) {
|
|
963
|
+
// meta is typed via RequestMeta augmentation — use it for tracing,
|
|
964
|
+
// priority routing, custom auth, etc.
|
|
865
965
|
const res = await axios({ url, method, headers, data: body, signal })
|
|
866
966
|
return {
|
|
867
967
|
status: res.status,
|
|
@@ -7,12 +7,28 @@ import { createClient, createFetchAdapter } from 'ts-procedures/client'
|
|
|
7
7
|
import { createApiBindings, Api } from './generated/api'
|
|
8
8
|
// With --service-name {{Name}}: import { create{{Name}}Bindings, {{Name}} } from './generated/api'
|
|
9
9
|
|
|
10
|
+
// --- Optional: type per-request meta end-to-end via declaration merging ---
|
|
11
|
+
// Self-contained clients augment './generated/_types' instead:
|
|
12
|
+
// declare module './generated/_types' { interface RequestMeta { traceId: string } }
|
|
13
|
+
declare module 'ts-procedures/client' {
|
|
14
|
+
interface RequestMeta {
|
|
15
|
+
// TODO: add your fields — typed in options.meta, ctx.request.meta, adapter req.meta
|
|
16
|
+
// traceId?: string
|
|
17
|
+
// priority?: 'high' | 'low'
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
10
21
|
// Create the typed client
|
|
11
22
|
export const {{name}}Client = createClient({
|
|
12
23
|
adapter: createFetchAdapter(),
|
|
13
24
|
basePath: 'http://localhost:3000', // TODO: configure base URL
|
|
14
25
|
scopes: createApiBindings,
|
|
15
26
|
// With --service-name {{Name}}: scopes: create{{Name}}Bindings,
|
|
27
|
+
defaults: {
|
|
28
|
+
// TODO: set client-wide defaults (overridden by per-call options)
|
|
29
|
+
// timeout: 30_000,
|
|
30
|
+
// headers: { 'X-Client-Version': '1.0.0' },
|
|
31
|
+
},
|
|
16
32
|
hooks: {
|
|
17
33
|
onBeforeRequest(ctx) {
|
|
18
34
|
// TODO: add auth headers, request IDs, etc.
|
|
@@ -42,12 +58,24 @@ export const {{name}}Client = createClient({
|
|
|
42
58
|
// }
|
|
43
59
|
// const result = await stream.result // Typed from server returnType schema
|
|
44
60
|
|
|
45
|
-
// --- Per-
|
|
46
|
-
// const user = await {{name}}Client.users.GetUser(
|
|
47
|
-
//
|
|
48
|
-
//
|
|
61
|
+
// --- Per-call options (timeout, signal, headers, basePath, meta, hooks) ---
|
|
62
|
+
// const user = await {{name}}Client.users.GetUser(
|
|
63
|
+
// { id: '123' },
|
|
64
|
+
// {
|
|
65
|
+
// timeout: 5000,
|
|
66
|
+
// headers: { 'X-Request-Id': crypto.randomUUID() },
|
|
67
|
+
// // meta is typed via RequestMeta augmentation above:
|
|
68
|
+
// // meta: { traceId: 'req-abc' },
|
|
69
|
+
// onAfterResponse(ctx) {
|
|
70
|
+
// console.log('Rate limit:', ctx.response.headers['x-rate-limit-remaining'])
|
|
71
|
+
// },
|
|
49
72
|
// },
|
|
50
|
-
//
|
|
73
|
+
// )
|
|
74
|
+
|
|
75
|
+
// --- Cancellation with AbortController ---
|
|
76
|
+
// const controller = new AbortController()
|
|
77
|
+
// const promise = {{name}}Client.users.GetUser({ id: '123' }, { signal: controller.signal })
|
|
78
|
+
// setTimeout(() => controller.abort(), 3000)
|
|
51
79
|
```
|
|
52
80
|
|
|
53
81
|
## Test — `{{Name}}.client.test.ts`
|
|
@@ -112,4 +140,7 @@ npx ts-procedures-codegen --url http://localhost:3000/docs --out ./src/generated
|
|
|
112
140
|
|
|
113
141
|
# Watch mode for development
|
|
114
142
|
npx ts-procedures-codegen --url http://localhost:3000/docs --out ./src/generated/api --watch
|
|
143
|
+
|
|
144
|
+
# Wipe the output directory before writing (prunes stale scope files left over from removed scopes)
|
|
145
|
+
npx ts-procedures-codegen --url http://localhost:3000/docs --out ./src/generated/api --clean-out-dir
|
|
115
146
|
```
|
|
@@ -317,6 +317,7 @@ npx ts-procedures-codegen --url http://localhost:3000/docs --out ./src/generated
|
|
|
317
317
|
# --array-item-naming Item --uncountable-words criteria,alumni
|
|
318
318
|
# --dry-run --watch --client-import-path @my-app/client
|
|
319
319
|
# --config ./codegen.config.json --service-name Auth
|
|
320
|
+
# --clean-out-dir # recursively wipe --out before writing (prunes stale scope files)
|
|
320
321
|
```
|
|
321
322
|
|
|
322
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.ProcedureError`, etc. The errors file (`_errors.ts`) emits `${ServiceName}Errors` and `${ServiceName}ProcedureErrorUnion` (defaults: `ApiErrors`, `ApiProcedureErrorUnion`).
|
|
@@ -335,6 +336,7 @@ const client = createClient({
|
|
|
335
336
|
adapter: createFetchAdapter(),
|
|
336
337
|
basePath: 'http://localhost:3000',
|
|
337
338
|
scopes: createApiBindings,
|
|
339
|
+
defaults: { timeout: 30_000, headers: { 'X-Client-Version': '1.0.0' } },
|
|
338
340
|
hooks: {
|
|
339
341
|
onBeforeRequest(ctx) {
|
|
340
342
|
ctx.request.headers = { ...ctx.request.headers, Authorization: `Bearer ${getToken()}` }
|
|
@@ -349,20 +351,67 @@ const client = createClient({
|
|
|
349
351
|
// Fully typed — params and response inferred from server schemas; type aliases live under Api.<Scope>.<Route>.
|
|
350
352
|
const user = await client.users.GetUser({ pathParams: { id: '123' } })
|
|
351
353
|
|
|
352
|
-
// Per-call
|
|
353
|
-
await client.users.GetUser(
|
|
354
|
-
|
|
355
|
-
|
|
354
|
+
// Per-call options — timeout, signal, headers, basePath, and hooks all share one bag
|
|
355
|
+
await client.users.GetUser(
|
|
356
|
+
{ pathParams: { id: '123' } },
|
|
357
|
+
{
|
|
358
|
+
timeout: 5000,
|
|
359
|
+
headers: { 'X-Request-Id': crypto.randomUUID() },
|
|
360
|
+
onAfterResponse(ctx) {
|
|
361
|
+
console.log(ctx.response.headers['x-rate-limit-remaining'])
|
|
362
|
+
},
|
|
356
363
|
},
|
|
357
|
-
|
|
364
|
+
)
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
### Per-Call Options & Defaults
|
|
368
|
+
|
|
369
|
+
```typescript
|
|
370
|
+
interface ProcedureCallDefaults {
|
|
371
|
+
signal?: AbortSignal // cancellation (combined with per-call via AbortSignal.any)
|
|
372
|
+
timeout?: number // ms — per-call timeout:0 disables inherited default
|
|
373
|
+
headers?: Record<string, string> // merged, per-call keys win
|
|
374
|
+
basePath?: string // per-call > default > config.basePath
|
|
375
|
+
meta?: RequestMeta // typed per-request metadata (declaration-mergeable)
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
interface ProcedureCallOptions extends ProcedureCallDefaults, ClientHooks {}
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
- Defaults are set via `config.defaults`; per-call options are passed as the 2nd argument to any generated callable.
|
|
382
|
+
- Header precedence (low → high): adapter config < `defaults.headers` < per-call `headers` < route-declared `schema.input.headers` < `onBeforeRequest` mutations.
|
|
383
|
+
|
|
384
|
+
### Typed RequestMeta (Declaration Merging)
|
|
385
|
+
|
|
386
|
+
Augment `RequestMeta` to type `meta` end-to-end (options, hooks, adapter):
|
|
387
|
+
|
|
388
|
+
```typescript
|
|
389
|
+
// For code-generated self-contained clients
|
|
390
|
+
declare module './generated/_types' {
|
|
391
|
+
interface RequestMeta {
|
|
392
|
+
traceId: string
|
|
393
|
+
priority?: 'high' | 'low'
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// Or for direct ts-procedures/client usage
|
|
398
|
+
declare module 'ts-procedures/client' {
|
|
399
|
+
interface RequestMeta { traceId: string }
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
await client.users.GetUser(
|
|
403
|
+
{ pathParams: { id: '1' } },
|
|
404
|
+
{ meta: { traceId: 'req-abc', priority: 'high' } }, // fully typed
|
|
405
|
+
)
|
|
358
406
|
```
|
|
359
407
|
|
|
360
408
|
### Hook Types
|
|
361
409
|
|
|
362
410
|
```typescript
|
|
363
411
|
interface ClientHooks {
|
|
364
|
-
onBeforeRequest?: (ctx:
|
|
365
|
-
onAfterResponse?: (ctx:
|
|
412
|
+
onBeforeRequest?: (ctx: BeforeRequestContext) => BeforeRequestContext | Promise<BeforeRequestContext>
|
|
413
|
+
onAfterResponse?: (ctx: AfterResponseContext) => void | Promise<void>
|
|
414
|
+
onError?: (ctx: ErrorContext) => void | Promise<void>
|
|
366
415
|
}
|
|
367
416
|
```
|
|
368
417
|
|
|
@@ -317,6 +317,7 @@ npx ts-procedures-codegen --url http://localhost:3000/docs --out ./src/generated
|
|
|
317
317
|
# --array-item-naming Item --uncountable-words criteria,alumni
|
|
318
318
|
# --dry-run --watch --client-import-path @my-app/client
|
|
319
319
|
# --config ./codegen.config.json --service-name Auth
|
|
320
|
+
# --clean-out-dir # recursively wipe --out before writing (prunes stale scope files)
|
|
320
321
|
```
|
|
321
322
|
|
|
322
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.ProcedureError`, etc. The errors file (`_errors.ts`) emits `${ServiceName}Errors` and `${ServiceName}ProcedureErrorUnion` (defaults: `ApiErrors`, `ApiProcedureErrorUnion`).
|
|
@@ -335,6 +336,7 @@ const client = createClient({
|
|
|
335
336
|
adapter: createFetchAdapter(),
|
|
336
337
|
basePath: 'http://localhost:3000',
|
|
337
338
|
scopes: createApiBindings,
|
|
339
|
+
defaults: { timeout: 30_000, headers: { 'X-Client-Version': '1.0.0' } },
|
|
338
340
|
hooks: {
|
|
339
341
|
onBeforeRequest(ctx) {
|
|
340
342
|
ctx.request.headers = { ...ctx.request.headers, Authorization: `Bearer ${getToken()}` }
|
|
@@ -349,20 +351,67 @@ const client = createClient({
|
|
|
349
351
|
// Fully typed — params and response inferred from server schemas; type aliases live under Api.<Scope>.<Route>.
|
|
350
352
|
const user = await client.users.GetUser({ pathParams: { id: '123' } })
|
|
351
353
|
|
|
352
|
-
// Per-call
|
|
353
|
-
await client.users.GetUser(
|
|
354
|
-
|
|
355
|
-
|
|
354
|
+
// Per-call options — timeout, signal, headers, basePath, and hooks all share one bag
|
|
355
|
+
await client.users.GetUser(
|
|
356
|
+
{ pathParams: { id: '123' } },
|
|
357
|
+
{
|
|
358
|
+
timeout: 5000,
|
|
359
|
+
headers: { 'X-Request-Id': crypto.randomUUID() },
|
|
360
|
+
onAfterResponse(ctx) {
|
|
361
|
+
console.log(ctx.response.headers['x-rate-limit-remaining'])
|
|
362
|
+
},
|
|
356
363
|
},
|
|
357
|
-
|
|
364
|
+
)
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
### Per-Call Options & Defaults
|
|
368
|
+
|
|
369
|
+
```typescript
|
|
370
|
+
interface ProcedureCallDefaults {
|
|
371
|
+
signal?: AbortSignal // cancellation (combined with per-call via AbortSignal.any)
|
|
372
|
+
timeout?: number // ms — per-call timeout:0 disables inherited default
|
|
373
|
+
headers?: Record<string, string> // merged, per-call keys win
|
|
374
|
+
basePath?: string // per-call > default > config.basePath
|
|
375
|
+
meta?: RequestMeta // typed per-request metadata (declaration-mergeable)
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
interface ProcedureCallOptions extends ProcedureCallDefaults, ClientHooks {}
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
- Defaults are set via `config.defaults`; per-call options are passed as the 2nd argument to any generated callable.
|
|
382
|
+
- Header precedence (low → high): adapter config < `defaults.headers` < per-call `headers` < route-declared `schema.input.headers` < `onBeforeRequest` mutations.
|
|
383
|
+
|
|
384
|
+
### Typed RequestMeta (Declaration Merging)
|
|
385
|
+
|
|
386
|
+
Augment `RequestMeta` to type `meta` end-to-end (options, hooks, adapter):
|
|
387
|
+
|
|
388
|
+
```typescript
|
|
389
|
+
// For code-generated self-contained clients
|
|
390
|
+
declare module './generated/_types' {
|
|
391
|
+
interface RequestMeta {
|
|
392
|
+
traceId: string
|
|
393
|
+
priority?: 'high' | 'low'
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// Or for direct ts-procedures/client usage
|
|
398
|
+
declare module 'ts-procedures/client' {
|
|
399
|
+
interface RequestMeta { traceId: string }
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
await client.users.GetUser(
|
|
403
|
+
{ pathParams: { id: '1' } },
|
|
404
|
+
{ meta: { traceId: 'req-abc', priority: 'high' } }, // fully typed
|
|
405
|
+
)
|
|
358
406
|
```
|
|
359
407
|
|
|
360
408
|
### Hook Types
|
|
361
409
|
|
|
362
410
|
```typescript
|
|
363
411
|
interface ClientHooks {
|
|
364
|
-
onBeforeRequest?: (ctx:
|
|
365
|
-
onAfterResponse?: (ctx:
|
|
412
|
+
onBeforeRequest?: (ctx: BeforeRequestContext) => BeforeRequestContext | Promise<BeforeRequestContext>
|
|
413
|
+
onAfterResponse?: (ctx: AfterResponseContext) => void | Promise<void>
|
|
414
|
+
onError?: (ctx: ErrorContext) => void | Promise<void>
|
|
366
415
|
}
|
|
367
416
|
```
|
|
368
417
|
|
package/build/client/call.d.ts
CHANGED
|
@@ -1,14 +1,23 @@
|
|
|
1
|
-
import type { ClientAdapter, ClientHooks, CallDescriptor } from './types.js';
|
|
1
|
+
import type { ClientAdapter, ClientHooks, CallDescriptor, ProcedureCallDefaults, ProcedureCallOptions } from './types.js';
|
|
2
|
+
export interface ExecuteCallConfig {
|
|
3
|
+
descriptor: CallDescriptor;
|
|
4
|
+
basePath: string;
|
|
5
|
+
adapter: ClientAdapter;
|
|
6
|
+
hooks: ClientHooks;
|
|
7
|
+
defaults?: ProcedureCallDefaults;
|
|
8
|
+
options?: ProcedureCallOptions;
|
|
9
|
+
}
|
|
2
10
|
/**
|
|
3
11
|
* Executes a single procedure call through the adapter.
|
|
4
12
|
*
|
|
5
13
|
* Flow:
|
|
6
|
-
* 1.
|
|
7
|
-
* 2.
|
|
8
|
-
* 3.
|
|
9
|
-
* 4.
|
|
10
|
-
* 5.
|
|
11
|
-
* 6.
|
|
12
|
-
* 7.
|
|
14
|
+
* 1. Resolve base path (per-call > defaults > config) and build AdapterRequest
|
|
15
|
+
* 2. Apply request options (headers, signal, timeout, meta) from defaults + per-call
|
|
16
|
+
* 3. Run onBeforeRequest hooks (global then local) — may further mutate request
|
|
17
|
+
* 4. Call adapter.request()
|
|
18
|
+
* 5. On adapter error: run onError hooks, re-throw
|
|
19
|
+
* 6. Run onAfterResponse hooks (may mutate response.status to swallow errors)
|
|
20
|
+
* 7. If response status is non-2xx: throw ClientRequestError
|
|
21
|
+
* 8. Return response.body as TResponse
|
|
13
22
|
*/
|
|
14
|
-
export declare function executeCall<TResponse>(
|
|
23
|
+
export declare function executeCall<TResponse>(config: ExecuteCallConfig): Promise<TResponse>;
|
package/build/client/call.js
CHANGED
|
@@ -1,37 +1,43 @@
|
|
|
1
1
|
import { buildAdapterRequest } from './request-builder.js';
|
|
2
2
|
import { runBeforeRequest, runAfterResponse, runOnError } from './hooks.js';
|
|
3
|
+
import { applyRequestOptions, resolveBasePath } from './resolve-options.js';
|
|
3
4
|
import { ClientRequestError } from './errors.js';
|
|
4
5
|
/**
|
|
5
6
|
* Executes a single procedure call through the adapter.
|
|
6
7
|
*
|
|
7
8
|
* Flow:
|
|
8
|
-
* 1.
|
|
9
|
-
* 2.
|
|
10
|
-
* 3.
|
|
11
|
-
* 4.
|
|
12
|
-
* 5.
|
|
13
|
-
* 6.
|
|
14
|
-
* 7.
|
|
9
|
+
* 1. Resolve base path (per-call > defaults > config) and build AdapterRequest
|
|
10
|
+
* 2. Apply request options (headers, signal, timeout, meta) from defaults + per-call
|
|
11
|
+
* 3. Run onBeforeRequest hooks (global then local) — may further mutate request
|
|
12
|
+
* 4. Call adapter.request()
|
|
13
|
+
* 5. On adapter error: run onError hooks, re-throw
|
|
14
|
+
* 6. Run onAfterResponse hooks (may mutate response.status to swallow errors)
|
|
15
|
+
* 7. If response status is non-2xx: throw ClientRequestError
|
|
16
|
+
* 8. Return response.body as TResponse
|
|
15
17
|
*/
|
|
16
|
-
export async function executeCall(
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
export async function executeCall(config) {
|
|
19
|
+
const { descriptor, basePath, adapter, hooks, defaults, options } = config;
|
|
20
|
+
// 1. Build the initial request (path/query/body from descriptor)
|
|
21
|
+
const resolvedBasePath = resolveBasePath(defaults, options, basePath);
|
|
22
|
+
let request = buildAdapterRequest(descriptor, resolvedBasePath);
|
|
23
|
+
// 2. Apply request-level options (headers, signal, timeout, meta)
|
|
24
|
+
request = applyRequestOptions(request, defaults, options);
|
|
25
|
+
// 3. Run before-request hooks — they may further mutate the request
|
|
26
|
+
const beforeCtx = await runBeforeRequest({ procedureName: descriptor.name, scope: descriptor.scope, request }, hooks, options);
|
|
21
27
|
request = beforeCtx.request;
|
|
22
|
-
//
|
|
28
|
+
// 4. Call the adapter
|
|
23
29
|
let response;
|
|
24
30
|
try {
|
|
25
31
|
response = await adapter.request(request);
|
|
26
32
|
}
|
|
27
33
|
catch (err) {
|
|
28
|
-
//
|
|
29
|
-
await runOnError({ procedureName: descriptor.name, scope: descriptor.scope, request, error: err },
|
|
34
|
+
// 5. On adapter error: run error hooks, re-throw
|
|
35
|
+
await runOnError({ procedureName: descriptor.name, scope: descriptor.scope, request, error: err }, hooks, options);
|
|
30
36
|
throw err;
|
|
31
37
|
}
|
|
32
|
-
//
|
|
33
|
-
await runAfterResponse({ procedureName: descriptor.name, scope: descriptor.scope, request, response },
|
|
34
|
-
//
|
|
38
|
+
// 6. Run after-response hooks — they may mutate response.status to swallow errors
|
|
39
|
+
await runAfterResponse({ procedureName: descriptor.name, scope: descriptor.scope, request, response }, hooks, options);
|
|
40
|
+
// 7. Check status AFTER hooks (hooks may have swallowed the error by mutating status)
|
|
35
41
|
if (response.status < 200 || response.status >= 300) {
|
|
36
42
|
throw new ClientRequestError({
|
|
37
43
|
status: response.status,
|
|
@@ -41,7 +47,7 @@ export async function executeCall(descriptor, basePath, adapter, globalHooks, lo
|
|
|
41
47
|
scope: descriptor.scope,
|
|
42
48
|
});
|
|
43
49
|
}
|
|
44
|
-
//
|
|
50
|
+
// 8. Return the body
|
|
45
51
|
return response.body;
|
|
46
52
|
}
|
|
47
53
|
//# sourceMappingURL=call.js.map
|
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,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;AAkBhD;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAY,MAAyB;IACpE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,CAAA;IAE1E,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,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"}
|