@arki/http 0.0.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/LICENSE +21 -0
- package/README.md +229 -0
- package/dist/bundle.d.ts +121 -0
- package/dist/bundle.d.ts.map +1 -0
- package/dist/bundle.js +98 -0
- package/dist/bundle.js.map +1 -0
- package/dist/context.d.ts +29 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +34 -0
- package/dist/context.js.map +1 -0
- package/dist/contract.d.ts +120 -0
- package/dist/contract.d.ts.map +1 -0
- package/dist/contract.js +49 -0
- package/dist/contract.js.map +1 -0
- package/dist/derive.d.ts +58 -0
- package/dist/derive.d.ts.map +1 -0
- package/dist/derive.js +28 -0
- package/dist/derive.js.map +1 -0
- package/dist/dot.d.ts +106 -0
- package/dist/dot.d.ts.map +1 -0
- package/dist/dot.js +210 -0
- package/dist/dot.js.map +1 -0
- package/dist/engine.d.ts +36 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +173 -0
- package/dist/engine.js.map +1 -0
- package/dist/error.d.ts +107 -0
- package/dist/error.d.ts.map +1 -0
- package/dist/error.js +122 -0
- package/dist/error.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/listen.d.ts +23 -0
- package/dist/listen.d.ts.map +1 -0
- package/dist/listen.js +71 -0
- package/dist/listen.js.map +1 -0
- package/dist/openapi.d.ts +45 -0
- package/dist/openapi.d.ts.map +1 -0
- package/dist/openapi.js +140 -0
- package/dist/openapi.js.map +1 -0
- package/dist/sse.d.ts +12 -0
- package/dist/sse.d.ts.map +1 -0
- package/dist/sse.js +86 -0
- package/dist/sse.js.map +1 -0
- package/package.json +73 -0
- package/src/bundle.ts +221 -0
- package/src/context.ts +39 -0
- package/src/contract.ts +152 -0
- package/src/derive.ts +67 -0
- package/src/dot.ts +282 -0
- package/src/engine.ts +239 -0
- package/src/error.ts +158 -0
- package/src/index.ts +53 -0
- package/src/listen.ts +100 -0
- package/src/openapi.ts +168 -0
- package/src/sse.ts +92 -0
package/dist/engine.js
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The request engine — builds one fetch handler from a list of bundles.
|
|
3
|
+
*
|
|
4
|
+
* Hono does the routing internally; no Hono type appears in the public
|
|
5
|
+
* API, so the engine stays a swappable implementation detail. The route
|
|
6
|
+
* table order is bundle order then binding order — declaration order,
|
|
7
|
+
* deterministically, per DOT principle 3.
|
|
8
|
+
*/
|
|
9
|
+
import { Hono } from 'hono';
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
import { runWithRequestContext } from './context.js';
|
|
12
|
+
import { describeInternalError, errorResponse, HTTP_ERROR_CODES, HttpConfigError, HttpError, toErrorResponse } from './error.js';
|
|
13
|
+
import { sseResponse } from './sse.js';
|
|
14
|
+
/**
|
|
15
|
+
* Compose bundles into a single fetch handler. Throws
|
|
16
|
+
* `ARKI_HTTP_E002`/`E006` on route collisions and malformed mounts —
|
|
17
|
+
* callers (the `http()` pip's `boot`) let these bubble as boot failures.
|
|
18
|
+
*/
|
|
19
|
+
export function buildEngine(bundles) {
|
|
20
|
+
const app = new Hono();
|
|
21
|
+
const claimed = new Map();
|
|
22
|
+
const routeIds = [];
|
|
23
|
+
for (const bundle of bundles) {
|
|
24
|
+
for (const mount of bundle.mounts) {
|
|
25
|
+
registerMount(app, claimed, mount);
|
|
26
|
+
routeIds.push(mount.id);
|
|
27
|
+
}
|
|
28
|
+
for (const binding of bundle.bindings) {
|
|
29
|
+
registerBinding(app, claimed, bundle, binding);
|
|
30
|
+
routeIds.push(binding.contract.id);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
app.notFound(c => errorResponse(404, HTTP_ERROR_CODES.notFound, `no route for ${c.req.method} ${new URL(c.req.url).pathname}`));
|
|
34
|
+
app.onError((error, _c) => toErrorResponse(error));
|
|
35
|
+
return {
|
|
36
|
+
fetch: req => Promise.resolve(app.fetch(req)),
|
|
37
|
+
routeIds,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function registerMount(app, claimed, mount) {
|
|
41
|
+
const key = `MOUNT ${mount.path}`;
|
|
42
|
+
const prior = claimed.get(key);
|
|
43
|
+
if (prior !== undefined) {
|
|
44
|
+
throw new HttpConfigError({
|
|
45
|
+
code: HTTP_ERROR_CODES.duplicateRoute,
|
|
46
|
+
message: `[http] duplicate mount at "${mount.path}": "${mount.id}" collides with "${prior}".`,
|
|
47
|
+
remediation: 'Give each mounted handler a distinct path prefix.',
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
claimed.set(key, mount.id);
|
|
51
|
+
app.mount(mount.path, mount.handler);
|
|
52
|
+
}
|
|
53
|
+
function registerBinding(app, claimed, bundle, binding) {
|
|
54
|
+
const { contract } = binding;
|
|
55
|
+
const key = `${contract.method} ${contract.path}`;
|
|
56
|
+
const prior = claimed.get(key);
|
|
57
|
+
if (prior !== undefined) {
|
|
58
|
+
throw new HttpConfigError({
|
|
59
|
+
code: HTTP_ERROR_CODES.duplicateRoute,
|
|
60
|
+
message: `[http] duplicate route ${key}: "${contract.id}" collides with "${prior}".`,
|
|
61
|
+
remediation: 'Two bindings (possibly from different bundles) claim the same method and path. Change one path, or drop the duplicate binding.',
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
claimed.set(key, contract.id);
|
|
65
|
+
app.on(contract.method, contract.path, c => executeBinding(bundle, binding, c.req.raw, c.req.param()));
|
|
66
|
+
}
|
|
67
|
+
async function executeBinding(bundle, binding, req, params) {
|
|
68
|
+
const base = {
|
|
69
|
+
req,
|
|
70
|
+
url: new URL(req.url),
|
|
71
|
+
requestId: req.headers.get('x-request-id') ?? crypto.randomUUID(),
|
|
72
|
+
signal: req.signal,
|
|
73
|
+
};
|
|
74
|
+
return runWithRequestContext(base, async () => {
|
|
75
|
+
try {
|
|
76
|
+
let ctx = base;
|
|
77
|
+
for (const deriver of bundle.derivers) {
|
|
78
|
+
// Erasure boundary: derivers were stored with `never` context (see
|
|
79
|
+
// ErasedDeriver); the accumulated ctx is the value they were typed
|
|
80
|
+
// against at composition time.
|
|
81
|
+
const value = await deriver.derive(req, ctx);
|
|
82
|
+
ctx = { ...ctx, [deriver.key]: value };
|
|
83
|
+
}
|
|
84
|
+
const input = await validateInput(binding.contract, params, base.url, req);
|
|
85
|
+
if (binding.contract.kind === 'sse') {
|
|
86
|
+
// Erasure boundary, same as above — input/ctx match the handler's
|
|
87
|
+
// composition-time types.
|
|
88
|
+
const events = binding.handler(input, ctx);
|
|
89
|
+
return sseResponse(events, binding.contract, base.signal);
|
|
90
|
+
}
|
|
91
|
+
const result = await binding.handler(input, ctx);
|
|
92
|
+
if (result instanceof Response)
|
|
93
|
+
return result;
|
|
94
|
+
return serializeOutput(binding.contract, result);
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
return toErrorResponse(error);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
async function validateInput(contract, params, url, req) {
|
|
102
|
+
let query;
|
|
103
|
+
if (contract.query !== undefined) {
|
|
104
|
+
// Multi-valued query params collapse to their last value here; declare
|
|
105
|
+
// arrays via a transform on the contract schema if you need them.
|
|
106
|
+
query = parseWith(contract.query, Object.fromEntries(url.searchParams), 'query');
|
|
107
|
+
}
|
|
108
|
+
let body;
|
|
109
|
+
if (contract.body !== undefined) {
|
|
110
|
+
let raw;
|
|
111
|
+
try {
|
|
112
|
+
raw = await req.json();
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
throw new HttpError(400, HTTP_ERROR_CODES.badRequest, 'request body is not valid JSON', {
|
|
116
|
+
remediation: 'Send a JSON body with content-type: application/json.',
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
body = parseWith(contract.body, raw, 'body');
|
|
120
|
+
}
|
|
121
|
+
return { params, query, body };
|
|
122
|
+
}
|
|
123
|
+
function parseWith(schema, value, where) {
|
|
124
|
+
try {
|
|
125
|
+
return schema.parse(value);
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
throw new HttpError(400, HTTP_ERROR_CODES.badRequest, `${where} validation failed: ${zodMessage(error)}`, {
|
|
129
|
+
cause: error,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function zodMessage(error) {
|
|
134
|
+
if (error instanceof z.ZodError) {
|
|
135
|
+
return error.issues.map(issue => `${issue.path.join('.') || '(root)'}: ${issue.message}`).join('; ');
|
|
136
|
+
}
|
|
137
|
+
return describeInternalError(error);
|
|
138
|
+
}
|
|
139
|
+
function serializeOutput(contract, result) {
|
|
140
|
+
if (contract.output === undefined) {
|
|
141
|
+
throw new HttpError(500, HTTP_ERROR_CODES.internal, `handler for "${contract.id}" returned a value but the contract declares no output schema`, { remediation: 'Return a Response, or declare an output schema on the contract.' });
|
|
142
|
+
}
|
|
143
|
+
let validated;
|
|
144
|
+
try {
|
|
145
|
+
validated = contract.output.parse(result);
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
throw new HttpError(500, HTTP_ERROR_CODES.internal, `handler output for "${contract.id}" violates the contract's output schema: ${zodMessage(error)}`, { cause: error });
|
|
149
|
+
}
|
|
150
|
+
return Response.json(validated);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Wrap a fetch handler in middleware (first = outermost). A middleware
|
|
154
|
+
* that throws resolves to the coded error envelope — `HttpError` keeps
|
|
155
|
+
* its status, anything else is a 500.
|
|
156
|
+
*/
|
|
157
|
+
export function composeMiddleware(fetch, middleware) {
|
|
158
|
+
let composed = fetch;
|
|
159
|
+
for (const layer of middleware.toReversed()) {
|
|
160
|
+
const next = composed;
|
|
161
|
+
composed = async (req) => await layer(req, next);
|
|
162
|
+
}
|
|
163
|
+
const outermost = composed;
|
|
164
|
+
return async (req) => {
|
|
165
|
+
try {
|
|
166
|
+
return await outermost(req);
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
return toErrorResponse(error);
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
|
package/dist/error.d.ts
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error surface for `@arki/http`.
|
|
3
|
+
*
|
|
4
|
+
* Two families, mirroring the DOT diagnostics doctrine:
|
|
5
|
+
*
|
|
6
|
+
* - {@link HttpConfigError} — composition/lifecycle failures (duplicate
|
|
7
|
+
* routes, listen failures, drain timeouts). Thrown from `boot`/`start`/
|
|
8
|
+
* `stop`; the kernel wraps them and their `code`/`remediation`/`docsUrl`
|
|
9
|
+
* propagate into `app.diagnostics.issues`.
|
|
10
|
+
* - {@link HttpError} — per-request failures. Thrown from handlers,
|
|
11
|
+
* derivers, or validation; serialized onto the wire as the coded
|
|
12
|
+
* envelope `{ error: { code, message, remediation?, docsUrl? } }`.
|
|
13
|
+
*
|
|
14
|
+
* Every code is stable API. Match on codes, never parse messages.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Stable error codes for `@arki/http`. `E0NN` codes surface through the
|
|
18
|
+
* DOT lifecycle (boot/start/stop failures); `E4xx`/`E5xx` codes surface
|
|
19
|
+
* on the wire in the error envelope.
|
|
20
|
+
*/
|
|
21
|
+
export declare const HTTP_ERROR_CODES: {
|
|
22
|
+
/** `start` could not bind the port. */
|
|
23
|
+
readonly listenFailed: "ARKI_HTTP_E001";
|
|
24
|
+
/** Two bindings claim the same method + path. */
|
|
25
|
+
readonly duplicateRoute: "ARKI_HTTP_E002";
|
|
26
|
+
/** `stop` exceeded `drainTimeoutMs` with requests still in flight. */
|
|
27
|
+
readonly drainTimeout: "ARKI_HTTP_E005";
|
|
28
|
+
/** A mount path is malformed. */
|
|
29
|
+
readonly invalidMount: "ARKI_HTTP_E006";
|
|
30
|
+
/** A deriver key duplicates an earlier deriver or a base context key. */
|
|
31
|
+
readonly duplicateDeriverKey: "ARKI_HTTP_E007";
|
|
32
|
+
/** Request validation failed (query/body) or the body is not valid JSON. */
|
|
33
|
+
readonly badRequest: "ARKI_HTTP_E400";
|
|
34
|
+
/** A deriver rejected the request's credentials. */
|
|
35
|
+
readonly unauthorized: "ARKI_HTTP_E401";
|
|
36
|
+
/** A deriver rejected the request's permissions. */
|
|
37
|
+
readonly forbidden: "ARKI_HTTP_E403";
|
|
38
|
+
/** No route matches the request. */
|
|
39
|
+
readonly notFound: "ARKI_HTTP_E404";
|
|
40
|
+
/** Handler crash or output-schema violation. */
|
|
41
|
+
readonly internal: "ARKI_HTTP_E500";
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* A per-request failure with an HTTP status and a stable code. Throw from
|
|
45
|
+
* a handler or deriver to short-circuit into the wire envelope:
|
|
46
|
+
*
|
|
47
|
+
* ```ts
|
|
48
|
+
* throw new HttpError(401, HTTP_ERROR_CODES.unauthorized, 'missing or invalid credentials');
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export declare class HttpError extends Error {
|
|
52
|
+
readonly status: number;
|
|
53
|
+
readonly code: string;
|
|
54
|
+
readonly remediation: string | undefined;
|
|
55
|
+
readonly docsUrl: string | undefined;
|
|
56
|
+
/** Extra response headers — e.g. `www-authenticate` on a 401, `retry-after` on a 429. */
|
|
57
|
+
readonly headers: Readonly<Record<string, string>> | undefined;
|
|
58
|
+
constructor(status: number, code: string, message: string, options?: {
|
|
59
|
+
readonly remediation?: string;
|
|
60
|
+
readonly docsUrl?: string;
|
|
61
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
62
|
+
readonly cause?: unknown;
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* A composition or lifecycle failure. Carries the same code/remediation/
|
|
67
|
+
* docsUrl fields the DOT kernel propagates into diagnostics when a hook
|
|
68
|
+
* throws.
|
|
69
|
+
*/
|
|
70
|
+
export declare class HttpConfigError extends Error {
|
|
71
|
+
readonly code: string;
|
|
72
|
+
readonly remediation: string;
|
|
73
|
+
readonly docsUrl: string;
|
|
74
|
+
constructor(fields: {
|
|
75
|
+
readonly code: string;
|
|
76
|
+
readonly message: string;
|
|
77
|
+
readonly remediation: string;
|
|
78
|
+
readonly docsUrl?: string;
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
/** The wire error envelope. Stable shape — agents parse this. */
|
|
82
|
+
export type HttpErrorEnvelope = {
|
|
83
|
+
readonly error: {
|
|
84
|
+
readonly code: string;
|
|
85
|
+
readonly message: string;
|
|
86
|
+
readonly remediation?: string;
|
|
87
|
+
readonly docsUrl?: string;
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Message for an unexpected (non-{@link HttpError}) failure: full detail
|
|
92
|
+
* in development, redacted in production — internals never leak onto the
|
|
93
|
+
* wire of a deployed app.
|
|
94
|
+
*/
|
|
95
|
+
export declare function describeInternalError(error: unknown): string;
|
|
96
|
+
/**
|
|
97
|
+
* Map any thrown value to its wire envelope: {@link HttpError} keeps its
|
|
98
|
+
* status and fields; everything else is a redacted-in-production 500.
|
|
99
|
+
*/
|
|
100
|
+
export declare function toErrorResponse(error: unknown): Response;
|
|
101
|
+
/** Build the envelope `Response` for a coded failure. */
|
|
102
|
+
export declare function errorResponse(status: number, code: string, message: string, options?: {
|
|
103
|
+
readonly remediation?: string;
|
|
104
|
+
readonly docsUrl?: string;
|
|
105
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
106
|
+
}): Response;
|
|
107
|
+
//# sourceMappingURL=error.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;;;GAIG;AACH,eAAO,MAAM,gBAAgB;IAC3B,uCAAuC;;IAEvC,iDAAiD;;IAEjD,sEAAsE;;IAEtE,iCAAiC;;IAEjC,yEAAyE;;IAEzE,4EAA4E;;IAE5E,oDAAoD;;IAEpD,oDAAoD;;IAEpD,oCAAoC;;IAEpC,gDAAgD;;CAExC,CAAC;AAIX;;;;;;;GAOG;AACH,qBAAa,SAAU,SAAQ,KAAK;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,yFAAyF;IACzF,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,CAAC;gBAG7D,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;QACP,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;QACpD,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;KACrB;CAUT;AAED;;;;GAIG;AACH,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;gBAEb,MAAM,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE;CAOjI;AAED,iEAAiE;AACjE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,KAAK,EAAE;QACd,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;KAC3B,CAAC;CACH,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAG5D;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,QAAQ,CASxD;AAED,yDAAyD;AACzD,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;IACP,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAChD,GACL,QAAQ,CAUV"}
|
package/dist/error.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error surface for `@arki/http`.
|
|
3
|
+
*
|
|
4
|
+
* Two families, mirroring the DOT diagnostics doctrine:
|
|
5
|
+
*
|
|
6
|
+
* - {@link HttpConfigError} — composition/lifecycle failures (duplicate
|
|
7
|
+
* routes, listen failures, drain timeouts). Thrown from `boot`/`start`/
|
|
8
|
+
* `stop`; the kernel wraps them and their `code`/`remediation`/`docsUrl`
|
|
9
|
+
* propagate into `app.diagnostics.issues`.
|
|
10
|
+
* - {@link HttpError} — per-request failures. Thrown from handlers,
|
|
11
|
+
* derivers, or validation; serialized onto the wire as the coded
|
|
12
|
+
* envelope `{ error: { code, message, remediation?, docsUrl? } }`.
|
|
13
|
+
*
|
|
14
|
+
* Every code is stable API. Match on codes, never parse messages.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Stable error codes for `@arki/http`. `E0NN` codes surface through the
|
|
18
|
+
* DOT lifecycle (boot/start/stop failures); `E4xx`/`E5xx` codes surface
|
|
19
|
+
* on the wire in the error envelope.
|
|
20
|
+
*/
|
|
21
|
+
export const HTTP_ERROR_CODES = {
|
|
22
|
+
/** `start` could not bind the port. */
|
|
23
|
+
listenFailed: 'ARKI_HTTP_E001',
|
|
24
|
+
/** Two bindings claim the same method + path. */
|
|
25
|
+
duplicateRoute: 'ARKI_HTTP_E002',
|
|
26
|
+
/** `stop` exceeded `drainTimeoutMs` with requests still in flight. */
|
|
27
|
+
drainTimeout: 'ARKI_HTTP_E005',
|
|
28
|
+
/** A mount path is malformed. */
|
|
29
|
+
invalidMount: 'ARKI_HTTP_E006',
|
|
30
|
+
/** A deriver key duplicates an earlier deriver or a base context key. */
|
|
31
|
+
duplicateDeriverKey: 'ARKI_HTTP_E007',
|
|
32
|
+
/** Request validation failed (query/body) or the body is not valid JSON. */
|
|
33
|
+
badRequest: 'ARKI_HTTP_E400',
|
|
34
|
+
/** A deriver rejected the request's credentials. */
|
|
35
|
+
unauthorized: 'ARKI_HTTP_E401',
|
|
36
|
+
/** A deriver rejected the request's permissions. */
|
|
37
|
+
forbidden: 'ARKI_HTTP_E403',
|
|
38
|
+
/** No route matches the request. */
|
|
39
|
+
notFound: 'ARKI_HTTP_E404',
|
|
40
|
+
/** Handler crash or output-schema violation. */
|
|
41
|
+
internal: 'ARKI_HTTP_E500',
|
|
42
|
+
};
|
|
43
|
+
const docsUrlFor = (code) => `https://arki.dev/http/errors/${code.toLowerCase().replaceAll('_', '-')}`;
|
|
44
|
+
/**
|
|
45
|
+
* A per-request failure with an HTTP status and a stable code. Throw from
|
|
46
|
+
* a handler or deriver to short-circuit into the wire envelope:
|
|
47
|
+
*
|
|
48
|
+
* ```ts
|
|
49
|
+
* throw new HttpError(401, HTTP_ERROR_CODES.unauthorized, 'missing or invalid credentials');
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export class HttpError extends Error {
|
|
53
|
+
status;
|
|
54
|
+
code;
|
|
55
|
+
remediation;
|
|
56
|
+
docsUrl;
|
|
57
|
+
/** Extra response headers — e.g. `www-authenticate` on a 401, `retry-after` on a 429. */
|
|
58
|
+
headers;
|
|
59
|
+
constructor(status, code, message, options = {}) {
|
|
60
|
+
super(message, options.cause === undefined ? {} : { cause: options.cause });
|
|
61
|
+
this.name = 'HttpError';
|
|
62
|
+
this.status = status;
|
|
63
|
+
this.code = code;
|
|
64
|
+
this.remediation = options.remediation;
|
|
65
|
+
this.docsUrl = options.docsUrl ?? docsUrlFor(code);
|
|
66
|
+
this.headers = options.headers;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* A composition or lifecycle failure. Carries the same code/remediation/
|
|
71
|
+
* docsUrl fields the DOT kernel propagates into diagnostics when a hook
|
|
72
|
+
* throws.
|
|
73
|
+
*/
|
|
74
|
+
export class HttpConfigError extends Error {
|
|
75
|
+
code;
|
|
76
|
+
remediation;
|
|
77
|
+
docsUrl;
|
|
78
|
+
constructor(fields) {
|
|
79
|
+
super(fields.message);
|
|
80
|
+
this.name = 'HttpConfigError';
|
|
81
|
+
this.code = fields.code;
|
|
82
|
+
this.remediation = fields.remediation;
|
|
83
|
+
this.docsUrl = fields.docsUrl ?? docsUrlFor(fields.code);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Message for an unexpected (non-{@link HttpError}) failure: full detail
|
|
88
|
+
* in development, redacted in production — internals never leak onto the
|
|
89
|
+
* wire of a deployed app.
|
|
90
|
+
*/
|
|
91
|
+
export function describeInternalError(error) {
|
|
92
|
+
if (process.env.NODE_ENV === 'production')
|
|
93
|
+
return 'internal error';
|
|
94
|
+
return error instanceof Error ? error.message : String(error);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Map any thrown value to its wire envelope: {@link HttpError} keeps its
|
|
98
|
+
* status and fields; everything else is a redacted-in-production 500.
|
|
99
|
+
*/
|
|
100
|
+
export function toErrorResponse(error) {
|
|
101
|
+
if (error instanceof HttpError) {
|
|
102
|
+
return errorResponse(error.status, error.code, error.message, {
|
|
103
|
+
...(error.remediation === undefined ? {} : { remediation: error.remediation }),
|
|
104
|
+
...(error.docsUrl === undefined ? {} : { docsUrl: error.docsUrl }),
|
|
105
|
+
...(error.headers === undefined ? {} : { headers: error.headers }),
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
return errorResponse(500, HTTP_ERROR_CODES.internal, describeInternalError(error));
|
|
109
|
+
}
|
|
110
|
+
/** Build the envelope `Response` for a coded failure. */
|
|
111
|
+
export function errorResponse(status, code, message, options = {}) {
|
|
112
|
+
const envelope = {
|
|
113
|
+
error: {
|
|
114
|
+
code,
|
|
115
|
+
message,
|
|
116
|
+
...(options.remediation === undefined ? {} : { remediation: options.remediation }),
|
|
117
|
+
...(options.docsUrl === undefined ? {} : { docsUrl: options.docsUrl }),
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
return Response.json(envelope, { status, ...(options.headers === undefined ? {} : { headers: options.headers }) });
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error.js","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@arki/http` — typed HTTP for ARKI.
|
|
3
|
+
*
|
|
4
|
+
* Route contracts as data ({@link route}), zod-validated handlers bound in
|
|
5
|
+
* a typed bundle builder ({@link routes}), request-scope derivers
|
|
6
|
+
* ({@link derive}), SSE streaming, and deterministic OpenAPI generation
|
|
7
|
+
* ({@link toOpenApi}).
|
|
8
|
+
*
|
|
9
|
+
* The framework-agnostic core lives here — {@link buildEngine} +
|
|
10
|
+
* {@link listen} run a server without any framework. The DOT adapter (the
|
|
11
|
+
* `http()` pip) lives at `@arki/http/dot`; the ambient request context —
|
|
12
|
+
* a deliberate last resort — at `@arki/http/context`.
|
|
13
|
+
*/
|
|
14
|
+
export { route } from './contract.js';
|
|
15
|
+
export type { ContractLike, HttpMethod, ParamsOf, PathParams, RouteContract, SchemaLike, SseContract, } from './contract.js';
|
|
16
|
+
export { routes } from './bundle.js';
|
|
17
|
+
export type { HandlerResult, MountBinding, MountMeta, MountTransport, RouteBinding, RouteBundle, RouteBundleBuilder, RouteHandler, RouteInput, SseHandler, } from './bundle.js';
|
|
18
|
+
export { BASE_CTX_KEYS, derive } from './derive.js';
|
|
19
|
+
export type { BaseRequestCtx, Deriver, ErasedDeriver } from './derive.js';
|
|
20
|
+
export { describeInternalError, errorResponse, HTTP_ERROR_CODES, HttpConfigError, HttpError, toErrorResponse } from './error.js';
|
|
21
|
+
export type { HttpErrorEnvelope } from './error.js';
|
|
22
|
+
export { contractMeta, toOpenApi } from './openapi.js';
|
|
23
|
+
export type { OpenApiInfo, RouteMeta } from './openapi.js';
|
|
24
|
+
export { buildEngine, composeMiddleware } from './engine.js';
|
|
25
|
+
export type { Engine, HttpMiddleware } from './engine.js';
|
|
26
|
+
export { listen } from './listen.js';
|
|
27
|
+
export type { ListenHandle, ListenOptions } from './listen.js';
|
|
28
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,YAAY,EACV,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,UAAU,EACV,aAAa,EACb,UAAU,EACV,WAAW,GACZ,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,YAAY,EACV,aAAa,EACb,YAAY,EACZ,SAAS,EACT,cAAc,EACd,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,YAAY,EACZ,UAAU,EACV,UAAU,GACX,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACpD,YAAY,EAAE,cAAc,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE1E,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,gBAAgB,EAAE,eAAe,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AACjI,YAAY,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACvD,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAC7D,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE1D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@arki/http` — typed HTTP for ARKI.
|
|
3
|
+
*
|
|
4
|
+
* Route contracts as data ({@link route}), zod-validated handlers bound in
|
|
5
|
+
* a typed bundle builder ({@link routes}), request-scope derivers
|
|
6
|
+
* ({@link derive}), SSE streaming, and deterministic OpenAPI generation
|
|
7
|
+
* ({@link toOpenApi}).
|
|
8
|
+
*
|
|
9
|
+
* The framework-agnostic core lives here — {@link buildEngine} +
|
|
10
|
+
* {@link listen} run a server without any framework. The DOT adapter (the
|
|
11
|
+
* `http()` pip) lives at `@arki/http/dot`; the ambient request context —
|
|
12
|
+
* a deliberate last resort — at `@arki/http/context`.
|
|
13
|
+
*/
|
|
14
|
+
export { route } from './contract.js';
|
|
15
|
+
export { routes } from './bundle.js';
|
|
16
|
+
export { BASE_CTX_KEYS, derive } from './derive.js';
|
|
17
|
+
export { describeInternalError, errorResponse, HTTP_ERROR_CODES, HttpConfigError, HttpError, toErrorResponse } from './error.js';
|
|
18
|
+
export { contractMeta, toOpenApi } from './openapi.js';
|
|
19
|
+
export { buildEngine, composeMiddleware } from './engine.js';
|
|
20
|
+
export { listen } from './listen.js';
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAWtC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAcrC,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGpD,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,gBAAgB,EAAE,eAAe,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAGjI,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGvD,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAG7D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/listen.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The socket layer — runtime-adaptive listening.
|
|
3
|
+
*
|
|
4
|
+
* `Bun.serve` when the Bun global is present, `@hono/node-server`
|
|
5
|
+
* otherwise. Neither runtime's types leak into the public surface; the
|
|
6
|
+
* handle exposes exactly what the `http()` pip's lifecycle needs.
|
|
7
|
+
*/
|
|
8
|
+
export type ListenOptions = {
|
|
9
|
+
readonly port: number;
|
|
10
|
+
readonly hostname?: string;
|
|
11
|
+
};
|
|
12
|
+
export type ListenHandle = {
|
|
13
|
+
readonly port: number;
|
|
14
|
+
readonly hostname: string;
|
|
15
|
+
/** Stop accepting new connections; in-flight requests continue. */
|
|
16
|
+
stopAccepting(): void;
|
|
17
|
+
/** Sever remaining connections and release the port. */
|
|
18
|
+
forceClose(): void;
|
|
19
|
+
};
|
|
20
|
+
type FetchLike = (req: Request) => Response | Promise<Response>;
|
|
21
|
+
export declare function listen(fetch: FetchLike, options: ListenOptions): Promise<ListenHandle>;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=listen.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"listen.d.ts","sourceRoot":"","sources":["../src/listen.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,mEAAmE;IACnE,aAAa,IAAI,IAAI,CAAC;IACtB,wDAAwD;IACxD,UAAU,IAAI,IAAI,CAAC;CACpB,CAAC;AAEF,KAAK,SAAS,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;AAyBhE,wBAAsB,MAAM,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAI5F"}
|
package/dist/listen.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The socket layer — runtime-adaptive listening.
|
|
3
|
+
*
|
|
4
|
+
* `Bun.serve` when the Bun global is present, `@hono/node-server`
|
|
5
|
+
* otherwise. Neither runtime's types leak into the public surface; the
|
|
6
|
+
* handle exposes exactly what the `http()` pip's lifecycle needs.
|
|
7
|
+
*/
|
|
8
|
+
import { HTTP_ERROR_CODES, HttpConfigError } from './error.js';
|
|
9
|
+
/** Narrow structural view of the Bun global — `@types/node` has no Bun. */
|
|
10
|
+
function bunGlobal() {
|
|
11
|
+
return globalThis.Bun;
|
|
12
|
+
}
|
|
13
|
+
function listenFailure(port, cause) {
|
|
14
|
+
return new HttpConfigError({
|
|
15
|
+
code: HTTP_ERROR_CODES.listenFailed,
|
|
16
|
+
message: `[http] failed to listen on port ${port}: ${cause instanceof Error ? cause.message : String(cause)}`,
|
|
17
|
+
remediation: 'Is the port already in use? Change options.port on http(...) or stop the other process.',
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
export async function listen(fetch, options) {
|
|
21
|
+
const bun = bunGlobal();
|
|
22
|
+
if (bun !== undefined)
|
|
23
|
+
return listenBun(bun, fetch, options);
|
|
24
|
+
return listenNode(fetch, options);
|
|
25
|
+
}
|
|
26
|
+
function listenBun(bun, fetch, options) {
|
|
27
|
+
let server;
|
|
28
|
+
try {
|
|
29
|
+
server = bun.serve({
|
|
30
|
+
port: options.port,
|
|
31
|
+
fetch,
|
|
32
|
+
...(options.hostname === undefined ? {} : { hostname: options.hostname }),
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
throw listenFailure(options.port, error);
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
port: server.port,
|
|
40
|
+
hostname: server.hostname,
|
|
41
|
+
stopAccepting: () => {
|
|
42
|
+
server.stop(false);
|
|
43
|
+
},
|
|
44
|
+
forceClose: () => {
|
|
45
|
+
server.stop(true);
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
async function listenNode(fetch, options) {
|
|
50
|
+
const { serve } = await import('@hono/node-server');
|
|
51
|
+
return await new Promise((resolve, reject) => {
|
|
52
|
+
const server = serve({ fetch, port: options.port, hostname: options.hostname ?? '0.0.0.0' }, info => {
|
|
53
|
+
resolve({
|
|
54
|
+
port: info.port,
|
|
55
|
+
hostname: info.address,
|
|
56
|
+
stopAccepting: () => {
|
|
57
|
+
server.close();
|
|
58
|
+
},
|
|
59
|
+
forceClose: () => {
|
|
60
|
+
const closable = server;
|
|
61
|
+
closable.closeAllConnections?.();
|
|
62
|
+
closable.close();
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
server.on('error', (error) => {
|
|
67
|
+
reject(listenFailure(options.port, error));
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=listen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"listen.js","sourceRoot":"","sources":["../src/listen.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAPI generation — falls out of the contracts, doesn't bolt on.
|
|
3
|
+
*
|
|
4
|
+
* Contracts are static data carrying zod schemas, so the document is
|
|
5
|
+
* produced without booting anything, deterministically: same contracts in
|
|
6
|
+
* the same order → byte-identical output (DOT principle 3). No decorator
|
|
7
|
+
* reconstruction, no annotations — the schema IS the validation IS the
|
|
8
|
+
* documentation.
|
|
9
|
+
*/
|
|
10
|
+
import type { ContractLike } from './contract.js';
|
|
11
|
+
export type OpenApiInfo = {
|
|
12
|
+
readonly title: string;
|
|
13
|
+
readonly version: string;
|
|
14
|
+
readonly description?: string;
|
|
15
|
+
};
|
|
16
|
+
type JsonObject = Record<string, unknown>;
|
|
17
|
+
/**
|
|
18
|
+
* Render an OpenAPI 3.1 document from contracts. Paths and operations
|
|
19
|
+
* appear in contract order; duplicate method+path pairs fail loudly with
|
|
20
|
+
* `ARKI_HTTP_E002` (the same collision `buildEngine` rejects at boot).
|
|
21
|
+
*/
|
|
22
|
+
export declare function toOpenApi(contracts: readonly ContractLike[], info: OpenApiInfo): JsonObject;
|
|
23
|
+
/** The DOT `registerRoute` argument derived from a contract. */
|
|
24
|
+
export type RouteMeta = {
|
|
25
|
+
readonly id: string;
|
|
26
|
+
readonly method: string;
|
|
27
|
+
readonly path: string;
|
|
28
|
+
readonly transport: 'http';
|
|
29
|
+
readonly description?: string;
|
|
30
|
+
readonly input?: {
|
|
31
|
+
readonly query?: JsonObject;
|
|
32
|
+
readonly body?: JsonObject;
|
|
33
|
+
};
|
|
34
|
+
readonly output?: JsonObject;
|
|
35
|
+
readonly streaming?: boolean;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Manifest metadata for a contract — what `registerRoutes` (from
|
|
39
|
+
* `@arki/http/dot`) feeds into `ctx.registerRoute` so that
|
|
40
|
+
* `dot explain --openapi` can render without booting. SSE contracts mark
|
|
41
|
+
* `streaming` and carry the per-event schema as `output`.
|
|
42
|
+
*/
|
|
43
|
+
export declare function contractMeta(contract: ContractLike): RouteMeta;
|
|
44
|
+
export {};
|
|
45
|
+
//# sourceMappingURL=openapi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openapi.d.ts","sourceRoot":"","sources":["../src/openapi.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAGlD,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B,CAAC;AAEF,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAgF1C;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,SAAS,YAAY,EAAE,EAAE,IAAI,EAAE,WAAW,GAAG,UAAU,CAwB3F;AAED,gEAAgE;AAChE,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE;QAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;QAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,UAAU,CAAA;KAAE,CAAC;IAC7E,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;CAC9B,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,YAAY,GAAG,SAAS,CAiB9D"}
|