@jini-ai/http-kit 0.3.2 → 0.3.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/dist/delegated-tools.d.ts +89 -0
- package/dist/delegated-tools.d.ts.map +1 -1
- package/dist/delegated-tools.js +106 -1
- package/dist/delegated-tools.js.map +1 -1
- package/package.json +6 -6
- package/dist/express/run-stream.d.ts +0 -15
- package/dist/express/run-stream.d.ts.map +0 -1
- package/dist/express/run-stream.js +0 -11
- package/dist/express/run-stream.js.map +0 -1
- package/dist/express-index.d.ts +0 -32
- package/dist/express-index.d.ts.map +0 -1
- package/dist/express-index.js +0 -14
- package/dist/express-index.js.map +0 -1
- package/dist/fastify/adapter.d.ts +0 -31
- package/dist/fastify/adapter.d.ts.map +0 -1
- package/dist/fastify/adapter.js +0 -64
- package/dist/fastify/adapter.js.map +0 -1
- package/dist/fastify/agents.d.ts +0 -13
- package/dist/fastify/agents.d.ts.map +0 -1
- package/dist/fastify/agents.js +0 -7
- package/dist/fastify/agents.js.map +0 -1
- package/dist/fastify/api-security-middleware.d.ts +0 -64
- package/dist/fastify/api-security-middleware.d.ts.map +0 -1
- package/dist/fastify/api-security-middleware.js +0 -139
- package/dist/fastify/api-security-middleware.js.map +0 -1
- package/dist/fastify/compat.d.ts +0 -22
- package/dist/fastify/compat.d.ts.map +0 -1
- package/dist/fastify/compat.js +0 -16
- package/dist/fastify/compat.js.map +0 -1
- package/dist/fastify/daemon-status.d.ts +0 -22
- package/dist/fastify/daemon-status.d.ts.map +0 -1
- package/dist/fastify/daemon-status.js +0 -9
- package/dist/fastify/daemon-status.js.map +0 -1
- package/dist/fastify/host-tools.d.ts +0 -13
- package/dist/fastify/host-tools.d.ts.map +0 -1
- package/dist/fastify/host-tools.js +0 -8
- package/dist/fastify/host-tools.js.map +0 -1
- package/dist/fastify/index.d.ts +0 -36
- package/dist/fastify/index.d.ts.map +0 -1
- package/dist/fastify/index.js +0 -18
- package/dist/fastify/index.js.map +0 -1
- package/dist/fastify/local-daemon-request.d.ts +0 -43
- package/dist/fastify/local-daemon-request.d.ts.map +0 -1
- package/dist/fastify/local-daemon-request.js +0 -155
- package/dist/fastify/local-daemon-request.js.map +0 -1
- package/dist/fastify/origin.d.ts +0 -21
- package/dist/fastify/origin.d.ts.map +0 -1
- package/dist/fastify/origin.js +0 -14
- package/dist/fastify/origin.js.map +0 -1
- package/dist/fastify/request.d.ts +0 -20
- package/dist/fastify/request.d.ts.map +0 -1
- package/dist/fastify/request.js +0 -25
- package/dist/fastify/request.js.map +0 -1
- package/dist/fastify/response.d.ts +0 -20
- package/dist/fastify/response.d.ts.map +0 -1
- package/dist/fastify/response.js +0 -41
- package/dist/fastify/response.js.map +0 -1
- package/dist/fastify/route-registration-guard.d.ts +0 -70
- package/dist/fastify/route-registration-guard.d.ts.map +0 -1
- package/dist/fastify/route-registration-guard.js +0 -69
- package/dist/fastify/route-registration-guard.js.map +0 -1
- package/dist/fastify/run-stream.d.ts +0 -18
- package/dist/fastify/run-stream.d.ts.map +0 -1
- package/dist/fastify/run-stream.js +0 -10
- package/dist/fastify/run-stream.js.map +0 -1
- package/dist/fastify/runs.d.ts +0 -17
- package/dist/fastify/runs.d.ts.map +0 -1
- package/dist/fastify/runs.js +0 -33
- package/dist/fastify/runs.js.map +0 -1
- package/dist/run-stream.d.ts +0 -60
- package/dist/run-stream.d.ts.map +0 -1
- package/dist/run-stream.js +0 -108
- package/dist/run-stream.js.map +0 -1
package/dist/fastify/request.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { createApiError } from '@jini/protocol';
|
|
2
|
-
/**
|
|
3
|
-
* Extracts `body`/`query`/`params` from a Fastify `FastifyRequest` into a `RouteInputContext`, so
|
|
4
|
-
* a route's `parse` function can be unit-tested without constructing a real `FastifyRequest`.
|
|
5
|
-
*/
|
|
6
|
-
export function rawInput(request) {
|
|
7
|
-
return {
|
|
8
|
-
body: request.body,
|
|
9
|
-
query: (request.query ?? {}),
|
|
10
|
-
params: (request.params ?? {}),
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Builds a `BAD_REQUEST` `ApiError` for a failed parse. When `issues` is non-empty, attaches
|
|
15
|
-
* them as structured validation details so clients can render per-field errors.
|
|
16
|
-
*/
|
|
17
|
-
export function validationError(message, issues = []) {
|
|
18
|
-
if (issues.length === 0) {
|
|
19
|
-
return createApiError('BAD_REQUEST', message);
|
|
20
|
-
}
|
|
21
|
-
return createApiError('BAD_REQUEST', message, {
|
|
22
|
-
details: { kind: 'validation', issues },
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
//# sourceMappingURL=request.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"request.js","sourceRoot":"","sources":["../../src/fastify/request.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,cAAc,EAA0C,MAAM,gBAAgB,CAAC;AAGxF;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,OAAuB;IAC9C,OAAO;QACL,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,KAAK,EAAE,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAA4B;QACvD,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAA2B;KACzD,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC7B,OAAe,EACf,SAAyD,EAAE;IAE3D,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,cAAc,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;IAChD,CAAC;IACD,OAAO,cAAc,CAAC,aAAa,EAAE,OAAO,EAAE;QAC5C,OAAO,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAiD;KACvF,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Response-side serialization: writes a plain JSON body or a standard `ApiError` envelope onto a
|
|
3
|
-
* Fastify `FastifyReply`, and maps an `ApiErrorCode` to its default HTTP status. No internal
|
|
4
|
-
* dependencies — this is the terminal step of the Fastify Adapter's error-handling pipeline.
|
|
5
|
-
*
|
|
6
|
-
* Deliberately duplicated from `../express/response.ts` rather than shared: both files implement
|
|
7
|
-
* the identical `ApiErrorCode` -> HTTP status mapping and error-envelope shape, but this
|
|
8
|
-
* subtree's whole point is to stay independent of `express/` (see `../../source-map.md`'s
|
|
9
|
-
* Fastify-transport section) — a Fastify-only consumer must be able to import this module without
|
|
10
|
-
* ever pulling in anything that even *type*-references the `express` package.
|
|
11
|
-
*/
|
|
12
|
-
import type { FastifyReply } from 'fastify';
|
|
13
|
-
import { type ApiError } from '@jini/protocol';
|
|
14
|
-
/** Writes `body` as JSON with the given status code. */
|
|
15
|
-
export declare function sendJson(reply: FastifyReply, status: number, body: unknown): void;
|
|
16
|
-
/** Writes an `ApiError`, wrapped in the standard `{ error }` envelope, with the given status code. */
|
|
17
|
-
export declare function sendApiError(reply: FastifyReply, status: number, error: ApiError): void;
|
|
18
|
-
/** Resolves the HTTP status to send for an `ApiError`, defaulting to 500 for unmapped codes. */
|
|
19
|
-
export declare function statusForError(error: ApiError): number;
|
|
20
|
-
//# sourceMappingURL=response.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"response.d.ts","sourceRoot":"","sources":["../../src/fastify/response.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAA0B,KAAK,QAAQ,EAAqB,MAAM,gBAAgB,CAAC;AAE1F,wDAAwD;AACxD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAEjF;AAED,sGAAsG;AACtG,wBAAgB,YAAY,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG,IAAI,CAEvF;AA8BD,gGAAgG;AAChG,wBAAgB,cAAc,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,CAEtD"}
|
package/dist/fastify/response.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { createApiErrorResponse } from '@jini/protocol';
|
|
2
|
-
/** Writes `body` as JSON with the given status code. */
|
|
3
|
-
export function sendJson(reply, status, body) {
|
|
4
|
-
reply.code(status).send(body);
|
|
5
|
-
}
|
|
6
|
-
/** Writes an `ApiError`, wrapped in the standard `{ error }` envelope, with the given status code. */
|
|
7
|
-
export function sendApiError(reply, status, error) {
|
|
8
|
-
reply.code(status).send(createApiErrorResponse(error));
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* @internal
|
|
12
|
-
* Default HTTP status per generic `ApiErrorCode`. Codes not listed here fall back to 500 in
|
|
13
|
-
* `statusForError` — deliberately conservative, since an unmapped code (including any
|
|
14
|
-
* product-specific code a consuming pack defines) is more likely a new server-side failure mode
|
|
15
|
-
* than a client error. Kept identical to `../express/response.ts`'s copy — see this file's
|
|
16
|
-
* top-of-module doc for why it is duplicated rather than imported.
|
|
17
|
-
*/
|
|
18
|
-
const ERROR_STATUS_BY_CODE = {
|
|
19
|
-
BAD_REQUEST: 400,
|
|
20
|
-
UNAUTHORIZED: 401,
|
|
21
|
-
FORBIDDEN: 403,
|
|
22
|
-
NOT_FOUND: 404,
|
|
23
|
-
CONFLICT: 409,
|
|
24
|
-
PAYLOAD_TOO_LARGE: 413,
|
|
25
|
-
UNSUPPORTED_MEDIA_TYPE: 415,
|
|
26
|
-
VALIDATION_FAILED: 422,
|
|
27
|
-
RATE_LIMITED: 429,
|
|
28
|
-
INTERNAL_ERROR: 500,
|
|
29
|
-
UPSTREAM_UNAVAILABLE: 502,
|
|
30
|
-
TOOL_TOKEN_MISSING: 401,
|
|
31
|
-
TOOL_TOKEN_INVALID: 401,
|
|
32
|
-
TOOL_TOKEN_EXPIRED: 401,
|
|
33
|
-
TOOL_ENDPOINT_DENIED: 403,
|
|
34
|
-
TOOL_OPERATION_DENIED: 403,
|
|
35
|
-
TOOL_NOT_AVAILABLE: 503,
|
|
36
|
-
};
|
|
37
|
-
/** Resolves the HTTP status to send for an `ApiError`, defaulting to 500 for unmapped codes. */
|
|
38
|
-
export function statusForError(error) {
|
|
39
|
-
return ERROR_STATUS_BY_CODE[error.code] ?? 500;
|
|
40
|
-
}
|
|
41
|
-
//# sourceMappingURL=response.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"response.js","sourceRoot":"","sources":["../../src/fastify/response.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,sBAAsB,EAAoC,MAAM,gBAAgB,CAAC;AAE1F,wDAAwD;AACxD,MAAM,UAAU,QAAQ,CAAC,KAAmB,EAAE,MAAc,EAAE,IAAa;IACzE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAChC,CAAC;AAED,sGAAsG;AACtG,MAAM,UAAU,YAAY,CAAC,KAAmB,EAAE,MAAc,EAAE,KAAe;IAC/E,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,KAAK,CAAC,CAAC,CAAC;AACzD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,oBAAoB,GAA0C;IAClE,WAAW,EAAE,GAAG;IAChB,YAAY,EAAE,GAAG;IACjB,SAAS,EAAE,GAAG;IACd,SAAS,EAAE,GAAG;IACd,QAAQ,EAAE,GAAG;IACb,iBAAiB,EAAE,GAAG;IACtB,sBAAsB,EAAE,GAAG;IAC3B,iBAAiB,EAAE,GAAG;IACtB,YAAY,EAAE,GAAG;IACjB,cAAc,EAAE,GAAG;IACnB,oBAAoB,EAAE,GAAG;IACzB,kBAAkB,EAAE,GAAG;IACvB,kBAAkB,EAAE,GAAG;IACvB,kBAAkB,EAAE,GAAG;IACvB,oBAAoB,EAAE,GAAG;IACzB,qBAAqB,EAAE,GAAG;IAC1B,kBAAkB,EAAE,GAAG;CACxB,CAAC;AAEF,gGAAgG;AAChG,MAAM,UAAU,cAAc,CAAC,KAAe;IAC5C,OAAO,oBAAoB,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC;AACjD,CAAC"}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module fastify/route-registration-guard
|
|
3
|
-
*
|
|
4
|
-
* Builds a queryable inventory of every route registered on a Fastify instance, and guards a
|
|
5
|
-
* caller-supplied set of "must register at most once" route keys against accidental duplicate
|
|
6
|
-
* registration — e.g. two packs each mounting `POST /api/runs` would otherwise silently shadow
|
|
7
|
-
* one another instead of failing loudly at composition time.
|
|
8
|
-
*
|
|
9
|
-
* Unlike the Express version (`../express/route-registration-guard.ts`, which monkey-patches
|
|
10
|
-
* `get`/`post`/etc. because Express has no first-class "a route was just registered" signal),
|
|
11
|
-
* Fastify exposes a built-in `onRoute` application hook that fires exactly once per registered
|
|
12
|
-
* route with the fully resolved `{ method, url }` — no monkey-patching needed. `guardedRouteKey`
|
|
13
|
-
* is deliberately duplicated (not imported) from the Express version; see
|
|
14
|
-
* `./response.ts`'s top-of-module doc for why this subtree does not import from `express/`.
|
|
15
|
-
*/
|
|
16
|
-
import type { FastifyInstance } from 'fastify';
|
|
17
|
-
/** One recorded route registration: the HTTP verb and the literal string path it was mounted on. */
|
|
18
|
-
export interface RouteRegistration {
|
|
19
|
-
method: string;
|
|
20
|
-
path: string;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Builds the `METHOD PATH` key used to check `guardedRouteKeys` membership.
|
|
24
|
-
*
|
|
25
|
-
* @param method - The HTTP method name (any case; normalized to upper-case in the key).
|
|
26
|
-
* @param path - The route's registered URL. Fastify's `onRoute` hook always supplies a string
|
|
27
|
-
* `url`, so (unlike the Express version) there is no non-string-path branch to guard against here.
|
|
28
|
-
* @param guardedRouteKeys - The set of `METHOD PATH` keys this call installed a duplicate-registration
|
|
29
|
-
* guard for.
|
|
30
|
-
* @returns The matching key if it is in `guardedRouteKeys`, otherwise `null`.
|
|
31
|
-
* @complexity O(1) — a single `Set` lookup.
|
|
32
|
-
* @overallScore 100/100
|
|
33
|
-
*/
|
|
34
|
-
export declare function guardedRouteKey(method: string, path: string, guardedRouteKeys: ReadonlySet<string>): string | null;
|
|
35
|
-
export interface InstallRouteRegistrationGuardOptions {
|
|
36
|
-
/** `METHOD PATH` keys (e.g. `'POST /api/runs'`) that must be registered at most once on `app`. Defaults to none — installing the guard with no options only builds the inventory, it enforces nothing. */
|
|
37
|
-
guardedRouteKeys?: ReadonlySet<string>;
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Registers a Fastify `onRoute` application hook that records every route registration into a
|
|
41
|
-
* per-app inventory (retrievable via {@link getRouteRegistrationInventory}) and throws if any
|
|
42
|
-
* `options.guardedRouteKeys` entry is registered a second time.
|
|
43
|
-
*
|
|
44
|
-
* A route registered for multiple HTTP methods at once (`method: ['GET', 'POST']`, or Fastify's
|
|
45
|
-
* own automatic `HEAD` sibling for a `GET` route when `exposeHeadRoute` is left at its default)
|
|
46
|
-
* produces one inventory entry and one guard check per method — mirroring how the Express version
|
|
47
|
-
* records one entry per distinct `app.get(...)`/`app.post(...)` call.
|
|
48
|
-
*
|
|
49
|
-
* @param app - The Fastify instance to instrument. Must not already have this guard installed
|
|
50
|
-
* (installing twice would double-register the `onRoute` hook and double-count the inventory — not
|
|
51
|
-
* guarded against here since every caller in this codebase calls this exactly once per app at
|
|
52
|
-
* composition time).
|
|
53
|
-
* @param options.guardedRouteKeys - See {@link InstallRouteRegistrationGuardOptions}.
|
|
54
|
-
* @returns Nothing — registers a hook on `app` and stashes its inventory under a well-known `Symbol.for` key.
|
|
55
|
-
* @throws If a `guardedRouteKeys` entry is registered more than once, at the moment of the second registration.
|
|
56
|
-
* @complexity O(1) setup; each `onRoute` firing is O(m) in the number of methods the route was registered for (typically 1).
|
|
57
|
-
* @overallScore 100/100
|
|
58
|
-
*/
|
|
59
|
-
export declare function installRouteRegistrationGuard(app: FastifyInstance, options?: InstallRouteRegistrationGuardOptions): void;
|
|
60
|
-
/**
|
|
61
|
-
* Reads back every route {@link installRouteRegistrationGuard} recorded for `app`.
|
|
62
|
-
*
|
|
63
|
-
* @param app - An app the guard was installed on. Safe to call on an app with no guard installed
|
|
64
|
-
* (returns an empty array rather than throwing).
|
|
65
|
-
* @returns A fresh array copy each call — the caller can never mutate the guard's own internal inventory through the returned reference.
|
|
66
|
-
* @complexity O(n) in the number of routes registered so far.
|
|
67
|
-
* @overallScore 100/100
|
|
68
|
-
*/
|
|
69
|
-
export declare function getRouteRegistrationInventory(app: FastifyInstance): RouteRegistration[];
|
|
70
|
-
//# sourceMappingURL=route-registration-guard.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"route-registration-guard.d.ts","sourceRoot":"","sources":["../../src/fastify/route-registration-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,oGAAoG;AACpG,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAID;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,gBAAgB,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,MAAM,GAAG,IAAI,CAGlH;AAED,MAAM,WAAW,oCAAoC;IACnD,0MAA0M;IAC1M,gBAAgB,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CACxC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,6BAA6B,CAC3C,GAAG,EAAE,eAAe,EACpB,OAAO,GAAE,oCAAyC,GACjD,IAAI,CAmBN;AAED;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,eAAe,GAAG,iBAAiB,EAAE,CAEvF"}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
const routeInventorySymbol = Symbol.for('jini.routeRegistrationGuard.inventory');
|
|
2
|
-
/**
|
|
3
|
-
* Builds the `METHOD PATH` key used to check `guardedRouteKeys` membership.
|
|
4
|
-
*
|
|
5
|
-
* @param method - The HTTP method name (any case; normalized to upper-case in the key).
|
|
6
|
-
* @param path - The route's registered URL. Fastify's `onRoute` hook always supplies a string
|
|
7
|
-
* `url`, so (unlike the Express version) there is no non-string-path branch to guard against here.
|
|
8
|
-
* @param guardedRouteKeys - The set of `METHOD PATH` keys this call installed a duplicate-registration
|
|
9
|
-
* guard for.
|
|
10
|
-
* @returns The matching key if it is in `guardedRouteKeys`, otherwise `null`.
|
|
11
|
-
* @complexity O(1) — a single `Set` lookup.
|
|
12
|
-
* @overallScore 100/100
|
|
13
|
-
*/
|
|
14
|
-
export function guardedRouteKey(method, path, guardedRouteKeys) {
|
|
15
|
-
const key = `${method.toUpperCase()} ${path}`;
|
|
16
|
-
return guardedRouteKeys.has(key) ? key : null;
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Registers a Fastify `onRoute` application hook that records every route registration into a
|
|
20
|
-
* per-app inventory (retrievable via {@link getRouteRegistrationInventory}) and throws if any
|
|
21
|
-
* `options.guardedRouteKeys` entry is registered a second time.
|
|
22
|
-
*
|
|
23
|
-
* A route registered for multiple HTTP methods at once (`method: ['GET', 'POST']`, or Fastify's
|
|
24
|
-
* own automatic `HEAD` sibling for a `GET` route when `exposeHeadRoute` is left at its default)
|
|
25
|
-
* produces one inventory entry and one guard check per method — mirroring how the Express version
|
|
26
|
-
* records one entry per distinct `app.get(...)`/`app.post(...)` call.
|
|
27
|
-
*
|
|
28
|
-
* @param app - The Fastify instance to instrument. Must not already have this guard installed
|
|
29
|
-
* (installing twice would double-register the `onRoute` hook and double-count the inventory — not
|
|
30
|
-
* guarded against here since every caller in this codebase calls this exactly once per app at
|
|
31
|
-
* composition time).
|
|
32
|
-
* @param options.guardedRouteKeys - See {@link InstallRouteRegistrationGuardOptions}.
|
|
33
|
-
* @returns Nothing — registers a hook on `app` and stashes its inventory under a well-known `Symbol.for` key.
|
|
34
|
-
* @throws If a `guardedRouteKeys` entry is registered more than once, at the moment of the second registration.
|
|
35
|
-
* @complexity O(1) setup; each `onRoute` firing is O(m) in the number of methods the route was registered for (typically 1).
|
|
36
|
-
* @overallScore 100/100
|
|
37
|
-
*/
|
|
38
|
-
export function installRouteRegistrationGuard(app, options = {}) {
|
|
39
|
-
const guardedRouteKeys = options.guardedRouteKeys ?? new Set();
|
|
40
|
-
const seen = new Set();
|
|
41
|
-
const inventory = [];
|
|
42
|
-
app[routeInventorySymbol] = inventory;
|
|
43
|
-
app.addHook('onRoute', (routeOptions) => {
|
|
44
|
-
const methods = Array.isArray(routeOptions.method) ? routeOptions.method : [routeOptions.method];
|
|
45
|
-
for (const method of methods) {
|
|
46
|
-
inventory.push({ method: method.toUpperCase(), path: routeOptions.url });
|
|
47
|
-
const key = guardedRouteKey(method, routeOptions.url, guardedRouteKeys);
|
|
48
|
-
if (key) {
|
|
49
|
-
if (seen.has(key)) {
|
|
50
|
-
throw new Error(`duplicate guarded route registration: ${key}`);
|
|
51
|
-
}
|
|
52
|
-
seen.add(key);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Reads back every route {@link installRouteRegistrationGuard} recorded for `app`.
|
|
59
|
-
*
|
|
60
|
-
* @param app - An app the guard was installed on. Safe to call on an app with no guard installed
|
|
61
|
-
* (returns an empty array rather than throwing).
|
|
62
|
-
* @returns A fresh array copy each call — the caller can never mutate the guard's own internal inventory through the returned reference.
|
|
63
|
-
* @complexity O(n) in the number of routes registered so far.
|
|
64
|
-
* @overallScore 100/100
|
|
65
|
-
*/
|
|
66
|
-
export function getRouteRegistrationInventory(app) {
|
|
67
|
-
return [...(app[routeInventorySymbol] ?? [])];
|
|
68
|
-
}
|
|
69
|
-
//# sourceMappingURL=route-registration-guard.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"route-registration-guard.js","sourceRoot":"","sources":["../../src/fastify/route-registration-guard.ts"],"names":[],"mappings":"AAuBA,MAAM,oBAAoB,GAAG,MAAM,CAAC,GAAG,CAAC,uCAAuC,CAAC,CAAC;AAEjF;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc,EAAE,IAAY,EAAE,gBAAqC;IACjG,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC;IAC9C,OAAO,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AAChD,CAAC;AAOD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,6BAA6B,CAC3C,GAAoB,EACpB,UAAgD,EAAE;IAElD,MAAM,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,IAAI,IAAI,GAAG,EAAU,CAAC;IACvE,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,SAAS,GAAwB,EAAE,CAAC;IACzC,GAAsD,CAAC,oBAAoB,CAAC,GAAG,SAAS,CAAC;IAE1F,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,YAAY,EAAE,EAAE;QACtC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QACjG,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,SAAS,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,YAAY,CAAC,GAAG,EAAE,CAAC,CAAC;YACzE,MAAM,GAAG,GAAG,eAAe,CAAC,MAAM,EAAE,YAAY,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;YACxE,IAAI,GAAG,EAAE,CAAC;gBACR,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;oBAClB,MAAM,IAAI,KAAK,CAAC,yCAAyC,GAAG,EAAE,CAAC,CAAC;gBAClE,CAAC;gBACD,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAChB,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,6BAA6B,CAAC,GAAoB;IAChE,OAAO,CAAC,GAAG,CAAE,GAAkE,CAAC,oBAAoB,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;AAChH,CAAC"}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module fastify/run-stream
|
|
3
|
-
*
|
|
4
|
-
* Fastify-specific mounting glue for the shared AG-UI SSE run-stream handler
|
|
5
|
-
* (`../run-stream.js`). `reply.raw`/`request.raw` give the exact underlying `http.ServerResponse`/
|
|
6
|
-
* `http.IncomingMessage` pair directly, so this file's only job is resolving the `runId` route
|
|
7
|
-
* param and handing those raw objects straight through — a few lines, not a reimplementation, per
|
|
8
|
-
* the design decision that motivated building the SSE primitive once instead of duplicating it
|
|
9
|
-
* per transport. `reply.hijack()` tells Fastify this handler is taking over the raw response
|
|
10
|
-
* itself, so Fastify's own reply lifecycle (which otherwise expects the handler to return a value
|
|
11
|
-
* for it to serialize, or call `reply.send(...)`) does not try to act on a response this handler
|
|
12
|
-
* already wrote to and ended directly.
|
|
13
|
-
*/
|
|
14
|
-
import type { FastifyInstance } from 'fastify';
|
|
15
|
-
import { type RunStreamDeps } from '../run-stream.js';
|
|
16
|
-
/** Mounts the AG-UI SSE run-stream route on `app`. A pack's `http(app, services)` calls this directly. */
|
|
17
|
-
export declare function registerRunStreamRoute(app: FastifyInstance, deps: RunStreamDeps): void;
|
|
18
|
-
//# sourceMappingURL=run-stream.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"run-stream.d.ts","sourceRoot":"","sources":["../../src/fastify/run-stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,eAAe,EAAgC,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAiD,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAErG,0GAA0G;AAC1G,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,eAAe,EAAE,IAAI,EAAE,aAAa,GAAG,IAAI,CAMtF"}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { handleRunStreamRequest, RUN_STREAM_ROUTE_PATH } from '../run-stream.js';
|
|
2
|
-
/** Mounts the AG-UI SSE run-stream route on `app`. A pack's `http(app, services)` calls this directly. */
|
|
3
|
-
export function registerRunStreamRoute(app, deps) {
|
|
4
|
-
app.get(RUN_STREAM_ROUTE_PATH, async (request, reply) => {
|
|
5
|
-
reply.hijack();
|
|
6
|
-
const runId = request.params.runId;
|
|
7
|
-
await handleRunStreamRequest(request.raw, reply.raw, runId, deps);
|
|
8
|
-
});
|
|
9
|
-
}
|
|
10
|
-
//# sourceMappingURL=run-stream.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"run-stream.js","sourceRoot":"","sources":["../../src/fastify/run-stream.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAsB,MAAM,kBAAkB,CAAC;AAErG,0GAA0G;AAC1G,MAAM,UAAU,sBAAsB,CAAC,GAAoB,EAAE,IAAmB;IAC9E,GAAG,CAAC,GAAG,CAAC,qBAAqB,EAAE,KAAK,EAAE,OAAuB,EAAE,KAAmB,EAAE,EAAE;QACpF,KAAK,CAAC,MAAM,EAAE,CAAC;QACf,MAAM,KAAK,GAAI,OAAO,CAAC,MAA4B,CAAC,KAAK,CAAC;QAC1D,MAAM,sBAAsB,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/fastify/runs.d.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module fastify/runs
|
|
3
|
-
*
|
|
4
|
-
* Fastify-mounting glue for `../runs.js`'s route logic — every `JsonRouteSpec` (`runStartRoute`,
|
|
5
|
-
* `runListRoute`, `runStatusRoute`, `runCancelRoute`) and the SSE event-stream core
|
|
6
|
-
* (`handleRunEventStreamRequest`) are the exact same functions the Express mounting in `../runs.js`
|
|
7
|
-
* uses; nothing here re-implements route logic, only how a request reaches it and a response
|
|
8
|
-
* leaves it, mirroring the rest of this `fastify/` subtree.
|
|
9
|
-
*/
|
|
10
|
-
import type { FastifyInstance } from 'fastify';
|
|
11
|
-
import type { RunHttpDeps } from '../runs.js';
|
|
12
|
-
import { type AdapterContext } from './adapter.js';
|
|
13
|
-
/** Mounts `GET /api/runs/:runId/events` on `app` via Fastify's native `route()` (matching `mountJsonRoute`'s own registration mechanism, unlike `fastify/run-stream.ts`'s `.get()` shorthand — kept consistent within this file since `registerRunRoutes` below mounts both through the same `app`), hijacking the reply so `handleRunEventStreamRequest` can write the raw SSE stream directly. */
|
|
14
|
-
export declare function registerRunEventStream(app: FastifyInstance, deps: RunHttpDeps): void;
|
|
15
|
-
/** Mounts create/status/cancel JSON endpoints and the SSE event stream as one run transport — the Fastify-native equivalent of `../runs.js`'s `registerRunRoutes`, mounting the identical `JsonRouteSpec` objects. */
|
|
16
|
-
export declare function registerRunRoutes(app: FastifyInstance, deps: RunHttpDeps, adapter: AdapterContext): void;
|
|
17
|
-
//# sourceMappingURL=runs.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"runs.d.ts","sourceRoot":"","sources":["../../src/fastify/runs.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,eAAe,EAAgC,MAAM,SAAS,CAAC;AAC7E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,OAAO,EAAkB,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAWnE,oYAAoY;AACpY,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,eAAe,EAAE,IAAI,EAAE,WAAW,GAAG,IAAI,CAWpF;AAED,sNAAsN;AACtN,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,eAAe,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,GAAG,IAAI,CAMxG"}
|
package/dist/fastify/runs.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { handleRunEventStreamRequest, runCancelRoute, runListRoute, runStartRoute, runStatusRoute } from '../runs.js';
|
|
2
|
-
import { mountJsonRoute } from './adapter.js';
|
|
3
|
-
/** Reads a reconnect cursor from the `Last-Event-ID` header, falling back to an `afterCursor` query parameter — the Fastify-request-shaped equivalent of `../sse.js`'s `requestedAfterCursor` (Fastify already parses both `.headers` and `.query` for us, so no Express-`Request`-shaped adapter object is needed here). */
|
|
4
|
-
function requestedAfterCursorFastify(request) {
|
|
5
|
-
const header = request.headers['last-event-id'];
|
|
6
|
-
const headerValue = Array.isArray(header) ? header[0] : header;
|
|
7
|
-
if (headerValue !== undefined && headerValue.length > 0)
|
|
8
|
-
return headerValue;
|
|
9
|
-
const query = request.query?.afterCursor;
|
|
10
|
-
return typeof query === 'string' && query.length > 0 ? query : null;
|
|
11
|
-
}
|
|
12
|
-
/** Mounts `GET /api/runs/:runId/events` on `app` via Fastify's native `route()` (matching `mountJsonRoute`'s own registration mechanism, unlike `fastify/run-stream.ts`'s `.get()` shorthand — kept consistent within this file since `registerRunRoutes` below mounts both through the same `app`), hijacking the reply so `handleRunEventStreamRequest` can write the raw SSE stream directly. */
|
|
13
|
-
export function registerRunEventStream(app, deps) {
|
|
14
|
-
app.route({
|
|
15
|
-
method: 'GET',
|
|
16
|
-
url: '/api/runs/:runId/events',
|
|
17
|
-
exposeHeadRoute: false,
|
|
18
|
-
handler: async (request, reply) => {
|
|
19
|
-
reply.hijack();
|
|
20
|
-
const runId = request.params.runId ?? '';
|
|
21
|
-
await handleRunEventStreamRequest(reply.raw, runId, requestedAfterCursorFastify(request), deps);
|
|
22
|
-
},
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
/** Mounts create/status/cancel JSON endpoints and the SSE event stream as one run transport — the Fastify-native equivalent of `../runs.js`'s `registerRunRoutes`, mounting the identical `JsonRouteSpec` objects. */
|
|
26
|
-
export function registerRunRoutes(app, deps, adapter) {
|
|
27
|
-
mountJsonRoute(app, runStartRoute, deps, adapter);
|
|
28
|
-
mountJsonRoute(app, runListRoute, deps, adapter);
|
|
29
|
-
mountJsonRoute(app, runStatusRoute, deps, adapter);
|
|
30
|
-
mountJsonRoute(app, runCancelRoute, deps, adapter);
|
|
31
|
-
registerRunEventStream(app, deps);
|
|
32
|
-
}
|
|
33
|
-
//# sourceMappingURL=runs.js.map
|
package/dist/fastify/runs.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"runs.js","sourceRoot":"","sources":["../../src/fastify/runs.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,2BAA2B,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACtH,OAAO,EAAE,cAAc,EAAuB,MAAM,cAAc,CAAC;AAEnE,6TAA6T;AAC7T,SAAS,2BAA2B,CAAC,OAAuB;IAC1D,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IAChD,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAC/D,IAAI,WAAW,KAAK,SAAS,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,WAAW,CAAC;IAC5E,MAAM,KAAK,GAAI,OAAO,CAAC,KAA6C,EAAE,WAAW,CAAC;IAClF,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACtE,CAAC;AAED,oYAAoY;AACpY,MAAM,UAAU,sBAAsB,CAAC,GAAoB,EAAE,IAAiB;IAC5E,GAAG,CAAC,KAAK,CAAC;QACR,MAAM,EAAE,KAAK;QACb,GAAG,EAAE,yBAAyB;QAC9B,eAAe,EAAE,KAAK;QACtB,OAAO,EAAE,KAAK,EAAE,OAAuB,EAAE,KAAmB,EAAE,EAAE;YAC9D,KAAK,CAAC,MAAM,EAAE,CAAC;YACf,MAAM,KAAK,GAAI,OAAO,CAAC,MAA6B,CAAC,KAAK,IAAI,EAAE,CAAC;YACjE,MAAM,2BAA2B,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,EAAE,2BAA2B,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC;QAClG,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,sNAAsN;AACtN,MAAM,UAAU,iBAAiB,CAAC,GAAoB,EAAE,IAAiB,EAAE,OAAuB;IAChG,cAAc,CAAC,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAClD,cAAc,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACjD,cAAc,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACnD,cAAc,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACnD,sBAAsB,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;AACpC,CAAC"}
|
package/dist/run-stream.d.ts
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module run-stream
|
|
3
|
-
*
|
|
4
|
-
* An encoder-driven SSE run-stream route: subscribes to a run via `@jini-ai/daemon`'s
|
|
5
|
-
* `RunLifecycle.stream`, pipes every event through a composition-root-supplied protocol encoder,
|
|
6
|
-
* and writes each non-null event to the SSE response opened by `createSseResponse`.
|
|
7
|
-
* `handleRunStreamRequest` is the core
|
|
8
|
-
* — it only ever touches `node:http`'s `IncomingMessage`/`ServerResponse` — and
|
|
9
|
-
* `registerRunStreamRoute` below is Express's own thin mounting glue (Express's `Request`/
|
|
10
|
-
* `Response` already *are* Node's raw `http.IncomingMessage`/`http.ServerResponse`, so resolving
|
|
11
|
-
* `req.params.runId` and handing the request/response straight through is the whole job).
|
|
12
|
-
*/
|
|
13
|
-
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
14
|
-
import type { RunLifecycle } from '@jini-ai/daemon';
|
|
15
|
-
import type { RunProtocolEvent } from '@jini-ai/protocol';
|
|
16
|
-
import type { Express } from 'express';
|
|
17
|
-
/** Backward-compatible route path used by the AG-UI composition. The handler itself is encoder-agnostic. */
|
|
18
|
-
export declare const RUN_STREAM_ROUTE_PATH = "/api/runs/:runId/agui-stream";
|
|
19
|
-
export interface RunStreamEncoder {
|
|
20
|
-
encode(event: RunProtocolEvent, context: {
|
|
21
|
-
readonly runId: string;
|
|
22
|
-
}): unknown | null;
|
|
23
|
-
}
|
|
24
|
-
export interface RunStreamInternalErrorContext {
|
|
25
|
-
readonly source: 'encoder' | 'lifecycle' | 'route';
|
|
26
|
-
readonly runId: string;
|
|
27
|
-
readonly error: unknown;
|
|
28
|
-
}
|
|
29
|
-
export interface RunStreamDeps {
|
|
30
|
-
readonly lifecycle: RunLifecycle;
|
|
31
|
-
/** Protocol adapter supplied by the composition root (for example `createGenUiEncoder()`). */
|
|
32
|
-
readonly encoder: RunStreamEncoder;
|
|
33
|
-
/** Host-owned sink for failures that must not escape an async Express handler. Defaults to `console.error`. */
|
|
34
|
-
readonly onInternalError?: (context: RunStreamInternalErrorContext) => void;
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Handles one encoded SSE run-stream request end to end. Opens the SSE connection immediately (an
|
|
38
|
-
* SSE endpoint commits to `text/event-stream` headers before it can know whether `runId` is
|
|
39
|
-
* valid), then subscribes to the run: a replay-then-live-subscribe `unknown-run`/`replay-gap`/
|
|
40
|
-
* `invalid-cursor` result is reported as one `{ error }` SSE data event before closing (there is
|
|
41
|
-
* no JSON-status-code channel left once SSE headers are already committed). On the happy path,
|
|
42
|
-
* every event `RunLifecycle` delivers is encoded and forwarded; the connection closes itself once
|
|
43
|
-
* the run's own terminal `'end'` event has been forwarded (a driver's contract with
|
|
44
|
-
* `RunLifecycle` guarantees no further events follow a run's `'end')`, so nothing is lost by
|
|
45
|
-
* closing right after it). If the client disconnects first, `createSseResponse`'s own
|
|
46
|
-
* `req.on('close', ...)` fires first, which (via `onClose` here) unsubscribes from the run so a
|
|
47
|
-
* disconnected client never leaves a dangling `RunLifecycle` subscriber.
|
|
48
|
-
*
|
|
49
|
-
* @param req - The raw request `createSseResponse` opens the stream against.
|
|
50
|
-
* @param res - The raw response `createSseResponse` opens the stream against.
|
|
51
|
-
* @param runId - The run to stream, already resolved by the caller's transport-specific glue.
|
|
52
|
-
* @param deps.lifecycle - The `RunLifecycle` to subscribe to.
|
|
53
|
-
* @param deps.encoder - The protocol adapter chosen by the composition root.
|
|
54
|
-
* @complexity O(1) plus the supplied encoder's per-event cost and `RunLifecycle.stream`'s replay cost.
|
|
55
|
-
* @overallScore 100/100
|
|
56
|
-
*/
|
|
57
|
-
export declare function handleRunStreamRequest(req: IncomingMessage, res: ServerResponse, runId: string, deps: RunStreamDeps): Promise<void>;
|
|
58
|
-
/** Mounts the encoder-driven SSE run-stream route on `app`. */
|
|
59
|
-
export declare function registerRunStreamRoute(app: Express, deps: RunStreamDeps): void;
|
|
60
|
-
//# sourceMappingURL=run-stream.d.ts.map
|
package/dist/run-stream.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"run-stream.d.ts","sourceRoot":"","sources":["../src/run-stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAyB,MAAM,iBAAiB,CAAC;AAC3E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,KAAK,EAAE,OAAO,EAAqB,MAAM,SAAS,CAAC;AAG1D,4GAA4G;AAC5G,eAAO,MAAM,qBAAqB,iCAAiC,CAAC;AAEpE,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,GAAG,IAAI,CAAC;CACtF;AAED,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,OAAO,CAAC;IACnD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC;IACjC,8FAA8F;IAC9F,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC;IACnC,+GAA+G;IAC/G,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,6BAA6B,KAAK,IAAI,CAAC;CAC7E;AAwBD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,IAAI,CAAC,CAuCf;AAED,+DAA+D;AAC/D,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,GAAG,IAAI,CAiB9E"}
|
package/dist/run-stream.js
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import { createSseResponse } from './raw-sse.js';
|
|
2
|
-
/** Backward-compatible route path used by the AG-UI composition. The handler itself is encoder-agnostic. */
|
|
3
|
-
export const RUN_STREAM_ROUTE_PATH = '/api/runs/:runId/agui-stream';
|
|
4
|
-
function reportRunStreamInternalError(deps, source, runId, error) {
|
|
5
|
-
const context = { source, runId, error };
|
|
6
|
-
try {
|
|
7
|
-
if (deps.onInternalError) {
|
|
8
|
-
deps.onInternalError(context);
|
|
9
|
-
}
|
|
10
|
-
else {
|
|
11
|
-
// eslint-disable-next-line no-console
|
|
12
|
-
console.error(`[@jini-ai/http-kit] internal error (run-stream:${source}, runId=${runId})`, error);
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
catch (sinkError) {
|
|
16
|
-
// A diagnostic sink must never turn an already-contained stream failure into an unhandled
|
|
17
|
-
// rejection of its own.
|
|
18
|
-
// eslint-disable-next-line no-console
|
|
19
|
-
console.error(`[@jini-ai/http-kit] internal error sink failed (run-stream:${source}, runId=${runId})`, sinkError);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Handles one encoded SSE run-stream request end to end. Opens the SSE connection immediately (an
|
|
24
|
-
* SSE endpoint commits to `text/event-stream` headers before it can know whether `runId` is
|
|
25
|
-
* valid), then subscribes to the run: a replay-then-live-subscribe `unknown-run`/`replay-gap`/
|
|
26
|
-
* `invalid-cursor` result is reported as one `{ error }` SSE data event before closing (there is
|
|
27
|
-
* no JSON-status-code channel left once SSE headers are already committed). On the happy path,
|
|
28
|
-
* every event `RunLifecycle` delivers is encoded and forwarded; the connection closes itself once
|
|
29
|
-
* the run's own terminal `'end'` event has been forwarded (a driver's contract with
|
|
30
|
-
* `RunLifecycle` guarantees no further events follow a run's `'end')`, so nothing is lost by
|
|
31
|
-
* closing right after it). If the client disconnects first, `createSseResponse`'s own
|
|
32
|
-
* `req.on('close', ...)` fires first, which (via `onClose` here) unsubscribes from the run so a
|
|
33
|
-
* disconnected client never leaves a dangling `RunLifecycle` subscriber.
|
|
34
|
-
*
|
|
35
|
-
* @param req - The raw request `createSseResponse` opens the stream against.
|
|
36
|
-
* @param res - The raw response `createSseResponse` opens the stream against.
|
|
37
|
-
* @param runId - The run to stream, already resolved by the caller's transport-specific glue.
|
|
38
|
-
* @param deps.lifecycle - The `RunLifecycle` to subscribe to.
|
|
39
|
-
* @param deps.encoder - The protocol adapter chosen by the composition root.
|
|
40
|
-
* @complexity O(1) plus the supplied encoder's per-event cost and `RunLifecycle.stream`'s replay cost.
|
|
41
|
-
* @overallScore 100/100
|
|
42
|
-
*/
|
|
43
|
-
export async function handleRunStreamRequest(req, res, runId, deps) {
|
|
44
|
-
let unsubscribe;
|
|
45
|
-
const connection = createSseResponse(req, res, {
|
|
46
|
-
onClose: () => unsubscribe?.(),
|
|
47
|
-
});
|
|
48
|
-
const encoder = deps.encoder;
|
|
49
|
-
let result;
|
|
50
|
-
try {
|
|
51
|
-
result = await deps.lifecycle.stream(runId, (event) => {
|
|
52
|
-
if (connection.closed)
|
|
53
|
-
return;
|
|
54
|
-
try {
|
|
55
|
-
const encoded = encoder.encode(event, { runId });
|
|
56
|
-
if (encoded != null)
|
|
57
|
-
connection.send(encoded);
|
|
58
|
-
if (event.kind === 'end')
|
|
59
|
-
connection.close();
|
|
60
|
-
}
|
|
61
|
-
catch (error) {
|
|
62
|
-
reportRunStreamInternalError(deps, 'encoder', runId, error);
|
|
63
|
-
connection.close();
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
catch (error) {
|
|
68
|
-
reportRunStreamInternalError(deps, 'lifecycle', runId, error);
|
|
69
|
-
connection.close();
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
if (result.kind !== 'ok') {
|
|
73
|
-
connection.send({ error: result.kind });
|
|
74
|
-
connection.close();
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
// Assigned even when the run was already terminal (in which case the driver-facing 'end' event
|
|
78
|
-
// was already replayed synchronously above, already closing the connection, and `unsubscribe`
|
|
79
|
-
// here is `RunLifecycle`'s own no-op stub for that case) — keeping this assignment unconditional
|
|
80
|
-
// avoids a branch whose two arms would otherwise do the same thing.
|
|
81
|
-
unsubscribe = result.unsubscribe;
|
|
82
|
-
// The raw request can close while RunLifecycle is still awaiting durable replay. In that
|
|
83
|
-
// window `onClose` runs before `unsubscribe` exists, so clean up immediately once it arrives.
|
|
84
|
-
if (connection.closed)
|
|
85
|
-
unsubscribe();
|
|
86
|
-
}
|
|
87
|
-
/** Mounts the encoder-driven SSE run-stream route on `app`. */
|
|
88
|
-
export function registerRunStreamRoute(app, deps) {
|
|
89
|
-
app.get(RUN_STREAM_ROUTE_PATH, async (req, res) => {
|
|
90
|
-
// `:runId` is a required path segment of RUN_STREAM_ROUTE_PATH — this handler is only ever
|
|
91
|
-
// reached via a URL that already matched it, so the param is always present at runtime even
|
|
92
|
-
// though @types/express types every param as possibly `undefined` in general.
|
|
93
|
-
const runId = req.params.runId;
|
|
94
|
-
try {
|
|
95
|
-
await handleRunStreamRequest(req, res, runId, deps);
|
|
96
|
-
}
|
|
97
|
-
catch (error) {
|
|
98
|
-
reportRunStreamInternalError(deps, 'route', runId, error);
|
|
99
|
-
if (!res.headersSent) {
|
|
100
|
-
res.status(500).json({ error: { code: 'INTERNAL_ERROR', message: 'an internal error occurred' } });
|
|
101
|
-
}
|
|
102
|
-
else if (!res.writableEnded) {
|
|
103
|
-
res.end();
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
//# sourceMappingURL=run-stream.js.map
|
package/dist/run-stream.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"run-stream.js","sourceRoot":"","sources":["../src/run-stream.ts"],"names":[],"mappings":"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"}
|