@adhd/apigen-engine-runtime 0.1.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/README.md +40 -0
- package/index.d.ts +28 -0
- package/index.js +1 -0
- package/index.mjs +1398 -0
- package/lib/api-package.d.ts +4 -0
- package/lib/apigen-runtime.d.ts +1 -0
- package/lib/build-context.d.ts +4 -0
- package/lib/coerce-query.d.ts +38 -0
- package/lib/define-middleware.d.ts +5 -0
- package/lib/describe-params.d.ts +18 -0
- package/lib/dispatch.d.ts +23 -0
- package/lib/event-bus.d.ts +19 -0
- package/lib/fn-table.d.ts +16 -0
- package/lib/instance-registry.d.ts +104 -0
- package/lib/invoke.d.ts +112 -0
- package/lib/logger.d.ts +29 -0
- package/lib/logical/host-ts.d.ts +41 -0
- package/lib/logical/nominal-codec.d.ts +73 -0
- package/lib/logical/union-codec.d.ts +63 -0
- package/lib/mcp-output-schema.d.ts +21 -0
- package/lib/stream.d.ts +88 -0
- package/lib/tool-description.d.ts +18 -0
- package/lib/types.d.ts +35 -0
- package/lib/validate-layer.d.ts +54 -0
- package/package.json +19 -0
package/lib/stream.d.ts
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { AfterFirstChunkError, BeforeFirstChunkError } from '@adhd/apigen-base-errors';
|
|
2
|
+
|
|
3
|
+
/** A strongly-typed async iterable chunk stream (§11 consumer-pull). */
|
|
4
|
+
export type ApiStream<T = unknown> = AsyncIterable<T>;
|
|
5
|
+
/**
|
|
6
|
+
* Options for {@link createStream}.
|
|
7
|
+
*
|
|
8
|
+
* @template T - the chunk type yielded by the producer
|
|
9
|
+
*/
|
|
10
|
+
export interface CreateStreamOptions<T = unknown> {
|
|
11
|
+
/**
|
|
12
|
+
* The producer: an async generator that yields chunks.
|
|
13
|
+
* It receives the AbortSignal so it can honour cancellation directly;
|
|
14
|
+
* the harness also terminates iteration externally when the signal fires.
|
|
15
|
+
*/
|
|
16
|
+
produce: (signal: AbortSignal) => AsyncGenerator<T>;
|
|
17
|
+
/**
|
|
18
|
+
* Optional cancellation signal (§11).
|
|
19
|
+
* When aborted, iteration terminates after the current `yield` without
|
|
20
|
+
* surfacing an error — each Layer's **end** path runs.
|
|
21
|
+
*/
|
|
22
|
+
signal?: AbortSignal;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Wrap an async generator producer in a stream-lifecycle–aware `ApiStream`.
|
|
26
|
+
*
|
|
27
|
+
* The returned `AsyncIterable` is **consumer-pull**: the producer is driven
|
|
28
|
+
* one chunk at a time by the consumer's `for await`. Backpressure is
|
|
29
|
+
* natural — the producer only runs when the consumer is ready for the next
|
|
30
|
+
* value.
|
|
31
|
+
*
|
|
32
|
+
* Cancellation: when `options.signal` fires, the next `next()` call returns
|
|
33
|
+
* `{ done: true }` cleanly. Any pending `await` inside the producer is
|
|
34
|
+
* interrupted by the same signal (the producer must honour it).
|
|
35
|
+
*
|
|
36
|
+
* Error-after-first-chunk: if the producer throws after yielding at least
|
|
37
|
+
* one chunk, the `ApiStream` propagates the error as a normal iterator
|
|
38
|
+
* rejection (the consumer's `for await` body receives a thrown `ApiError`
|
|
39
|
+
* or plain error). Transport adapters catch this and deliver it in-band
|
|
40
|
+
* per the §11 carrier table.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* const stream = createStream({
|
|
45
|
+
* produce: async function* (signal) {
|
|
46
|
+
* for (const item of items) {
|
|
47
|
+
* if (signal.aborted) return
|
|
48
|
+
* yield item
|
|
49
|
+
* }
|
|
50
|
+
* },
|
|
51
|
+
* signal: call.signal,
|
|
52
|
+
* })
|
|
53
|
+
* for await (const chunk of stream) { ... }
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export declare function createStream<T = unknown>(options: CreateStreamOptions<T>): ApiStream<T>;
|
|
57
|
+
/**
|
|
58
|
+
* Collect all chunks from an `ApiStream` into an array.
|
|
59
|
+
*
|
|
60
|
+
* Used by CLI adapters and test helpers. Surfaces error-after-first-chunk
|
|
61
|
+
* as a thrown `ApiError` / plain error — callers wrap with try/catch.
|
|
62
|
+
*/
|
|
63
|
+
export declare function drainStream<T>(stream: ApiStream<T>): Promise<T[]>;
|
|
64
|
+
/** Result returned by {@link collectWithPhase}. */
|
|
65
|
+
export type CollectResult<T> = {
|
|
66
|
+
ok: true;
|
|
67
|
+
chunks: T[];
|
|
68
|
+
} | {
|
|
69
|
+
ok: false;
|
|
70
|
+
carrier: BeforeFirstChunkError | AfterFirstChunkError;
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Drain `stream`, tracking whether any chunks were emitted before an error.
|
|
74
|
+
*
|
|
75
|
+
* Returns a discriminated result:
|
|
76
|
+
* - `{ ok: true, chunks }` — stream completed cleanly.
|
|
77
|
+
* - `{ ok: false, carrier }` — stream threw; `carrier.phase` indicates
|
|
78
|
+
* whether the error was before or after the first chunk was produced.
|
|
79
|
+
*
|
|
80
|
+
* Transport adapters use this to select the correct §11 in-band carrier.
|
|
81
|
+
*/
|
|
82
|
+
export declare function collectWithPhase<T>(stream: ApiStream<T>): Promise<CollectResult<T>>;
|
|
83
|
+
/**
|
|
84
|
+
* Returns true when `value` is an `AsyncIterable` (i.e. an `ApiStream`).
|
|
85
|
+
*
|
|
86
|
+
* Used by Layer harness dispatch to distinguish streaming from scalar results.
|
|
87
|
+
*/
|
|
88
|
+
export declare function isApiStream(value: unknown): value is ApiStream<unknown>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** The minimal shape this module reads off a composed schema entry. */
|
|
2
|
+
export interface ToolDescriptionSchema {
|
|
3
|
+
input?: {
|
|
4
|
+
description?: unknown;
|
|
5
|
+
};
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Builds the description shown for tool `name` in an MCP `tools/list`
|
|
9
|
+
* response.
|
|
10
|
+
*
|
|
11
|
+
* @param name - The MCP tool name (used as the final fallback).
|
|
12
|
+
* @param schema - The function's composed schema (as produced by
|
|
13
|
+
* `composeSchemas`); `input.description` carries the auto-generated
|
|
14
|
+
* envelope/data-wrapper documentation.
|
|
15
|
+
* @param override - An optional caller-supplied description (e.g. from the
|
|
16
|
+
* `toolDescriptions` plugin option), prepended when present.
|
|
17
|
+
*/
|
|
18
|
+
export declare function buildToolDescription(name: string, schema: ToolDescriptionSchema | undefined, override?: string): string;
|
package/lib/types.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { GeneratedSchemas, ComposedSchemas } from '@adhd/apigen-core-client';
|
|
2
|
+
|
|
3
|
+
export type { GeneratedSchemas, ComposedSchemas };
|
|
4
|
+
export interface MiddlewareDef<_TEnvelope extends object = object, TContext extends object = object> {
|
|
5
|
+
id: string;
|
|
6
|
+
envelope?: Record<string, unknown>;
|
|
7
|
+
createContext?: (ctx: object) => TContext | Promise<TContext>;
|
|
8
|
+
eventMapping?: Record<string, (event: MiddlewareEvent) => void | Promise<void>>;
|
|
9
|
+
}
|
|
10
|
+
export interface MiddlewareEvent {
|
|
11
|
+
module: string;
|
|
12
|
+
method: string;
|
|
13
|
+
lifecycle: 'start' | 'complete' | 'error';
|
|
14
|
+
ctx: object;
|
|
15
|
+
error?: unknown;
|
|
16
|
+
}
|
|
17
|
+
export interface ApiPackageOptions<M extends readonly MiddlewareDef[]> {
|
|
18
|
+
domainSchemas: GeneratedSchemas;
|
|
19
|
+
middlewares: readonly [...M];
|
|
20
|
+
overrides?: Partial<Record<string, Partial<Record<string, boolean>>>>;
|
|
21
|
+
strict?: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface ApiPackageResult {
|
|
24
|
+
schemas: ComposedSchemas;
|
|
25
|
+
createClient: (envelope: Record<string, unknown>) => Promise<object>;
|
|
26
|
+
/**
|
|
27
|
+
* Release the package's event bus (removes every observer handler). Call
|
|
28
|
+
* when the package is discarded — hosts that create packages repeatedly
|
|
29
|
+
* (tests, hot reload, multi-tenant servers) leak handlers otherwise.
|
|
30
|
+
*/
|
|
31
|
+
dispose: () => void;
|
|
32
|
+
}
|
|
33
|
+
export declare class ConfigurationError extends Error {
|
|
34
|
+
constructor(message: string);
|
|
35
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { ComposedSchemas } from './types';
|
|
2
|
+
import { Layer } from './invoke';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A compose-time Layer that validates `call.domainArgs` and `call.envelope`
|
|
6
|
+
* against the operation's composed input schema before forwarding to dispatch.
|
|
7
|
+
*
|
|
8
|
+
* Place this Layer **innermost** (last in the `layers` array passed to
|
|
9
|
+
* `createInvoker`) so it runs immediately before dispatch, after all
|
|
10
|
+
* authentication / authorization Layers have had their chance to inspect (and
|
|
11
|
+
* reject) the call.
|
|
12
|
+
*
|
|
13
|
+
* Short-circuits with `ApiError{ code: 'invalid_argument' }` on any schema
|
|
14
|
+
* violation. Delegates to `next()` on success.
|
|
15
|
+
*
|
|
16
|
+
* @remarks
|
|
17
|
+
* This validates **shape**, not **domain correctness** (SPEC §6 necessary-but-
|
|
18
|
+
* not-sufficient boundary — see module JSDoc).
|
|
19
|
+
*/
|
|
20
|
+
export declare const validateLayer: Layer;
|
|
21
|
+
/**
|
|
22
|
+
* Typed ctx extension token that carries the `ComposedSchemas` through the
|
|
23
|
+
* Layer stack to `validateLayer`.
|
|
24
|
+
*
|
|
25
|
+
* Usage (by the caller / transport adapter):
|
|
26
|
+
* ```ts
|
|
27
|
+
* call.ctx.set(ValidateSchemasToken, schemas)
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* `validateLayer` reads it back with `call.ctx.get(ValidateSchemasToken)`.
|
|
31
|
+
*/
|
|
32
|
+
export declare const ValidateSchemasToken: unique symbol;
|
|
33
|
+
declare module './invoke' {
|
|
34
|
+
interface LayerContext {
|
|
35
|
+
get(token: typeof ValidateSchemasToken): ComposedSchemas | undefined;
|
|
36
|
+
set(token: typeof ValidateSchemasToken, value: ComposedSchemas): void;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Factory that produces a validation Layer **pre-bound** to a `ComposedSchemas`
|
|
41
|
+
* map. Prefer this over the raw `validateLayer` singleton when composing a
|
|
42
|
+
* static invoker at plugin instantiation time — it avoids the ctx-token
|
|
43
|
+
* ceremony and makes the Layer entirely self-contained.
|
|
44
|
+
*
|
|
45
|
+
* ```ts
|
|
46
|
+
* const invoke = createInvoker([makeValidateLayer(schemas), authLayer])
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* Validation is still necessary-but-not-sufficient (SPEC §6) — it validates
|
|
50
|
+
* shape, not domain correctness.
|
|
51
|
+
*
|
|
52
|
+
* @param schemas - The composed schemas for the target namespace.
|
|
53
|
+
*/
|
|
54
|
+
export declare function makeValidateLayer(schemas: ComposedSchemas): Layer;
|
package/package.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@adhd/apigen-engine-runtime",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"dependencies": {
|
|
5
|
+
"ajv": "^8.20.0",
|
|
6
|
+
"ajv-formats": "2.1.1",
|
|
7
|
+
"pino": "10.3.1",
|
|
8
|
+
"@adhd/apigen-core-client": "^0.1.0",
|
|
9
|
+
"@adhd/apigen-base-logical": "^0.0.1",
|
|
10
|
+
"@adhd/apigen-base-errors": "^0.1.1",
|
|
11
|
+
"better-sqlite3": "12.10.0"
|
|
12
|
+
},
|
|
13
|
+
"main": "./index.js",
|
|
14
|
+
"module": "./index.mjs",
|
|
15
|
+
"typings": "./index.d.ts",
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
}
|
|
19
|
+
}
|