@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,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route binding parameter decoder.
|
|
3
|
+
*
|
|
4
|
+
* Extracts params from all sources (host, path, query, header, body) per
|
|
5
|
+
* spec §3. Merge order: host < path < query < header < body — later wins.
|
|
6
|
+
* `route.self`, if set, is lifted to a separate top-level `self` channel
|
|
7
|
+
* AND removed from `params` — handlers read it via the `self` sibling in
|
|
8
|
+
* their execute context (`self.path.raw`), never from `params`. Leaving
|
|
9
|
+
* a copy in `params` would trip strict Zod validation of `inputSchema`
|
|
10
|
+
* (`route-self.ts` explicitly allows the placeholder to be absent from
|
|
11
|
+
* the schema, so the runtime must not smuggle it through anyway).
|
|
12
|
+
*
|
|
13
|
+
* Body modes:
|
|
14
|
+
* - `'*'` parse JSON body, merge top-level fields into params.
|
|
15
|
+
* - `'raw'` skip parsing; raw bytes at `params._body`.
|
|
16
|
+
* - `Record` parse JSON, pick mapped fields with wire-name remapping.
|
|
17
|
+
*/
|
|
18
|
+
import { jsonCodec } from '@astrale-os/kernel-api';
|
|
19
|
+
/** Check if a body pick is a whole-body read mode ({ as: 'text' } or { as: 'bytes' }). */
|
|
20
|
+
function isWholeBodyPick(pick) {
|
|
21
|
+
return typeof pick === 'object' && 'as' in pick;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Decode params from a route + request.
|
|
25
|
+
*
|
|
26
|
+
* Throws on body parse errors — the caller should map to PARSE_ERROR.
|
|
27
|
+
*/
|
|
28
|
+
export async function decodeRouteRequest(input) {
|
|
29
|
+
const { route, pathParams, hostParams = {}, request } = input;
|
|
30
|
+
const url = new URL(request.url);
|
|
31
|
+
const params = {};
|
|
32
|
+
// 1. Host placeholders (lowest priority)
|
|
33
|
+
for (const [k, v] of Object.entries(hostParams)) {
|
|
34
|
+
params[k] = v;
|
|
35
|
+
}
|
|
36
|
+
// 2. Path placeholders (implicit by name)
|
|
37
|
+
for (const [k, v] of Object.entries(pathParams)) {
|
|
38
|
+
params[k] = v;
|
|
39
|
+
}
|
|
40
|
+
// 3. Query parameters (explicit field → wire-name)
|
|
41
|
+
if (route.query) {
|
|
42
|
+
for (const [field, wireName] of Object.entries(route.query)) {
|
|
43
|
+
const value = url.searchParams.get(wireName);
|
|
44
|
+
if (value !== null) {
|
|
45
|
+
params[field] = decodeQueryValue(value);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// 4. Headers — per-entry: string = specific wire name, '*' = all headers
|
|
50
|
+
if (route.headers) {
|
|
51
|
+
for (const [field, pick] of Object.entries(route.headers)) {
|
|
52
|
+
if (pick === '*') {
|
|
53
|
+
const all = {};
|
|
54
|
+
request.headers.forEach((value, key) => {
|
|
55
|
+
all[key] = value;
|
|
56
|
+
});
|
|
57
|
+
params[field] = all;
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
const value = request.headers.get(pick);
|
|
61
|
+
if (value !== null) {
|
|
62
|
+
params[field] = value;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// 5. Body — '*' = JSON spread, Record = per-field picks
|
|
68
|
+
if (route.body !== undefined) {
|
|
69
|
+
if (route.body === '*') {
|
|
70
|
+
// Parse JSON, merge all top-level fields
|
|
71
|
+
if (hasBody(request.method)) {
|
|
72
|
+
const decoded = await parseJsonBody(request);
|
|
73
|
+
if (decoded && typeof decoded === 'object') {
|
|
74
|
+
for (const [k, v] of Object.entries(decoded)) {
|
|
75
|
+
params[k] = v;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
// Record<string, BodyPick> — inspect picks to determine read mode
|
|
82
|
+
const entries = Object.entries(route.body);
|
|
83
|
+
const wholeEntry = entries.find(([_, pick]) => isWholeBodyPick(pick));
|
|
84
|
+
if (wholeEntry) {
|
|
85
|
+
// Whole-body read: { as: 'text' } or { as: 'bytes' }
|
|
86
|
+
const [field, pick] = wholeEntry;
|
|
87
|
+
if (pick.as === 'text') {
|
|
88
|
+
params[field] = await request.text();
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
params[field] = new Uint8Array(await request.arrayBuffer());
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
else if (hasBody(request.method)) {
|
|
95
|
+
// All string picks → JSON field picking
|
|
96
|
+
const decoded = await parseJsonBody(request);
|
|
97
|
+
if (decoded && typeof decoded === 'object') {
|
|
98
|
+
const obj = decoded;
|
|
99
|
+
for (const [field, wireName] of entries) {
|
|
100
|
+
if (wireName in obj) {
|
|
101
|
+
params[field] = obj[wireName];
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// 6. self lift: route.self placeholder → DecodedRoute.self (sibling of
|
|
109
|
+
// params, NOT a member). The source field is REMOVED from params —
|
|
110
|
+
// `self` is the canonical channel for "the node this method runs
|
|
111
|
+
// on" (matches envelope dispatch via `<path>::method`, which also
|
|
112
|
+
// keeps self out of the body). Leaving a copy in `params` would
|
|
113
|
+
// cause strict Zod validation of the inputSchema to reject the
|
|
114
|
+
// placeholder field, even though `validateRouteSelf` already says
|
|
115
|
+
// the schema doesn't have to declare it.
|
|
116
|
+
let self;
|
|
117
|
+
if (route.self !== undefined) {
|
|
118
|
+
const sourceValue = params[route.self];
|
|
119
|
+
if (typeof sourceValue === 'string') {
|
|
120
|
+
self = sourceValue;
|
|
121
|
+
delete params[route.self];
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return self !== undefined ? { params, self } : { params };
|
|
125
|
+
}
|
|
126
|
+
// ─── Helpers ────────────────────────────────────────────────────────────────
|
|
127
|
+
function hasBody(method) {
|
|
128
|
+
return method === 'POST' || method === 'PUT' || method === 'PATCH' || method === 'DELETE';
|
|
129
|
+
}
|
|
130
|
+
async function parseJsonBody(req) {
|
|
131
|
+
const bytes = new Uint8Array(await req.arrayBuffer());
|
|
132
|
+
if (bytes.length === 0)
|
|
133
|
+
return null;
|
|
134
|
+
return jsonCodec.decode(bytes);
|
|
135
|
+
}
|
|
136
|
+
/** Coerce a query string value to a sensible JS value (number/bool/string). */
|
|
137
|
+
function decodeQueryValue(raw) {
|
|
138
|
+
if (raw === 'true')
|
|
139
|
+
return true;
|
|
140
|
+
if (raw === 'false')
|
|
141
|
+
return false;
|
|
142
|
+
if (raw !== '' && !isNaN(Number(raw)))
|
|
143
|
+
return Number(raw);
|
|
144
|
+
return raw;
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=params.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"params.js","sourceRoot":"","sources":["../../routed/params.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSE response with raw chunk framing — used by route bindings.
|
|
3
|
+
*
|
|
4
|
+
* Distinct from `envelope/sse.ts`: route SSE emits each yielded value as its
|
|
5
|
+
* own JSON `data:` line, with `event: end` / `event: error` for terminal
|
|
6
|
+
* events. There is no kernel envelope wrapping; the route's `outputSchema`
|
|
7
|
+
* IS the chunk shape.
|
|
8
|
+
*
|
|
9
|
+
* Setup failures from the first iteration become a kernel error response so
|
|
10
|
+
* the caller can return them with the right HTTP status.
|
|
11
|
+
*/
|
|
12
|
+
import type { KernelErrorPayload } from '@astrale-os/kernel-api';
|
|
13
|
+
export type StreamResponseResult = {
|
|
14
|
+
kind: 'response';
|
|
15
|
+
response: Response;
|
|
16
|
+
} | {
|
|
17
|
+
kind: 'error';
|
|
18
|
+
error: KernelErrorPayload;
|
|
19
|
+
};
|
|
20
|
+
export declare function buildRouteStreamResponse(generator: AsyncGenerator<unknown>, corsHeaders: Record<string, string>): Promise<StreamResponseResult>;
|
|
21
|
+
//# sourceMappingURL=stream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../routed/stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAIhE,MAAM,MAAM,oBAAoB,GAC5B;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GACxC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,kBAAkB,CAAA;CAAE,CAAA;AAEhD,wBAAsB,wBAAwB,CAC5C,SAAS,EAAE,cAAc,CAAC,OAAO,CAAC,EAClC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAClC,OAAO,CAAC,oBAAoB,CAAC,CAyD/B"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSE response with raw chunk framing — used by route bindings.
|
|
3
|
+
*
|
|
4
|
+
* Distinct from `envelope/sse.ts`: route SSE emits each yielded value as its
|
|
5
|
+
* own JSON `data:` line, with `event: end` / `event: error` for terminal
|
|
6
|
+
* events. There is no kernel envelope wrapping; the route's `outputSchema`
|
|
7
|
+
* IS the chunk shape.
|
|
8
|
+
*
|
|
9
|
+
* Setup failures from the first iteration become a kernel error response so
|
|
10
|
+
* the caller can return them with the right HTTP status.
|
|
11
|
+
*/
|
|
12
|
+
import { classifyError } from '@astrale-os/kernel-api';
|
|
13
|
+
export async function buildRouteStreamResponse(generator, corsHeaders) {
|
|
14
|
+
// Eagerly pull the first chunk so setup failures become a proper HTTP error.
|
|
15
|
+
let first;
|
|
16
|
+
try {
|
|
17
|
+
first = await generator.next();
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
return { kind: 'error', error: classifyError(err) };
|
|
21
|
+
}
|
|
22
|
+
const encoder = new TextEncoder();
|
|
23
|
+
let cancelled = false;
|
|
24
|
+
const stream = new ReadableStream({
|
|
25
|
+
async start(controller) {
|
|
26
|
+
try {
|
|
27
|
+
if (!first.done) {
|
|
28
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify(first.value)}\n\n`));
|
|
29
|
+
}
|
|
30
|
+
for await (const chunk of generator) {
|
|
31
|
+
if (cancelled)
|
|
32
|
+
break;
|
|
33
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify(chunk)}\n\n`));
|
|
34
|
+
}
|
|
35
|
+
if (!cancelled) {
|
|
36
|
+
controller.enqueue(encoder.encode(`event: end\ndata: {}\n\n`));
|
|
37
|
+
}
|
|
38
|
+
controller.close();
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
try {
|
|
42
|
+
const error = classifyError(err);
|
|
43
|
+
controller.enqueue(encoder.encode(`event: error\ndata: ${JSON.stringify({ code: error.code, message: error.message })}\n\n`));
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
/* swallow */
|
|
47
|
+
}
|
|
48
|
+
controller.close();
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
cancel() {
|
|
52
|
+
cancelled = true;
|
|
53
|
+
generator.return(undefined).catch(() => { });
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
return {
|
|
57
|
+
kind: 'response',
|
|
58
|
+
response: new Response(stream, {
|
|
59
|
+
status: 200,
|
|
60
|
+
headers: {
|
|
61
|
+
...corsHeaders,
|
|
62
|
+
'content-type': 'text/event-stream',
|
|
63
|
+
'cache-control': 'no-cache',
|
|
64
|
+
connection: 'keep-alive',
|
|
65
|
+
},
|
|
66
|
+
}),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream.js","sourceRoot":"","sources":["../../routed/stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAMtD,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,SAAkC,EAClC,WAAmC;IAEnC,6EAA6E;IAC7E,IAAI,KAA8B,CAAA;IAClC,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,CAAA;IAChC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,EAAE,CAAA;IACrD,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAA;IACjC,IAAI,SAAS,GAAG,KAAK,CAAA;IACrB,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC;QAChC,KAAK,CAAC,KAAK,CAAC,UAAU;YACpB,IAAI,CAAC;gBACH,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;oBAChB,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAA;gBAChF,CAAC;gBACD,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,SAAS,EAAE,CAAC;oBACpC,IAAI,SAAS;wBAAE,MAAK;oBACpB,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAA;gBAC1E,CAAC;gBACD,IAAI,CAAC,SAAS,EAAE,CAAC;oBACf,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,0BAA0B,CAAC,CAAC,CAAA;gBAChE,CAAC;gBACD,UAAU,CAAC,KAAK,EAAE,CAAA;YACpB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,CAAC;oBACH,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,CAAA;oBAChC,UAAU,CAAC,OAAO,CAChB,OAAO,CAAC,MAAM,CACZ,uBAAuB,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,MAAM,CAC1F,CACF,CAAA;gBACH,CAAC;gBAAC,MAAM,CAAC;oBACP,aAAa;gBACf,CAAC;gBACD,UAAU,CAAC,KAAK,EAAE,CAAA;YACpB,CAAC;QACH,CAAC;QACD,MAAM;YACJ,SAAS,GAAG,IAAI,CAAA;YAChB,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QAC7C,CAAC;KACF,CAAC,CAAA;IAEF,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,QAAQ,EAAE,IAAI,QAAQ,CAAC,MAAM,EAAE;YAC7B,MAAM,EAAE,GAAG;YACX,OAAO,EAAE;gBACP,GAAG,WAAW;gBACd,cAAc,EAAE,mBAAmB;gBACnC,eAAe,EAAE,UAAU;gBAC3B,UAAU,EAAE,YAAY;aACzB;SACF,CAAC;KACH,CAAA;AACH,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@astrale-os/kernel-server",
|
|
3
|
+
"version": "0.4.1",
|
|
4
|
+
"description": "Astrale Kernel Server - kernel envelope HTTP/WS server with Hono",
|
|
5
|
+
"files": [
|
|
6
|
+
"dist"
|
|
7
|
+
],
|
|
8
|
+
"type": "module",
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./app": {
|
|
17
|
+
"types": "./dist/app/index.d.ts",
|
|
18
|
+
"import": "./dist/app/index.js"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "restricted",
|
|
23
|
+
"registry": "https://npm.pkg.github.com"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"hono": "^4.6.20",
|
|
27
|
+
"zod": "^4.3.6",
|
|
28
|
+
"@astrale-os/kernel-api": "0.4.2",
|
|
29
|
+
"@astrale-os/kernel-core": "0.4.1"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@astrale/typescript-config": "npm:@jsr/astrale__typescript-config@~1.1.0",
|
|
33
|
+
"@types/node": "^22.15.0",
|
|
34
|
+
"@typescript/native-preview": "latest",
|
|
35
|
+
"typescript": "~6.0.1-rc",
|
|
36
|
+
"vitest": "^3.0.0"
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "tsgo",
|
|
40
|
+
"clean": "rm -rf dist",
|
|
41
|
+
"typecheck": "tsgo --noEmit",
|
|
42
|
+
"test": "vitest run",
|
|
43
|
+
"preinstall": "node .check-workspace.cjs"
|
|
44
|
+
}
|
|
45
|
+
}
|