@zudojs/api 1.2.1 → 1.2.3
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
CHANGED
|
@@ -59,6 +59,7 @@ import {
|
|
|
59
59
|
type APIExecutionContext,
|
|
60
60
|
type APIExecutorOptions,
|
|
61
61
|
type APIHandler,
|
|
62
|
+
type APIHandlerContext,
|
|
62
63
|
type APIInterceptor,
|
|
63
64
|
type APIOperation,
|
|
64
65
|
type APIOperationMetadata,
|
|
@@ -308,6 +309,8 @@ Every operation has a deadline. `timeout` must be a positive, finite integer of
|
|
|
308
309
|
|
|
309
310
|
The handler always receives a `context.signal`, even when the caller supplied none. It aborts when the deadline elapses (its `reason` is the `APITimeoutError` the call fails with, 504) or when the caller's signal aborts (its `reason` is the `ErrorCode.OPERATION_CANCELLED` error the call fails with), so pass it into anything that supports it (`fetch`, a driver query, a loop check) and the work stops instead of running on and repeating side effects after the caller has given up. The signal is not aborted when the handler completes normally. Everything else on the handler's context (`requestId`, `state`, `get`/`set`, `metadata`) is the caller's context. Branch on `ErrorCode.OPERATION_CANCELLED` rather than on the (nginx-convention) 499 status.
|
|
310
311
|
|
|
312
|
+
The type says so too: a handler's context is `APIHandlerContext` (`APIContext & { readonly signal: AbortSignal }`), so `context.signal` needs no `!` under strict TypeScript. Only the handler's view is narrowed; a context you build with `createAPIContext` and pass to `executor.execute(op, input, context)` may still omit the signal, and a handler annotated with the plain `APIContext` is still accepted.
|
|
313
|
+
|
|
311
314
|
```typescript
|
|
312
315
|
const exportReport = defineOperation({
|
|
313
316
|
name: "reports.export",
|
|
@@ -341,7 +344,7 @@ At most `MAX_INTERCEPTORS` interceptors per executor, and each `next()` may be a
|
|
|
341
344
|
|
|
342
345
|
## Context
|
|
343
346
|
|
|
344
|
-
`APIContext` carries the request id, an optional `AbortSignal
|
|
347
|
+
`APIContext` carries the request id, an optional `AbortSignal` (always present on the handler's `APIHandlerContext`), caller state, and typed key/value slots. Keys carry their own identity, so two keys created with the same name never collide:
|
|
345
348
|
|
|
346
349
|
```typescript
|
|
347
350
|
const FeatureFlagsKey = createContextKey<readonly string[]>("featureFlags");
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { APIContext } from "../context/context.type.js";
|
|
2
|
+
import type { APIHandlerContext } from "../handler/handler.type.js";
|
|
2
3
|
import type { APIError } from "../errors/index.js";
|
|
3
4
|
/**
|
|
4
5
|
* Error for an execution cancelled by the caller's `AbortSignal`.
|
|
@@ -19,7 +20,7 @@ export declare function abortedError(operationName: string): APIError;
|
|
|
19
20
|
* is visible to the handler and vice versa, and any extra members of a
|
|
20
21
|
* hand-rolled context are reachable through the prototype chain.
|
|
21
22
|
*/
|
|
22
|
-
export declare function withContextSignal(context: APIContext, signal: AbortSignal):
|
|
23
|
+
export declare function withContextSignal(context: APIContext, signal: AbortSignal): APIHandlerContext;
|
|
23
24
|
/**
|
|
24
25
|
* Runs `run` under a deadline and the caller's abort signal.
|
|
25
26
|
*
|
|
@@ -1,4 +1,16 @@
|
|
|
1
1
|
import type { APIContext } from "../context/context.type.js";
|
|
2
|
+
/**
|
|
3
|
+
* The context an operation handler receives.
|
|
4
|
+
*
|
|
5
|
+
* The caller's {@link APIContext} with a non-optional `signal`: the
|
|
6
|
+
* executor always derives one, which aborts when the operation's deadline
|
|
7
|
+
* elapses or the caller's own signal aborts, even when the caller passed
|
|
8
|
+
* no signal. Contexts built by callers (`createAPIContext`,
|
|
9
|
+
* `executor.execute(op, input, context)`) may still omit it.
|
|
10
|
+
*/
|
|
11
|
+
export type APIHandlerContext<TState = unknown> = APIContext<TState> & {
|
|
12
|
+
readonly signal: AbortSignal;
|
|
13
|
+
};
|
|
2
14
|
/**
|
|
3
15
|
* Handler for an API operation.
|
|
4
16
|
*
|
|
@@ -8,8 +20,8 @@ import type { APIContext } from "../context/context.type.js";
|
|
|
8
20
|
* validated value; without one, input is passed through as-is and the
|
|
9
21
|
* handler must validate it itself.
|
|
10
22
|
*
|
|
11
|
-
* `context.signal` aborts when the operation's
|
|
12
|
-
* caller aborts; pass it to anything cancellable.
|
|
23
|
+
* `context.signal` is always present. It aborts when the operation's
|
|
24
|
+
* deadline elapses or the caller aborts; pass it to anything cancellable.
|
|
13
25
|
*/
|
|
14
|
-
export type APIHandler<TInput = unknown, TOutput = unknown> = (input: TInput, context:
|
|
26
|
+
export type APIHandler<TInput = unknown, TOutput = unknown> = (input: TInput, context: APIHandlerContext) => Promise<TOutput>;
|
|
15
27
|
//# sourceMappingURL=handler.type.d.ts.map
|
package/dist/index.d.ts
CHANGED
|
@@ -43,7 +43,7 @@ export { APIError, APIValidationError, APIAuthenticationError, APIAuthorizationE
|
|
|
43
43
|
export { DEFAULT_OPERATION_TIMEOUT, MAX_OPERATION_TIMEOUT, MAX_INTERCEPTORS, MAX_VALIDATION_ISSUES, MAX_VALIDATION_ISSUE_LENGTH, MAX_OPERATION_NAME_LENGTH, MAX_REQUEST_ID_LENGTH, } from "./api/constants.js";
|
|
44
44
|
export type { APIContext, APIContextKey, APITransportKind, } from "./api/context/context.type.js";
|
|
45
45
|
export { createAPIContext, createContextKey, isValidRequestId, normalizeRequestId, RequestIdContextKey, CorrelationIdContextKey, TenantIdContextKey, UserIdContextKey, StartTimeContextKey, TransportContextKey, } from "./api/context/context.type.js";
|
|
46
|
-
export type { APIHandler } from "./api/handler/handler.type.js";
|
|
46
|
+
export type { APIHandler, APIHandlerContext, } from "./api/handler/handler.type.js";
|
|
47
47
|
export type { AnyAPIOperation, APIOperation, APIOperationMetadata, DefineOperationOptions, } from "./api/operation/operation.type.js";
|
|
48
48
|
export { defineOperation, resolveOperationTimeout, } from "./api/operation/operation.type.js";
|
|
49
49
|
export type { APIInputSchema, DefineOperationWithSchemaOptions, InferAPISchemaOutput, } from "./api/operation/operationSchema.type.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zudojs/api",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.3",
|
|
4
4
|
"description": "Application-facing API layer for Zudojs — operation definitions, execution context, interceptors, and transport-agnostic contracts.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -27,13 +27,13 @@
|
|
|
27
27
|
"node": ">=24.0.0"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@zudojs/errors": "1.3.
|
|
31
|
-
"@zudojs/openapi": "1.5.
|
|
32
|
-
"@zudojs/queue": "1.
|
|
33
|
-
"@zudojs/rpc": "1.4.
|
|
34
|
-
"@zudojs/schema": "1.2.
|
|
35
|
-
"@zudojs/security": "1.3.
|
|
36
|
-
"@zudojs/serialization": "1.2.
|
|
30
|
+
"@zudojs/errors": "1.3.2",
|
|
31
|
+
"@zudojs/openapi": "1.5.2",
|
|
32
|
+
"@zudojs/queue": "1.5.1",
|
|
33
|
+
"@zudojs/rpc": "1.4.3",
|
|
34
|
+
"@zudojs/schema": "1.2.3",
|
|
35
|
+
"@zudojs/security": "1.3.3",
|
|
36
|
+
"@zudojs/serialization": "1.2.3",
|
|
37
37
|
"@zudojs/types": "1.2.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|