@astrale-os/kernel-server 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app/create.d.ts +48 -0
- package/dist/app/create.d.ts.map +1 -0
- package/dist/app/create.js +107 -0
- package/dist/app/create.js.map +1 -0
- package/dist/app/index.d.ts +4 -0
- package/dist/app/index.d.ts.map +1 -0
- package/dist/app/index.js +4 -0
- package/dist/app/index.js.map +1 -0
- package/dist/app/multiplexed.d.ts +53 -0
- package/dist/app/multiplexed.d.ts.map +1 -0
- package/dist/app/multiplexed.js +63 -0
- package/dist/app/multiplexed.js.map +1 -0
- package/dist/app/ws-upgrade.d.ts +35 -0
- package/dist/app/ws-upgrade.d.ts.map +1 -0
- package/dist/app/ws-upgrade.js +93 -0
- package/dist/app/ws-upgrade.js.map +1 -0
- package/dist/cors.d.ts +21 -0
- package/dist/cors.d.ts.map +1 -0
- package/dist/cors.js +17 -0
- package/dist/cors.js.map +1 -0
- package/dist/envelope/batch.d.ts +12 -0
- package/dist/envelope/batch.d.ts.map +1 -0
- package/dist/envelope/batch.js +90 -0
- package/dist/envelope/batch.js.map +1 -0
- package/dist/envelope/codec.d.ts +26 -0
- package/dist/envelope/codec.d.ts.map +1 -0
- package/dist/envelope/codec.js +52 -0
- package/dist/envelope/codec.js.map +1 -0
- package/dist/envelope/credential.d.ts +20 -0
- package/dist/envelope/credential.d.ts.map +1 -0
- package/dist/envelope/credential.js +32 -0
- package/dist/envelope/credential.js.map +1 -0
- package/dist/envelope/http.d.ts +30 -0
- package/dist/envelope/http.d.ts.map +1 -0
- package/dist/envelope/http.js +128 -0
- package/dist/envelope/http.js.map +1 -0
- package/dist/envelope/index.d.ts +6 -0
- package/dist/envelope/index.d.ts.map +1 -0
- package/dist/envelope/index.js +6 -0
- package/dist/envelope/index.js.map +1 -0
- package/dist/envelope/sse.d.ts +11 -0
- package/dist/envelope/sse.d.ts.map +1 -0
- package/dist/envelope/sse.js +73 -0
- package/dist/envelope/sse.js.map +1 -0
- package/dist/envelope/ws.d.ts +32 -0
- package/dist/envelope/ws.d.ts.map +1 -0
- package/dist/envelope/ws.js +136 -0
- package/dist/envelope/ws.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/jwks/discovery.d.ts +40 -0
- package/dist/jwks/discovery.d.ts.map +1 -0
- package/dist/jwks/discovery.js +113 -0
- package/dist/jwks/discovery.js.map +1 -0
- package/dist/jwks/index.d.ts +3 -0
- package/dist/jwks/index.d.ts.map +1 -0
- package/dist/jwks/index.js +3 -0
- package/dist/jwks/index.js.map +1 -0
- package/dist/jwks/issuers.d.ts +47 -0
- package/dist/jwks/issuers.d.ts.map +1 -0
- package/dist/jwks/issuers.js +76 -0
- package/dist/jwks/issuers.js.map +1 -0
- package/dist/jwks/keys.d.ts +44 -0
- package/dist/jwks/keys.d.ts.map +1 -0
- package/dist/jwks/keys.js +56 -0
- package/dist/jwks/keys.js.map +1 -0
- package/dist/plan/host-params.d.ts +13 -0
- package/dist/plan/host-params.d.ts.map +1 -0
- package/dist/plan/host-params.js +23 -0
- package/dist/plan/host-params.js.map +1 -0
- package/dist/plan/host.d.ts +24 -0
- package/dist/plan/host.d.ts.map +1 -0
- package/dist/plan/host.js +24 -0
- package/dist/plan/host.js.map +1 -0
- package/dist/plan/index.d.ts +4 -0
- package/dist/plan/index.d.ts.map +1 -0
- package/dist/plan/index.js +4 -0
- package/dist/plan/index.js.map +1 -0
- package/dist/plan/walk.d.ts +51 -0
- package/dist/plan/walk.d.ts.map +1 -0
- package/dist/plan/walk.js +110 -0
- package/dist/plan/walk.js.map +1 -0
- package/dist/render/binary.d.ts +19 -0
- package/dist/render/binary.d.ts.map +1 -0
- package/dist/render/binary.js +33 -0
- package/dist/render/binary.js.map +1 -0
- package/dist/render/body.d.ts +10 -0
- package/dist/render/body.d.ts.map +1 -0
- package/dist/render/body.js +17 -0
- package/dist/render/body.js.map +1 -0
- package/dist/render/index.d.ts +3 -0
- package/dist/render/index.d.ts.map +1 -0
- package/dist/render/index.js +3 -0
- package/dist/render/index.js.map +1 -0
- package/dist/routed/credential.d.ts +10 -0
- package/dist/routed/credential.d.ts.map +1 -0
- package/dist/routed/credential.js +55 -0
- package/dist/routed/credential.js.map +1 -0
- package/dist/routed/handler.d.ts +36 -0
- package/dist/routed/handler.d.ts.map +1 -0
- package/dist/routed/handler.js +119 -0
- package/dist/routed/handler.js.map +1 -0
- package/dist/routed/index.d.ts +5 -0
- package/dist/routed/index.d.ts.map +1 -0
- package/dist/routed/index.js +5 -0
- package/dist/routed/index.js.map +1 -0
- package/dist/routed/params.d.ts +40 -0
- package/dist/routed/params.d.ts.map +1 -0
- package/dist/routed/params.js +146 -0
- package/dist/routed/params.js.map +1 -0
- package/dist/routed/stream.d.ts +21 -0
- package/dist/routed/stream.d.ts.map +1 -0
- package/dist/routed/stream.js +69 -0
- package/dist/routed/stream.js.map +1 -0
- package/package.json +45 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createKernelApp — Hono app builder for the kernel protocol.
|
|
3
|
+
*
|
|
4
|
+
* Walks a domain of MountableContract and mounts:
|
|
5
|
+
* - kernel HTTP envelope (POST) at each base URL
|
|
6
|
+
* - native HTTP routes per route binding
|
|
7
|
+
* - kernel WS upgrade at the same base URL when transports includes 'ws'
|
|
8
|
+
*
|
|
9
|
+
* Codecs are hardcoded (json + msgpack). Credentials for kernel HTTP are
|
|
10
|
+
* fixed to the Authorization header; route bindings can override via
|
|
11
|
+
* `route.credential`.
|
|
12
|
+
*/
|
|
13
|
+
import type { KernelAPI } from '@astrale-os/kernel-api';
|
|
14
|
+
import type { MountableContract } from '@astrale-os/kernel-api/routed';
|
|
15
|
+
import type { Hono } from 'hono';
|
|
16
|
+
import type { CorsConfig } from '../cors';
|
|
17
|
+
import type { JwksKeys } from '../jwks';
|
|
18
|
+
import type { MountPlan, ServerHost } from '../plan';
|
|
19
|
+
import { type WsAdapter } from './ws-upgrade';
|
|
20
|
+
export type { WsAdapter };
|
|
21
|
+
export type KernelAppConfig = {
|
|
22
|
+
/** The kernel runtime handling dispatch. */
|
|
23
|
+
kernel: KernelAPI;
|
|
24
|
+
/** The domain's mountable contracts — produced by defineMethods(schema, methods). */
|
|
25
|
+
domain: MountableContract[];
|
|
26
|
+
/** Server host URL. Functions anchor against this (ambient functions mount here). */
|
|
27
|
+
host: ServerHost;
|
|
28
|
+
/** Required — OpenID Connect Discovery + JWKS endpoints. */
|
|
29
|
+
jwks: JwksKeys;
|
|
30
|
+
/** Allowed transports. 'http' is mandatory. 'ws' is opt-in. */
|
|
31
|
+
transports?: readonly ('http' | 'ws')[];
|
|
32
|
+
/** CORS configuration. Defaults to { origin: '*' }. */
|
|
33
|
+
cors?: CorsConfig;
|
|
34
|
+
/** Optional health endpoint path (defaults to '/health'; false disables). */
|
|
35
|
+
health?: string | false;
|
|
36
|
+
/** Pre-created Hono app (for attaching to an existing app). */
|
|
37
|
+
app?: Hono;
|
|
38
|
+
/**
|
|
39
|
+
* Runtime-specific WS adapter (from `hono/bun`, `@hono/node-ws`, `hono/deno`).
|
|
40
|
+
* Required when `transports` includes `'ws'`.
|
|
41
|
+
*/
|
|
42
|
+
ws?: WsAdapter;
|
|
43
|
+
};
|
|
44
|
+
export declare function createKernelApp(config: KernelAppConfig): {
|
|
45
|
+
app: Hono;
|
|
46
|
+
plan: MountPlan;
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=create.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../app/create.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AACvD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAA;AACtE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAIhC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACzC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AACvC,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAMpD,OAAO,EAAiB,KAAK,SAAS,EAAE,MAAM,cAAc,CAAA;AAE5D,YAAY,EAAE,SAAS,EAAE,CAAA;AAIzB,MAAM,MAAM,eAAe,GAAG;IAC5B,4CAA4C;IAC5C,MAAM,EAAE,SAAS,CAAA;IACjB,qFAAqF;IACrF,MAAM,EAAE,iBAAiB,EAAE,CAAA;IAC3B,qFAAqF;IACrF,IAAI,EAAE,UAAU,CAAA;IAChB,4DAA4D;IAC5D,IAAI,EAAE,QAAQ,CAAA;IACd,+DAA+D;IAC/D,UAAU,CAAC,EAAE,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAA;IACvC,uDAAuD;IACvD,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,CAAA;IACvB,+DAA+D;IAC/D,GAAG,CAAC,EAAE,IAAI,CAAA;IACV;;;OAGG;IACH,EAAE,CAAC,EAAE,SAAS,CAAA;CACf,CAAA;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG;IAAE,GAAG,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,SAAS,CAAA;CAAE,CA2FvF"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createKernelApp — Hono app builder for the kernel protocol.
|
|
3
|
+
*
|
|
4
|
+
* Walks a domain of MountableContract and mounts:
|
|
5
|
+
* - kernel HTTP envelope (POST) at each base URL
|
|
6
|
+
* - native HTTP routes per route binding
|
|
7
|
+
* - kernel WS upgrade at the same base URL when transports includes 'ws'
|
|
8
|
+
*
|
|
9
|
+
* Codecs are hardcoded (json + msgpack). Credentials for kernel HTTP are
|
|
10
|
+
* fixed to the Authorization header; route bindings can override via
|
|
11
|
+
* `route.credential`.
|
|
12
|
+
*/
|
|
13
|
+
import { Hono as HonoCtor } from 'hono';
|
|
14
|
+
import { createKernelDispatcher } from '../envelope/http';
|
|
15
|
+
import { mountJwks } from '../jwks/keys';
|
|
16
|
+
import { extractHostParams, walkDomain } from '../plan';
|
|
17
|
+
import { createRouteHandler } from '../routed/handler';
|
|
18
|
+
import { mountKernelWs } from './ws-upgrade';
|
|
19
|
+
const DEFAULT_CORS = { origin: '*' };
|
|
20
|
+
export function createKernelApp(config) {
|
|
21
|
+
const cors = config.cors ?? DEFAULT_CORS;
|
|
22
|
+
const app = config.app ?? new HonoCtor();
|
|
23
|
+
const transports = config.transports ?? ['http'];
|
|
24
|
+
if (!transports.includes('http')) {
|
|
25
|
+
throw new Error(`createKernelApp: transports must include 'http'`);
|
|
26
|
+
}
|
|
27
|
+
// 1. Walk domain → compute mount plan.
|
|
28
|
+
const plan = walkDomain(config.domain, config.host);
|
|
29
|
+
// 2. JWKS (always mounted).
|
|
30
|
+
mountJwks(app, { ...config.jwks, cors });
|
|
31
|
+
// 3. Health endpoint.
|
|
32
|
+
if (config.health !== false) {
|
|
33
|
+
app.get(config.health ?? '/health', (c) => c.json({ status: 'ok' }));
|
|
34
|
+
}
|
|
35
|
+
// 4. Kernel HTTP mounts — POST envelope at each unique base path.
|
|
36
|
+
// Because ambient functions all share the server's base path, and
|
|
37
|
+
// anchored functions re-use the same host, nearly always there's just
|
|
38
|
+
// one base path. For multi-domain servers with different remoteUrl
|
|
39
|
+
// base paths, we create one mount per path.
|
|
40
|
+
const hostParams = plan.hostMatcher
|
|
41
|
+
? (req) => extractHostParams(plan.hostMatcher, req)
|
|
42
|
+
: undefined;
|
|
43
|
+
const dispatcher = createKernelDispatcher(cors, { hostParams });
|
|
44
|
+
const basePaths = new Set();
|
|
45
|
+
for (const basePath of plan.kernelMounts.keys()) {
|
|
46
|
+
basePaths.add(basePath === '' ? '/' : basePath);
|
|
47
|
+
}
|
|
48
|
+
if (basePaths.size === 0)
|
|
49
|
+
basePaths.add('/');
|
|
50
|
+
// 4a. WS upgrade (HTTP GET with Upgrade header) at each base path.
|
|
51
|
+
if (transports.includes('ws')) {
|
|
52
|
+
if (!config.ws) {
|
|
53
|
+
throw new Error(`createKernelApp: transports includes 'ws' but no WS adapter was passed. ` +
|
|
54
|
+
`Pass { ws: { upgradeWebSocket } } from your runtime's Hono adapter ` +
|
|
55
|
+
`(hono/bun, @hono/node-ws, hono/deno).`);
|
|
56
|
+
}
|
|
57
|
+
for (const wsPath of basePaths) {
|
|
58
|
+
mountKernelWs(app, wsPath, config.ws, config.kernel);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// 4b. HTTP POST envelope + OPTIONS preflight for each base path.
|
|
62
|
+
for (const path of basePaths) {
|
|
63
|
+
app.post(path, (c) => dispatcher(c.req.raw, config.kernel));
|
|
64
|
+
app.options(path, (c) => dispatcher(c.req.raw, config.kernel));
|
|
65
|
+
}
|
|
66
|
+
// 6. Route bindings — one Hono handler per mounted route.
|
|
67
|
+
for (const mountedRoute of plan.routes) {
|
|
68
|
+
const { route, fullPath } = mountedRoute;
|
|
69
|
+
const honoPath = toHonoPath(fullPath);
|
|
70
|
+
const handler = createRouteHandler({
|
|
71
|
+
method: mountedRoute.contract.ref,
|
|
72
|
+
route,
|
|
73
|
+
kernel: config.kernel,
|
|
74
|
+
cors,
|
|
75
|
+
hostParams,
|
|
76
|
+
auth: mountedRoute.contract.binding?.auth,
|
|
77
|
+
});
|
|
78
|
+
const mountHandler = async (c) => {
|
|
79
|
+
const pathParams = {};
|
|
80
|
+
for (const m of fullPath.matchAll(/\{(\w+)([+*])?\}/g)) {
|
|
81
|
+
const name = m[1];
|
|
82
|
+
const value = c.req.param(name);
|
|
83
|
+
if (value !== undefined)
|
|
84
|
+
pathParams[name] = decodeURIComponent(value);
|
|
85
|
+
}
|
|
86
|
+
return handler(c.req.raw, pathParams);
|
|
87
|
+
};
|
|
88
|
+
if (route.method === '*') {
|
|
89
|
+
app.all(honoPath, mountHandler);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
const verb = route.method.toLowerCase();
|
|
93
|
+
app[verb](honoPath, mountHandler);
|
|
94
|
+
}
|
|
95
|
+
// Always allow CORS preflight on routes.
|
|
96
|
+
app.options(honoPath, (c) => handler(c.req.raw, {}));
|
|
97
|
+
}
|
|
98
|
+
return { app, plan };
|
|
99
|
+
}
|
|
100
|
+
/** Convert spec path syntax `/tasks/{id}`, `/files/{name+}` and `/files/{name*}` to Hono syntax. */
|
|
101
|
+
function toHonoPath(path) {
|
|
102
|
+
return path
|
|
103
|
+
.replace(/\{(\w+)\+\}/g, ':$1{.+}')
|
|
104
|
+
.replace(/\{(\w+)\*\}/g, ':$1{.*}')
|
|
105
|
+
.replace(/\{(\w+)\}/g, ':$1');
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=create.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.js","sourceRoot":"","sources":["../../app/create.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,OAAO,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,MAAM,CAAA;AAMvC,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAA;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AACxC,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AACtD,OAAO,EAAE,aAAa,EAAkB,MAAM,cAAc,CAAA;AAI5D,MAAM,YAAY,GAAe,EAAE,MAAM,EAAE,GAAG,EAAE,CAAA;AA0BhD,MAAM,UAAU,eAAe,CAAC,MAAuB;IACrD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,YAAY,CAAA;IACxC,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,IAAI,IAAI,QAAQ,EAAE,CAAA;IACxC,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,IAAI,CAAC,MAAM,CAAC,CAAA;IAEhD,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAA;IACpE,CAAC;IAED,uCAAuC;IACvC,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAA;IAEnD,4BAA4B;IAC5B,SAAS,CAAC,GAAG,EAAE,EAAE,GAAG,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;IAExC,sBAAsB;IACtB,IAAI,MAAM,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;QAC5B,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,IAAI,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;IACtE,CAAC;IAED,kEAAkE;IAClE,qEAAqE;IACrE,yEAAyE;IACzE,sEAAsE;IACtE,+CAA+C;IAC/C,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW;QACjC,CAAC,CAAC,CAAC,GAAY,EAAE,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,CAAC;QAC5D,CAAC,CAAC,SAAS,CAAA;IAEb,MAAM,UAAU,GAAG,sBAAsB,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,CAAC,CAAA;IAE/D,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAA;IACnC,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,EAAE,CAAC;QAChD,SAAS,CAAC,GAAG,CAAC,QAAQ,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAA;IACjD,CAAC;IACD,IAAI,SAAS,CAAC,IAAI,KAAK,CAAC;QAAE,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IAE5C,mEAAmE;IACnE,IAAI,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9B,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CACb,0EAA0E;gBACxE,qEAAqE;gBACrE,uCAAuC,CAC1C,CAAA;QACH,CAAC;QACD,KAAK,MAAM,MAAM,IAAI,SAAS,EAAE,CAAC;YAC/B,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;QACtD,CAAC;IACH,CAAC;IAED,iEAAiE;IACjE,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAA;QAC3D,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAA;IAChE,CAAC;IAED,0DAA0D;IAC1D,KAAK,MAAM,YAAY,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QACvC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,YAAY,CAAA;QACxC,MAAM,QAAQ,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAA;QACrC,MAAM,OAAO,GAAG,kBAAkB,CAAC;YACjC,MAAM,EAAE,YAAY,CAAC,QAAQ,CAAC,GAAG;YACjC,KAAK;YACL,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,IAAI;YACJ,UAAU;YACV,IAAI,EAAE,YAAY,CAAC,QAAQ,CAAC,OAAO,EAAE,IAAI;SAC1C,CAAC,CAAA;QACF,MAAM,YAAY,GAAG,KAAK,EAAE,CAE3B,EAAE,EAAE;YACH,MAAM,UAAU,GAA2B,EAAE,CAAA;YAC7C,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;gBACvD,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;gBACjB,MAAM,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;gBAC/B,IAAI,KAAK,KAAK,SAAS;oBAAE,UAAU,CAAC,IAAI,CAAC,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAA;YACvE,CAAC;YACD,OAAO,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,CAAC,CAAA;QACvC,CAAC,CAAA;QACD,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACzB,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAA;QACjC,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,WAAW,EAAW,CAAA;YAChD,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAA;QACnC,CAAC;QACD,yCAAyC;QACzC,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAA;IACtD,CAAC;IAED,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,CAAA;AACtB,CAAC;AAED,oGAAoG;AACpG,SAAS,UAAU,CAAC,IAAY;IAC9B,OAAO,IAAI;SACR,OAAO,CAAC,cAAc,EAAE,SAAS,CAAC;SAClC,OAAO,CAAC,cAAc,EAAE,SAAS,CAAC;SAClC,OAAO,CAAC,YAAY,EAAE,KAAK,CAAC,CAAA;AACjC,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { createKernelApp, type KernelAppConfig, type WsAdapter } from './create';
|
|
2
|
+
export { createMultiplexedKernelApp, type MultiplexedKernelAppConfig, type KernelResolver, } from './multiplexed';
|
|
3
|
+
export { mountKernelWs } from './ws-upgrade';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../app/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,KAAK,eAAe,EAAE,KAAK,SAAS,EAAE,MAAM,UAAU,CAAA;AAChF,OAAO,EACL,0BAA0B,EAC1B,KAAK,0BAA0B,EAC/B,KAAK,cAAc,GACpB,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../app/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAwC,MAAM,UAAU,CAAA;AAChF,OAAO,EACL,0BAA0B,GAG3B,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createMultiplexedKernelApp — Hono app for multi-instance kernel hosting.
|
|
3
|
+
*
|
|
4
|
+
* One HTTP server hosts many kernel instances under `/{id}/...` paths. Each
|
|
5
|
+
* incoming request is resolved to a kernel via the supplied `resolve()`
|
|
6
|
+
* function. The manager kernel (if any) is mounted at its own static prefix.
|
|
7
|
+
*
|
|
8
|
+
* Both the envelope HTTP dispatcher and the WS upgrade handler are built
|
|
9
|
+
* once at startup. The dispatcher takes `(req, kernel)` per request; the WS
|
|
10
|
+
* handler resolves its kernel once at upgrade time and pins it to the
|
|
11
|
+
* connection for its entire lifetime.
|
|
12
|
+
*
|
|
13
|
+
* Note: this skips per-instance domain mount-walking (no `domain` argument
|
|
14
|
+
* per request) — multiplexed servers dispatch all calls to the kernel layer
|
|
15
|
+
* regardless of binding. Anchored functions still work, since the binding is
|
|
16
|
+
* carried by the contract registered in the runtime.
|
|
17
|
+
*/
|
|
18
|
+
import type { KernelAPI } from '@astrale-os/kernel-api';
|
|
19
|
+
import type { Hono } from 'hono';
|
|
20
|
+
import type { CorsConfig } from '../cors';
|
|
21
|
+
import type { JwksKeys, MultiplexedJwks } from '../jwks';
|
|
22
|
+
import { type WsAdapter } from './ws-upgrade';
|
|
23
|
+
/**
|
|
24
|
+
* Resolves a KernelAPI from an incoming request (multi-instance servers).
|
|
25
|
+
*/
|
|
26
|
+
export type KernelResolver = (req: Request) => KernelAPI | null | Promise<KernelAPI | null>;
|
|
27
|
+
export type MultiplexedKernelAppConfig = {
|
|
28
|
+
/** Per-request kernel resolver (direct access — instance handles its own auth). */
|
|
29
|
+
resolve: KernelResolver;
|
|
30
|
+
/** Optional manager kernel hosted at a static prefix. */
|
|
31
|
+
manager?: {
|
|
32
|
+
kernel: KernelAPI;
|
|
33
|
+
prefix: string;
|
|
34
|
+
jwks: JwksKeys;
|
|
35
|
+
};
|
|
36
|
+
/** Path prefix for instance routes. Defaults to `/:id`. */
|
|
37
|
+
instancePrefix?: string;
|
|
38
|
+
/** Per-instance JWKS lookup. */
|
|
39
|
+
jwks: MultiplexedJwks;
|
|
40
|
+
cors?: CorsConfig;
|
|
41
|
+
health?: string | false;
|
|
42
|
+
app?: Hono;
|
|
43
|
+
/**
|
|
44
|
+
* Runtime-specific WS adapter (from `hono/bun`, `@hono/node-ws`, `hono/deno`).
|
|
45
|
+
* When provided, WS endpoints are mounted for the manager (if any) and all
|
|
46
|
+
* instances at `{instancePrefix}`. Omit to serve HTTP only.
|
|
47
|
+
*/
|
|
48
|
+
ws?: WsAdapter;
|
|
49
|
+
};
|
|
50
|
+
export declare function createMultiplexedKernelApp(config: MultiplexedKernelAppConfig): {
|
|
51
|
+
app: Hono;
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=multiplexed.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multiplexed.d.ts","sourceRoot":"","sources":["../../app/multiplexed.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AACvD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAIhC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACzC,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAIxD,OAAO,EAAiB,KAAK,SAAS,EAAE,MAAM,cAAc,CAAA;AAI5D;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,SAAS,GAAG,IAAI,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAA;AAE3F,MAAM,MAAM,0BAA0B,GAAG;IACvC,mFAAmF;IACnF,OAAO,EAAE,cAAc,CAAA;IACvB,yDAAyD;IACzD,OAAO,CAAC,EAAE;QAAE,MAAM,EAAE,SAAS,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,QAAQ,CAAA;KAAE,CAAA;IAC/D,2DAA2D;IAC3D,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,gCAAgC;IAChC,IAAI,EAAE,eAAe,CAAA;IACrB,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,CAAA;IACvB,GAAG,CAAC,EAAE,IAAI,CAAA;IACV;;;;OAIG;IACH,EAAE,CAAC,EAAE,SAAS,CAAA;CACf,CAAA;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,0BAA0B,GAAG;IAAE,GAAG,EAAE,IAAI,CAAA;CAAE,CA+C5F"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createMultiplexedKernelApp — Hono app for multi-instance kernel hosting.
|
|
3
|
+
*
|
|
4
|
+
* One HTTP server hosts many kernel instances under `/{id}/...` paths. Each
|
|
5
|
+
* incoming request is resolved to a kernel via the supplied `resolve()`
|
|
6
|
+
* function. The manager kernel (if any) is mounted at its own static prefix.
|
|
7
|
+
*
|
|
8
|
+
* Both the envelope HTTP dispatcher and the WS upgrade handler are built
|
|
9
|
+
* once at startup. The dispatcher takes `(req, kernel)` per request; the WS
|
|
10
|
+
* handler resolves its kernel once at upgrade time and pins it to the
|
|
11
|
+
* connection for its entire lifetime.
|
|
12
|
+
*
|
|
13
|
+
* Note: this skips per-instance domain mount-walking (no `domain` argument
|
|
14
|
+
* per request) — multiplexed servers dispatch all calls to the kernel layer
|
|
15
|
+
* regardless of binding. Anchored functions still work, since the binding is
|
|
16
|
+
* carried by the contract registered in the runtime.
|
|
17
|
+
*/
|
|
18
|
+
import { Hono as HonoCtor } from 'hono';
|
|
19
|
+
import { createKernelDispatcher } from '../envelope/http';
|
|
20
|
+
import { mountInstanceJwks, mountJwks } from '../jwks/keys';
|
|
21
|
+
import { mountKernelWs } from './ws-upgrade';
|
|
22
|
+
const DEFAULT_CORS = { origin: '*' };
|
|
23
|
+
export function createMultiplexedKernelApp(config) {
|
|
24
|
+
const cors = config.cors ?? DEFAULT_CORS;
|
|
25
|
+
const app = config.app ?? new HonoCtor();
|
|
26
|
+
const instancePrefix = config.instancePrefix ?? '/:id';
|
|
27
|
+
if (config.health !== false) {
|
|
28
|
+
app.get(typeof config.health === 'string' ? config.health : '/health', (c) => c.json({ status: 'ok' }));
|
|
29
|
+
}
|
|
30
|
+
// Single dispatcher, reused across manager + all instance kernels.
|
|
31
|
+
const dispatcher = createKernelDispatcher(cors);
|
|
32
|
+
// Manager kernel (if any) — static prefix, fixed kernel.
|
|
33
|
+
// POST + OPTIONS handle HTTP dispatch; GET is reserved for WS upgrade
|
|
34
|
+
// (matches createKernelApp's mount layout).
|
|
35
|
+
if (config.manager) {
|
|
36
|
+
const managerKernel = config.manager.kernel;
|
|
37
|
+
const managerPath = `${config.manager.prefix}/`;
|
|
38
|
+
app.post(managerPath, (c) => dispatcher(c.req.raw, managerKernel));
|
|
39
|
+
app.options(managerPath, (c) => dispatcher(c.req.raw, managerKernel));
|
|
40
|
+
mountJwks(app, { ...config.manager.jwks, cors });
|
|
41
|
+
if (config.ws) {
|
|
42
|
+
mountKernelWs(app, managerPath, config.ws, managerKernel);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// Per-instance JWKS
|
|
46
|
+
mountInstanceJwks(app, instancePrefix, { ...config.jwks, cors });
|
|
47
|
+
// Per-instance kernel envelope — kernel resolved per request.
|
|
48
|
+
const instancePath = `${instancePrefix}/`;
|
|
49
|
+
const httpDispatch = async (c) => {
|
|
50
|
+
const kernel = await config.resolve(c.req.raw);
|
|
51
|
+
if (!kernel)
|
|
52
|
+
return new Response('Instance not found', { status: 404 });
|
|
53
|
+
return dispatcher(c.req.raw, kernel);
|
|
54
|
+
};
|
|
55
|
+
app.post(instancePath, httpDispatch);
|
|
56
|
+
app.options(instancePath, httpDispatch);
|
|
57
|
+
// Per-instance WS upgrade — kernel resolved at upgrade time and pinned.
|
|
58
|
+
if (config.ws) {
|
|
59
|
+
mountKernelWs(app, instancePath, config.ws, config.resolve);
|
|
60
|
+
}
|
|
61
|
+
return { app };
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=multiplexed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multiplexed.js","sourceRoot":"","sources":["../../app/multiplexed.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAKH,OAAO,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,MAAM,CAAA;AAKvC,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAA;AACzD,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAC3D,OAAO,EAAE,aAAa,EAAkB,MAAM,cAAc,CAAA;AAE5D,MAAM,YAAY,GAAe,EAAE,MAAM,EAAE,GAAG,EAAE,CAAA;AA2BhD,MAAM,UAAU,0BAA0B,CAAC,MAAkC;IAC3E,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,YAAY,CAAA;IACxC,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,IAAI,IAAI,QAAQ,EAAE,CAAA;IACxC,MAAM,cAAc,GAAG,MAAM,CAAC,cAAc,IAAI,MAAM,CAAA;IAEtD,IAAI,MAAM,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;QAC5B,GAAG,CAAC,GAAG,CAAC,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAC3E,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CACzB,CAAA;IACH,CAAC;IAED,mEAAmE;IACnE,MAAM,UAAU,GAAG,sBAAsB,CAAC,IAAI,CAAC,CAAA;IAE/C,yDAAyD;IACzD,sEAAsE;IACtE,4CAA4C;IAC5C,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAA;QAC3C,MAAM,WAAW,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAA;QAC/C,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC,CAAA;QAClE,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC,CAAA;QACrE,SAAS,CAAC,GAAG,EAAE,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;QAChD,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;YACd,aAAa,CAAC,GAAG,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,EAAE,aAAa,CAAC,CAAA;QAC3D,CAAC;IACH,CAAC;IAED,oBAAoB;IACpB,iBAAiB,CAAC,GAAG,EAAE,cAAc,EAAE,EAAE,GAAG,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;IAEhE,8DAA8D;IAC9D,MAAM,YAAY,GAAG,GAAG,cAAc,GAAG,CAAA;IACzC,MAAM,YAAY,GAAG,KAAK,EAAE,CAA4B,EAAqB,EAAE;QAC7E,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QAC9C,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,QAAQ,CAAC,oBAAoB,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;QACvE,OAAO,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;IACtC,CAAC,CAAA;IACD,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC,CAAA;IACpC,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,YAAY,CAAC,CAAA;IAEvC,wEAAwE;IACxE,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;QACd,aAAa,CAAC,GAAG,EAAE,YAAY,EAAE,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,CAAA;IAC7D,CAAC;IAED,OAAO,EAAE,GAAG,EAAE,CAAA;AAChB,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hono WS upgrade adapter — wires the kernel envelope WS connection class
|
|
3
|
+
* into a Hono app via the runtime-specific `upgradeWebSocket` shim.
|
|
4
|
+
*
|
|
5
|
+
* The adapter is supplied by the caller (`hono/bun`, `@hono/node-ws`,
|
|
6
|
+
* `hono/deno`) so that this module remains free of runtime imports.
|
|
7
|
+
*
|
|
8
|
+
* The kernel can be either a fixed `KernelAPI` (single-kernel servers) or a
|
|
9
|
+
* resolver called at upgrade time with the upgrade request (multi-instance
|
|
10
|
+
* servers). Once resolved, the kernel is pinned to the WS connection for its
|
|
11
|
+
* entire lifetime.
|
|
12
|
+
*/
|
|
13
|
+
import type { KernelAPI } from '@astrale-os/kernel-api';
|
|
14
|
+
import type { Hono } from 'hono';
|
|
15
|
+
import type { UpgradeWebSocket } from 'hono/ws';
|
|
16
|
+
export type WsAdapter = {
|
|
17
|
+
upgradeWebSocket: UpgradeWebSocket;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Kernel source for a WS mount — either a fixed kernel or a per-request
|
|
21
|
+
* resolver. Resolvers may be async and return `null` to reject the upgrade.
|
|
22
|
+
*/
|
|
23
|
+
export type WsKernelSource = KernelAPI | ((req: Request) => KernelAPI | null | Promise<KernelAPI | null>);
|
|
24
|
+
/**
|
|
25
|
+
* Mount the kernel WS handler at `path` on the Hono app.
|
|
26
|
+
*
|
|
27
|
+
* The handler shares the URL with the kernel HTTP handler — clients use the
|
|
28
|
+
* same base URL and switch transports via HTTP Upgrade negotiation.
|
|
29
|
+
*
|
|
30
|
+
* When `source` is a resolver, it is invoked once at upgrade time. A null
|
|
31
|
+
* result closes the socket with code 4004 (instance not found) before any
|
|
32
|
+
* messages are exchanged.
|
|
33
|
+
*/
|
|
34
|
+
export declare function mountKernelWs(app: Hono, path: string, ws: WsAdapter, source: WsKernelSource): void;
|
|
35
|
+
//# sourceMappingURL=ws-upgrade.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ws-upgrade.d.ts","sourceRoot":"","sources":["../../app/ws-upgrade.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AACvD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAChC,OAAO,KAAK,EAAE,gBAAgB,EAAa,MAAM,SAAS,CAAA;AAK1D,MAAM,MAAM,SAAS,GAAG;IACtB,gBAAgB,EAAE,gBAAgB,CAAA;CACnC,CAAA;AAED;;;GAGG;AACH,MAAM,MAAM,cAAc,GACtB,SAAS,GACT,CAAC,CAAC,GAAG,EAAE,OAAO,KAAK,SAAS,GAAG,IAAI,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,CAAA;AAuBpE;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,IAAI,EACT,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,SAAS,EACb,MAAM,EAAE,cAAc,GACrB,IAAI,CAkDN"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hono WS upgrade adapter — wires the kernel envelope WS connection class
|
|
3
|
+
* into a Hono app via the runtime-specific `upgradeWebSocket` shim.
|
|
4
|
+
*
|
|
5
|
+
* The adapter is supplied by the caller (`hono/bun`, `@hono/node-ws`,
|
|
6
|
+
* `hono/deno`) so that this module remains free of runtime imports.
|
|
7
|
+
*
|
|
8
|
+
* The kernel can be either a fixed `KernelAPI` (single-kernel servers) or a
|
|
9
|
+
* resolver called at upgrade time with the upgrade request (multi-instance
|
|
10
|
+
* servers). Once resolved, the kernel is pinned to the WS connection for its
|
|
11
|
+
* entire lifetime.
|
|
12
|
+
*/
|
|
13
|
+
import { negotiateWsCodec } from '../envelope/codec';
|
|
14
|
+
import { KernelWsConnection } from '../envelope/ws';
|
|
15
|
+
function adaptHonoWs(ws) {
|
|
16
|
+
const raw = ws.raw;
|
|
17
|
+
return {
|
|
18
|
+
send(data) {
|
|
19
|
+
ws.send(data);
|
|
20
|
+
},
|
|
21
|
+
close(code, reason) {
|
|
22
|
+
ws.close(code, reason);
|
|
23
|
+
},
|
|
24
|
+
get readyState() {
|
|
25
|
+
return raw?.readyState ?? ws.readyState;
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function isResolver(source) {
|
|
30
|
+
return typeof source === 'function';
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Mount the kernel WS handler at `path` on the Hono app.
|
|
34
|
+
*
|
|
35
|
+
* The handler shares the URL with the kernel HTTP handler — clients use the
|
|
36
|
+
* same base URL and switch transports via HTTP Upgrade negotiation.
|
|
37
|
+
*
|
|
38
|
+
* When `source` is a resolver, it is invoked once at upgrade time. A null
|
|
39
|
+
* result closes the socket with code 4004 (instance not found) before any
|
|
40
|
+
* messages are exchanged.
|
|
41
|
+
*/
|
|
42
|
+
export function mountKernelWs(app, path, ws, source) {
|
|
43
|
+
const route = ws.upgradeWebSocket((c) => {
|
|
44
|
+
const upgradeRequest = c.req.raw;
|
|
45
|
+
const codec = negotiateWsCodec(upgradeRequest);
|
|
46
|
+
let conn = null;
|
|
47
|
+
return {
|
|
48
|
+
async onOpen(_evt, wsCtx) {
|
|
49
|
+
if (!codec) {
|
|
50
|
+
wsCtx.close(4000, 'Unsupported codec');
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
let kernel;
|
|
54
|
+
try {
|
|
55
|
+
kernel = isResolver(source) ? await source(upgradeRequest) : source;
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
// A mount-time failure (e.g. a child kernel boot throwing) must not
|
|
59
|
+
// escape: this `onOpen` is async but the host WS adapter wraps it in
|
|
60
|
+
// a *synchronous* try/catch that cannot observe an async rejection,
|
|
61
|
+
// so an uncaught throw here becomes a process-killing unhandled
|
|
62
|
+
// rejection. Reject the upgrade by closing the socket instead — and
|
|
63
|
+
// log the error so a programmer bug (e.g. an unrelated TypeError
|
|
64
|
+
// bubbling up from the resolver) isn't silently masked as a benign
|
|
65
|
+
// mount fail.
|
|
66
|
+
// eslint-disable-next-line no-console -- diagnostic from boundary handler
|
|
67
|
+
console.error('[ws-upgrade] mount failed (socket closed 4005):', err);
|
|
68
|
+
wsCtx.close(4005, 'mount failed');
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (!kernel) {
|
|
72
|
+
wsCtx.close(4004, 'Instance not found');
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
conn = new KernelWsConnection(adaptHonoWs(wsCtx), codec, kernel);
|
|
76
|
+
conn.start();
|
|
77
|
+
},
|
|
78
|
+
onMessage(evt) {
|
|
79
|
+
conn?.handleMessage(evt.data);
|
|
80
|
+
},
|
|
81
|
+
onClose() {
|
|
82
|
+
conn?.handleClose();
|
|
83
|
+
conn = null;
|
|
84
|
+
},
|
|
85
|
+
onError(evt) {
|
|
86
|
+
const msg = evt instanceof ErrorEvent ? evt.message : `WebSocket error: ${evt.type}`;
|
|
87
|
+
conn?.handleError(new Error(msg));
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
});
|
|
91
|
+
app.get(path, route);
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=ws-upgrade.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ws-upgrade.js","sourceRoot":"","sources":["../../app/ws-upgrade.ts"],"names":[],"mappings":"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"}
|
package/dist/cors.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CORS configuration and header builder.
|
|
3
|
+
*
|
|
4
|
+
* Cross-cutting helper consumed by every protocol handler. The shape mirrors
|
|
5
|
+
* the standard `Access-Control-*` headers; multi-origin matching belongs in
|
|
6
|
+
* framework-level middleware (e.g. Hono's `cors()`), not here.
|
|
7
|
+
*/
|
|
8
|
+
export type CorsConfig = {
|
|
9
|
+
/**
|
|
10
|
+
* Allowed origin. Use '*' for any, or a single origin string.
|
|
11
|
+
*
|
|
12
|
+
* Note: HTTP `Access-Control-Allow-Origin` does not support multiple
|
|
13
|
+
* comma-separated origins. For multi-origin, implement per-request
|
|
14
|
+
* matching at the framework middleware level (e.g., Hono cors()).
|
|
15
|
+
*/
|
|
16
|
+
origin: string;
|
|
17
|
+
methods?: string[];
|
|
18
|
+
headers?: string[];
|
|
19
|
+
};
|
|
20
|
+
export declare function buildCorsHeaders(cors: CorsConfig): Record<string, string>;
|
|
21
|
+
//# sourceMappingURL=cors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cors.d.ts","sourceRoot":"","sources":["../cors.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,UAAU,GAAG;IACvB;;;;;;OAMG;IACH,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;CACnB,CAAA;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQzE"}
|
package/dist/cors.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CORS configuration and header builder.
|
|
3
|
+
*
|
|
4
|
+
* Cross-cutting helper consumed by every protocol handler. The shape mirrors
|
|
5
|
+
* the standard `Access-Control-*` headers; multi-origin matching belongs in
|
|
6
|
+
* framework-level middleware (e.g. Hono's `cors()`), not here.
|
|
7
|
+
*/
|
|
8
|
+
export function buildCorsHeaders(cors) {
|
|
9
|
+
const origin = cors.origin;
|
|
10
|
+
return {
|
|
11
|
+
'access-control-allow-origin': origin,
|
|
12
|
+
'access-control-allow-methods': (cors.methods ?? ['POST', 'OPTIONS']).join(', '),
|
|
13
|
+
'access-control-allow-headers': (cors.headers ?? ['content-type', 'authorization']).join(', '),
|
|
14
|
+
'access-control-expose-headers': 'x-binary-result',
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=cors.js.map
|
package/dist/cors.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cors.js","sourceRoot":"","sources":["../cors.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAeH,MAAM,UAAU,gBAAgB,CAAC,IAAgB;IAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAA;IAC1B,OAAO;QACL,6BAA6B,EAAE,MAAM;QACrC,8BAA8B,EAAE,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QAChF,8BAA8B,EAAE,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QAC9F,+BAA+B,EAAE,iBAAiB;KACnD,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kernel envelope batch processing.
|
|
3
|
+
*
|
|
4
|
+
* A batch is an array of kernel envelope requests delivered in a single HTTP
|
|
5
|
+
* POST. Each is dispatched independently and the encoded responses are
|
|
6
|
+
* collected into an array. Notifications are dropped from the response;
|
|
7
|
+
* streams and binary results are rejected (those need their own connection).
|
|
8
|
+
*/
|
|
9
|
+
import type { KernelAPI } from '@astrale-os/kernel-api';
|
|
10
|
+
import { type CodecEntry } from './codec';
|
|
11
|
+
export declare function handleBatch(raw: unknown[], kernel: KernelAPI, codecEntry: CodecEntry, req: Request, corsHeaders: Record<string, string>): Promise<Response>;
|
|
12
|
+
//# sourceMappingURL=batch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"batch.d.ts","sourceRoot":"","sources":["../../envelope/batch.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAsB,MAAM,wBAAwB,CAAA;AAa3E,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,SAAS,CAAA;AAGzC,wBAAsB,WAAW,CAC/B,GAAG,EAAE,OAAO,EAAE,EACd,MAAM,EAAE,SAAS,EACjB,UAAU,EAAE,UAAU,EACtB,GAAG,EAAE,OAAO,EACZ,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAClC,OAAO,CAAC,QAAQ,CAAC,CAmFnB"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kernel envelope batch processing.
|
|
3
|
+
*
|
|
4
|
+
* A batch is an array of kernel envelope requests delivered in a single HTTP
|
|
5
|
+
* POST. Each is dispatched independently and the encoded responses are
|
|
6
|
+
* collected into an array. Notifications are dropped from the response;
|
|
7
|
+
* streams and binary results are rejected (those need their own connection).
|
|
8
|
+
*/
|
|
9
|
+
import { KERNEL_ERROR_CODES, decodeKernelRequest, dispatch, encodeKernelError, encodeKernelRedirect, encodeKernelResponse, isBinaryResult, } from '@astrale-os/kernel-api';
|
|
10
|
+
import { toBody } from '../render';
|
|
11
|
+
import {} from './codec';
|
|
12
|
+
import { extractCredential } from './credential';
|
|
13
|
+
export async function handleBatch(raw, kernel, codecEntry, req, corsHeaders) {
|
|
14
|
+
if (raw.length === 0) {
|
|
15
|
+
return errorResponse(codecEntry, { code: KERNEL_ERROR_CODES.INVALID_REQUEST, message: 'Empty batch' }, corsHeaders, 400);
|
|
16
|
+
}
|
|
17
|
+
const auth = await extractCredential(req);
|
|
18
|
+
const results = Array.from({ length: raw.length }, () => null);
|
|
19
|
+
await Promise.all(raw.map(async (item, i) => {
|
|
20
|
+
let request;
|
|
21
|
+
try {
|
|
22
|
+
request = decodeKernelRequest(item);
|
|
23
|
+
}
|
|
24
|
+
catch (e) {
|
|
25
|
+
results[i] = encodeKernelError(null, {
|
|
26
|
+
code: KERNEL_ERROR_CODES.INVALID_REQUEST,
|
|
27
|
+
message: e instanceof Error ? e.message : 'Invalid request',
|
|
28
|
+
});
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const isAck = request.id === undefined;
|
|
32
|
+
let cred;
|
|
33
|
+
if (request.creds !== undefined) {
|
|
34
|
+
cred = request.creds;
|
|
35
|
+
}
|
|
36
|
+
else if (!auth.ok) {
|
|
37
|
+
results[i] = encodeKernelError(request.id ?? null, {
|
|
38
|
+
code: KERNEL_ERROR_CODES.AUTH_INVALID,
|
|
39
|
+
message: `Unsupported Authorization scheme: ${auth.scheme}`,
|
|
40
|
+
});
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
cred = auth.credential;
|
|
45
|
+
}
|
|
46
|
+
const res = await dispatch(request.method, request.params, cred, kernel, isAck ? { ack: true } : { id: request.id, isStream: false });
|
|
47
|
+
if (res.kind === 'ack')
|
|
48
|
+
return;
|
|
49
|
+
if (res.kind === 'stream') {
|
|
50
|
+
results[i] = encodeKernelError(request.id, {
|
|
51
|
+
code: KERNEL_ERROR_CODES.INVALID_REQUEST,
|
|
52
|
+
message: 'Streaming is not supported inside a batch',
|
|
53
|
+
});
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (res.kind === 'redirect') {
|
|
57
|
+
results[i] = encodeKernelRedirect(res.id, res.redirection);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (res.kind === 'success') {
|
|
61
|
+
if (isBinaryResult(res.data)) {
|
|
62
|
+
results[i] = encodeKernelError(res.id, {
|
|
63
|
+
code: KERNEL_ERROR_CODES.INVALID_REQUEST,
|
|
64
|
+
message: 'Binary result is not supported inside a batch',
|
|
65
|
+
});
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
results[i] = encodeKernelResponse(res.id, res.data);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
results[i] = encodeKernelError(res.id, res.error);
|
|
72
|
+
}));
|
|
73
|
+
const encoded = results.filter((r) => r !== null);
|
|
74
|
+
if (encoded.length === 0) {
|
|
75
|
+
return new Response(null, { status: 204, headers: corsHeaders });
|
|
76
|
+
}
|
|
77
|
+
const bytes = codecEntry.codec.encode(encoded);
|
|
78
|
+
return new Response(toBody(bytes), {
|
|
79
|
+
status: 200,
|
|
80
|
+
headers: { ...corsHeaders, 'content-type': codecEntry.kernelType },
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
function errorResponse(codecEntry, error, corsHeaders, httpStatus) {
|
|
84
|
+
const bytes = codecEntry.codec.encode(encodeKernelError(null, error));
|
|
85
|
+
return new Response(toBody(bytes), {
|
|
86
|
+
status: httpStatus,
|
|
87
|
+
headers: { ...corsHeaders, 'content-type': codecEntry.kernelType },
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=batch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"batch.js","sourceRoot":"","sources":["../../envelope/batch.ts"],"names":[],"mappings":"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"}
|