@ozanarslan/corpus 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.txt +20 -0
- package/README.md +337 -0
- package/dist/App/index.d.ts +377 -0
- package/dist/App/index.d.ts.map +1 -0
- package/dist/C.namespace.d.ts +27 -0
- package/dist/C.namespace.d.ts.map +1 -0
- package/dist/Config/index.d.ts +163 -0
- package/dist/Config/index.d.ts.map +1 -0
- package/dist/Context/ContextAccess/index.d.ts +50 -0
- package/dist/Context/ContextAccess/index.d.ts.map +1 -0
- package/dist/Context/index.d.ts +162 -0
- package/dist/Context/index.d.ts.map +1 -0
- package/dist/Controller/index.d.ts +164 -0
- package/dist/Controller/index.d.ts.map +1 -0
- package/dist/Cookies/index.d.ts +81 -0
- package/dist/Cookies/index.d.ts.map +1 -0
- package/dist/Cors/index.d.ts +135 -0
- package/dist/Cors/index.d.ts.map +1 -0
- package/dist/Exception/index.d.ts +85 -0
- package/dist/Exception/index.d.ts.map +1 -0
- package/dist/Globals/AppsRegistry/index.d.ts +48 -0
- package/dist/Globals/AppsRegistry/index.d.ts.map +1 -0
- package/dist/Globals/ParsersRegistry/index.d.ts +93 -0
- package/dist/Globals/ParsersRegistry/index.d.ts.map +1 -0
- package/dist/Globals/index.d.ts +109 -0
- package/dist/Globals/index.d.ts.map +1 -0
- package/dist/Headers/index.d.ts +208 -0
- package/dist/Headers/index.d.ts.map +1 -0
- package/dist/Middleware/index.d.ts +125 -0
- package/dist/Middleware/index.d.ts.map +1 -0
- package/dist/ParserBase/BodyParser/index.d.ts +138 -0
- package/dist/ParserBase/BodyParser/index.d.ts.map +1 -0
- package/dist/ParserBase/FormDataParser/index.d.ts +57 -0
- package/dist/ParserBase/FormDataParser/index.d.ts.map +1 -0
- package/dist/ParserBase/SchemaParser/index.d.ts +143 -0
- package/dist/ParserBase/SchemaParser/index.d.ts.map +1 -0
- package/dist/ParserBase/SearchParamsParser/index.d.ts +61 -0
- package/dist/ParserBase/SearchParamsParser/index.d.ts.map +1 -0
- package/dist/ParserBase/URLParamsParser/index.d.ts +32 -0
- package/dist/ParserBase/URLParamsParser/index.d.ts.map +1 -0
- package/dist/ParserBase/index.d.ts +92 -0
- package/dist/ParserBase/index.d.ts.map +1 -0
- package/dist/RateLimiter/index.d.ts +321 -0
- package/dist/RateLimiter/index.d.ts.map +1 -0
- package/dist/Request/index.d.ts +81 -0
- package/dist/Request/index.d.ts.map +1 -0
- package/dist/Res/index.d.ts +353 -0
- package/dist/Res/index.d.ts.map +1 -0
- package/dist/RouteBase/BundleRoute/index.d.ts +268 -0
- package/dist/RouteBase/BundleRoute/index.d.ts.map +1 -0
- package/dist/RouteBase/FileRoute/index.d.ts +121 -0
- package/dist/RouteBase/FileRoute/index.d.ts.map +1 -0
- package/dist/RouteBase/Route/index.d.ts +83 -0
- package/dist/RouteBase/Route/index.d.ts.map +1 -0
- package/dist/RouteBase/StaticRoute/index.d.ts +149 -0
- package/dist/RouteBase/StaticRoute/index.d.ts.map +1 -0
- package/dist/RouteBase/WebSocketRoute/index.d.ts +117 -0
- package/dist/RouteBase/WebSocketRoute/index.d.ts.map +1 -0
- package/dist/RouteBase/index.d.ts +206 -0
- package/dist/RouteBase/index.d.ts.map +1 -0
- package/dist/Server/index.d.ts +44 -0
- package/dist/Server/index.d.ts.map +1 -0
- package/dist/XFile/index.d.ts +202 -0
- package/dist/XFile/index.d.ts.map +1 -0
- package/dist/exports.d.ts +11 -0
- package/dist/exports.d.ts.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +47 -0
- package/dist/initialize.d.ts +22 -0
- package/dist/initialize.d.ts.map +1 -0
- package/dist/utils/assert.d.ts +7 -0
- package/dist/utils/assert.d.ts.map +1 -0
- package/dist/utils/is.d.ts +17 -0
- package/dist/utils/is.d.ts.map +1 -0
- package/dist/utils/lazy.d.ts +27 -0
- package/dist/utils/lazy.d.ts.map +1 -0
- package/dist/utils/logger.d.ts +31 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/object.d.ts +20 -0
- package/dist/utils/object.d.ts.map +1 -0
- package/dist/utils/path.d.ts +6 -0
- package/dist/utils/path.d.ts.map +1 -0
- package/dist/utils/tuple.d.ts +3 -0
- package/dist/utils/tuple.d.ts.map +1 -0
- package/package.json +57 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Serving a single file from a single endpoint.
|
|
3
|
+
*
|
|
4
|
+
* {@link FileRoute} is the {@link RouteVariant.file} member of the
|
|
5
|
+
* {@link RouteBase} family, and the narrowest of the file-serving routes: one
|
|
6
|
+
* endpoint, one file, no path resolution. Reach for {@link BundleRoute} to serve
|
|
7
|
+
* a whole directory, or {@link StaticRoute} when the file's contents feed a
|
|
8
|
+
* handler rather than being sent as-is.
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { FileRoute } from "@ozanarslan/corpus";
|
|
12
|
+
*
|
|
13
|
+
* new FileRoute("GET /robots.txt", "./public/robots.txt");
|
|
14
|
+
* new FileRoute("GET /report", { filePath: "./report.pdf", disposition: "attachment" });
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @module FileRoute
|
|
18
|
+
*/
|
|
19
|
+
import type { ContextHandler } from "../../Context";
|
|
20
|
+
import { type ContentDispositionDefinition, type CacheControlDefinition } from "../../Headers";
|
|
21
|
+
import { Method } from "../../Request";
|
|
22
|
+
import { RouteBase, type RouteAddress, RouteVariant, type RouteConfig } from "..";
|
|
23
|
+
/**
|
|
24
|
+
* Describes the file a {@link FileRoute} serves and how it is sent. Pass a bare
|
|
25
|
+
* path string instead when the defaults suffice.
|
|
26
|
+
*/
|
|
27
|
+
interface FileRouteDefinition {
|
|
28
|
+
/** Path to the file, resolved when the request arrives rather than at registration. */
|
|
29
|
+
filePath: string;
|
|
30
|
+
/**
|
|
31
|
+
* The `Content-Disposition` to send. Setting it also switches the route to
|
|
32
|
+
* streaming — see {@link FileRoute.disposition}.
|
|
33
|
+
*/
|
|
34
|
+
disposition?: ContentDispositionDefinition["disposition"];
|
|
35
|
+
/** Caching policy. Defaults to {@link FileRoute.cache}. */
|
|
36
|
+
cache?: CacheControlDefinition;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* What a {@link FileRoute} handler resolves to: a stream when a disposition is
|
|
40
|
+
* set, bytes otherwise, or a string when {@link FileRoute.onFileNotFound} is
|
|
41
|
+
* overridden to return one.
|
|
42
|
+
*/
|
|
43
|
+
type FileRouteRes = ReadableStream<Uint8Array> | Uint8Array | string;
|
|
44
|
+
/**
|
|
45
|
+
* Serves one file at one endpoint.
|
|
46
|
+
*
|
|
47
|
+
* The file is read per request, not at registration, so replacing it on disk
|
|
48
|
+
* takes effect without a restart — and a file that does not exist yet is not an
|
|
49
|
+
* error until someone asks for it.
|
|
50
|
+
*
|
|
51
|
+
* How the body is sent depends on {@link FileRoute.disposition}: with one set,
|
|
52
|
+
* the file is streamed and carries a `Content-Disposition`; without one, it is
|
|
53
|
+
* read into memory and carries an exact `Content-Length`.
|
|
54
|
+
*
|
|
55
|
+
* @typeParam E - The literal endpoint type, carried so the endpoint stays
|
|
56
|
+
* narrowly typed at the call site.
|
|
57
|
+
*/
|
|
58
|
+
declare class FileRoute<E extends string = string> extends RouteBase<never, never, never, FileRouteRes, E> {
|
|
59
|
+
/**
|
|
60
|
+
* Creates a file route for subclasses, which declare
|
|
61
|
+
* {@link FileRoute.endpoint} and {@link FileRoute.filePath} as class fields
|
|
62
|
+
* and call {@link RouteBase.register} themselves.
|
|
63
|
+
*/
|
|
64
|
+
constructor();
|
|
65
|
+
/**
|
|
66
|
+
* Creates a file route and registers it on the nearest {@link App}.
|
|
67
|
+
*
|
|
68
|
+
* @param address - The {@link RouteAddress}: a `"METHOD /endpoint"` string or a
|
|
69
|
+
* method-and-endpoint pair.
|
|
70
|
+
* @param definition - A {@link FileRouteDefinition}, or just the file path when
|
|
71
|
+
* the default caching and inline sending are fine.
|
|
72
|
+
*/
|
|
73
|
+
constructor(address: RouteAddress<E>, definition: FileRouteDefinition | string);
|
|
74
|
+
/** Path to the file to serve, read fresh on every request. */
|
|
75
|
+
filePath: string;
|
|
76
|
+
/**
|
|
77
|
+
* The `Content-Disposition` to send — `"inline"` to display in the browser,
|
|
78
|
+
* `"attachment"` to download under the file's own name.
|
|
79
|
+
*
|
|
80
|
+
* Setting it also switches the route to streaming, so large downloads are
|
|
81
|
+
* never buffered. Leaving it unset sends the bytes with a `Content-Length`
|
|
82
|
+
* instead, which suits small files a client may want to cache or range over.
|
|
83
|
+
*/
|
|
84
|
+
disposition?: ContentDispositionDefinition["disposition"];
|
|
85
|
+
/**
|
|
86
|
+
* Caching policy, rendered into `Cache-Control` by
|
|
87
|
+
* {@link createCacheControlHeader}. Defaults to one hour of public caching.
|
|
88
|
+
*/
|
|
89
|
+
cache: CacheControlDefinition;
|
|
90
|
+
/**
|
|
91
|
+
* Decides what to serve when {@link FileRoute.filePath} does not exist at
|
|
92
|
+
* request time. Replace it to serve a placeholder or redirect instead of
|
|
93
|
+
* throwing.
|
|
94
|
+
*
|
|
95
|
+
* @returns The {@link FileRouteRes} to send instead.
|
|
96
|
+
* @throws {@link Exception} with {@link Status.NOT_FOUND} by default.
|
|
97
|
+
*/
|
|
98
|
+
onFileNotFound: () => Promise<FileRouteRes>;
|
|
99
|
+
/** Marks this route as {@link RouteVariant.file} for {@link App} route compilation. */
|
|
100
|
+
readonly variant: RouteVariant;
|
|
101
|
+
/** The method the file is served on. Taken from the {@link RouteAddress}; defaults to {@link Method.GET}. */
|
|
102
|
+
method: Method;
|
|
103
|
+
/** The path the file is served at. */
|
|
104
|
+
endpoint: E;
|
|
105
|
+
/**
|
|
106
|
+
* File routes take no params, search or body, so no {@link RouteConfig}
|
|
107
|
+
* schemas apply.
|
|
108
|
+
*/
|
|
109
|
+
config?: RouteConfig<never, never, never, FileRouteRes> | undefined;
|
|
110
|
+
/**
|
|
111
|
+
* Reads the file and sends it, setting the content type, caching and length or
|
|
112
|
+
* disposition headers on {@link Context.res}.
|
|
113
|
+
*
|
|
114
|
+
* @param c - The {@link Context} for the request.
|
|
115
|
+
* @returns The file body — a stream when {@link FileRoute.disposition} is set,
|
|
116
|
+
* bytes otherwise — or whatever {@link FileRoute.onFileNotFound} produced.
|
|
117
|
+
*/
|
|
118
|
+
handler: ContextHandler<never, never, never, FileRouteRes>;
|
|
119
|
+
}
|
|
120
|
+
export { FileRoute };
|
|
121
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/RouteBase/FileRoute/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEhD,OAAO,EACN,KAAK,4BAA4B,EACjC,KAAK,sBAAsB,EAI3B,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAEnC,OAAO,EACN,SAAS,EACT,KAAK,YAAY,EAEjB,YAAY,EACZ,KAAK,WAAW,EAChB,MAAM,aAAa,CAAC;AAKrB;;;GAGG;AACH,UAAU,mBAAmB;IAC5B,uFAAuF;IACvF,QAAQ,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,WAAW,CAAC,EAAE,4BAA4B,CAAC,aAAa,CAAC,CAAC;IAC1D,2DAA2D;IAC3D,KAAK,CAAC,EAAE,sBAAsB,CAAC;CAC/B;AAED;;;;GAIG;AACH,KAAK,YAAY,GAAG,cAAc,CAAC,UAAU,CAAC,GAAG,UAAU,GAAG,MAAM,CAAC;AAErE;;;;;;;;;;;;;GAaG;AACH,cAAM,SAAS,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,CAAE,SAAQ,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC;IACjG;;;;OAIG;;IAEH;;;;;;;OAOG;gBACS,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,mBAAmB,GAAG,MAAM;IAmB9E,8DAA8D;IAC9D,QAAQ,EAAG,MAAM,CAAC;IAElB;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,4BAA4B,CAAC,aAAa,CAAC,CAAC;IAE1D;;;OAGG;IACH,KAAK,EAAE,sBAAsB,CAI3B;IAEF;;;;;;;OAOG;IACH,cAAc,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,CAEzC;IAEF,uFAAuF;IACvF,SAAkB,OAAO,EAAE,YAAY,CAAqB;IAE5D,6GAA6G;IACpG,MAAM,EAAE,MAAM,CAAc;IAErC,sCAAsC;IAC7B,QAAQ,EAAG,CAAC,CAAC;IAEtB;;;OAGG;IACM,MAAM,CAAC,EAAE,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC,GAAG,SAAS,CAAC;IAE7E;;;;;;;OAOG;IACM,OAAO,EAAE,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC,CA0BjE;CACF;AAED,OAAO,EAAE,SAAS,EAAE,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ordinary route: a method, an endpoint, and a handler.
|
|
3
|
+
*
|
|
4
|
+
* {@link Route} is the {@link RouteVariant.dynamic} member of the
|
|
5
|
+
* {@link RouteBase} family and the one most code uses. The others exist for
|
|
6
|
+
* responses the framework can produce itself — files, directories, socket
|
|
7
|
+
* upgrades — while this one just runs your function.
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { Route } from "@ozanarslan/corpus";
|
|
11
|
+
*
|
|
12
|
+
* new Route("GET /users/:id", (c) => findUser(c.params.id));
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* A {@link RouteConfig} adds schemas for the body, search and params, which both
|
|
16
|
+
* validate the request and type {@link Context}, so `c.params.id` is known to be
|
|
17
|
+
* whatever the schema says it is.
|
|
18
|
+
*
|
|
19
|
+
* @module Route
|
|
20
|
+
*/
|
|
21
|
+
import type { ContextHandler } from "../../Context";
|
|
22
|
+
import { Method } from "../../Request";
|
|
23
|
+
import { RouteBase, RouteVariant, type RouteAddress, type RouteConfig } from "..";
|
|
24
|
+
/**
|
|
25
|
+
* A route handled by a function.
|
|
26
|
+
*
|
|
27
|
+
* Constructing one registers it on the nearest {@link App}, which compiles it
|
|
28
|
+
* into the server's route map at {@link App.listen} time along with whatever
|
|
29
|
+
* {@link Middleware} targets it.
|
|
30
|
+
*
|
|
31
|
+
* The type parameters are usually inferred from the {@link RouteConfig} rather
|
|
32
|
+
* than written out, and flow into the {@link Context} the handler receives.
|
|
33
|
+
*
|
|
34
|
+
* @typeParam B - Parsed {@link Context.body} type.
|
|
35
|
+
* @typeParam S - Parsed {@link Context.search} type.
|
|
36
|
+
* @typeParam P - Parsed {@link Context.params} type.
|
|
37
|
+
* @typeParam R - Response body type.
|
|
38
|
+
* @typeParam E - The literal endpoint type, carried so the endpoint stays
|
|
39
|
+
* narrowly typed at the call site.
|
|
40
|
+
*/
|
|
41
|
+
declare class Route<B = unknown, S = unknown, P = unknown, R = unknown, E extends string = string> extends RouteBase<B, S, P, R, E> {
|
|
42
|
+
/**
|
|
43
|
+
* Creates a route for subclasses, which declare
|
|
44
|
+
* {@link Route.method}, {@link Route.endpoint} and {@link Route.handler} as
|
|
45
|
+
* class fields and call {@link RouteBase.register} themselves.
|
|
46
|
+
*/
|
|
47
|
+
constructor();
|
|
48
|
+
/**
|
|
49
|
+
* Creates a route and registers it on the nearest {@link App}.
|
|
50
|
+
*
|
|
51
|
+
* @param address - The {@link RouteAddress}: a `"METHOD /endpoint"` string or a
|
|
52
|
+
* method-and-endpoint pair.
|
|
53
|
+
* @param callback - The {@link ContextHandler} that answers the request.
|
|
54
|
+
* @param model - Optional {@link RouteConfig} declaring validation schemas and
|
|
55
|
+
* per-route limits. Its schemas also type the {@link Context} the handler
|
|
56
|
+
* receives.
|
|
57
|
+
*/
|
|
58
|
+
constructor(address: RouteAddress<E>, callback: ContextHandler<B, S, P, R>, model?: RouteConfig<B, S, P, R>);
|
|
59
|
+
/** Marks this route as {@link RouteVariant.dynamic} for {@link App} route compilation. */
|
|
60
|
+
readonly variant: RouteVariant;
|
|
61
|
+
/** The {@link Method} this route answers, taken from the {@link RouteAddress}. */
|
|
62
|
+
readonly method: Method;
|
|
63
|
+
/**
|
|
64
|
+
* The path this route answers. Supports `:name` parameters and a trailing
|
|
65
|
+
* wildcard, both of which arrive in {@link Context.params}.
|
|
66
|
+
*/
|
|
67
|
+
readonly endpoint: E;
|
|
68
|
+
/**
|
|
69
|
+
* Validation schemas and per-route limits. Absent means nothing is validated —
|
|
70
|
+
* and, since {@link getContextAccess} inspects it, absent schemas are one of
|
|
71
|
+
* the signals that a surface need not be parsed at all.
|
|
72
|
+
*/
|
|
73
|
+
readonly config?: RouteConfig<B, S, P, R>;
|
|
74
|
+
/**
|
|
75
|
+
* The function that answers the request.
|
|
76
|
+
*
|
|
77
|
+
* Return a value to send it as the body, a {@link Res} to control the whole
|
|
78
|
+
* response, or nothing after mutating {@link Context.res} directly.
|
|
79
|
+
*/
|
|
80
|
+
handler: ContextHandler<B, S, P, R>;
|
|
81
|
+
}
|
|
82
|
+
export { Route };
|
|
83
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/RouteBase/Route/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACnC,OAAO,EAEN,SAAS,EACT,YAAY,EACZ,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,MAAM,aAAa,CAAC;AAGrB;;;;;;;;;;;;;;;;GAgBG;AACH,cAAM,KAAK,CACV,CAAC,GAAG,OAAO,EACX,CAAC,GAAG,OAAO,EACX,CAAC,GAAG,OAAO,EACX,CAAC,GAAG,OAAO,EACX,CAAC,SAAS,MAAM,GAAG,MAAM,CACxB,SAAQ,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACjC;;;;OAIG;;IAEH;;;;;;;;;OASG;gBAEF,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,EACxB,QAAQ,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EACpC,KAAK,CAAC,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAmBhC,0FAA0F;IAC1F,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAwB;IAEtD,kFAAkF;IAClF,QAAQ,CAAC,MAAM,EAAG,MAAM,CAAC;IAEzB;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAG,CAAC,CAAC;IAEtB;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAa;IAEtD;;;;;OAKG;IACM,OAAO,EAAG,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;CAC9C;AAED,OAAO,EAAE,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Serving a file read once at startup, optionally through a handler.
|
|
3
|
+
*
|
|
4
|
+
* {@link StaticRoute} is the {@link RouteVariant.static} member of the
|
|
5
|
+
* {@link RouteBase} family. Unlike {@link FileRoute}, which reads its file per
|
|
6
|
+
* request, this one reads at construction and holds the bytes — so the file is
|
|
7
|
+
* served from memory, and changes on disk are not picked up until the process
|
|
8
|
+
* restarts.
|
|
9
|
+
*
|
|
10
|
+
* The optional callback receives the file's contents as text, which is what
|
|
11
|
+
* makes this the route for templating: an HTML shell can have values injected
|
|
12
|
+
* into it before being sent.
|
|
13
|
+
*
|
|
14
|
+
* ```ts
|
|
15
|
+
* import { StaticRoute } from "@ozanarslan/corpus";
|
|
16
|
+
*
|
|
17
|
+
* new StaticRoute("GET /about", "./pages/about.html");
|
|
18
|
+
* new StaticRoute("GET /", "./pages/index.html", (c, html) => html.replace("{{title}}", title));
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @module StaticRoute
|
|
22
|
+
*/
|
|
23
|
+
import type { Context, ContextHandler } from "../../Context";
|
|
24
|
+
import { type CacheControlDefinition } from "../../Headers";
|
|
25
|
+
import { Method } from "../../Request";
|
|
26
|
+
import { type Res } from "../../Res";
|
|
27
|
+
import { RouteBase, RouteVariant, type RouteAddress, type RouteConfig } from "..";
|
|
28
|
+
import { type Nullable, type MaybePromise } from "../../utils/is";
|
|
29
|
+
import { XFile } from "../../XFile";
|
|
30
|
+
/**
|
|
31
|
+
* Transforms a static file's contents before they are sent.
|
|
32
|
+
*
|
|
33
|
+
* @param context - The {@link Context} for the request.
|
|
34
|
+
* @param content - The file's contents, decoded as UTF-8 text.
|
|
35
|
+
* @returns What to send: a string, raw bytes, or a {@link Res} for full control
|
|
36
|
+
* over the response.
|
|
37
|
+
* @typeParam B - Parsed {@link Context.body} type.
|
|
38
|
+
* @typeParam S - Parsed {@link Context.search} type.
|
|
39
|
+
* @typeParam P - Parsed {@link Context.params} type.
|
|
40
|
+
*/
|
|
41
|
+
type StaticRouteCallback<B = unknown, S = unknown, P = unknown> = (context: Context<B, S, P, StaticRouteRes>, content: string) => MaybePromise<StaticRouteRes>;
|
|
42
|
+
/**
|
|
43
|
+
* What a {@link StaticRoute} handler resolves to: the file's bytes when there is
|
|
44
|
+
* no callback, or whatever the {@link StaticRouteCallback} returned.
|
|
45
|
+
*/
|
|
46
|
+
type StaticRouteRes = Uint8Array | string | Res;
|
|
47
|
+
/**
|
|
48
|
+
* A {@link RouteConfig} that also carries a caching policy.
|
|
49
|
+
*
|
|
50
|
+
* @typeParam B - Parsed {@link Context.body} type.
|
|
51
|
+
* @typeParam S - Parsed {@link Context.search} type.
|
|
52
|
+
* @typeParam P - Parsed {@link Context.params} type.
|
|
53
|
+
*/
|
|
54
|
+
interface StaticRouteConfig<B = unknown, S = unknown, P = unknown> extends RouteConfig<B, S, P, StaticRouteRes> {
|
|
55
|
+
/**
|
|
56
|
+
* Caching policy for the served file. Defaults to one hour of public caching.
|
|
57
|
+
*/
|
|
58
|
+
cache?: CacheControlDefinition;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Serves a file held in memory, optionally passing it through a callback first.
|
|
62
|
+
*
|
|
63
|
+
* The file is read once during construction and kept as bytes, so every request
|
|
64
|
+
* is answered without touching the filesystem. A file that does not exist at
|
|
65
|
+
* that point is not an error — the route registers, and requests reach
|
|
66
|
+
* {@link StaticRoute.onFileNotFound} instead.
|
|
67
|
+
*
|
|
68
|
+
* @typeParam B - Parsed {@link Context.body} type.
|
|
69
|
+
* @typeParam S - Parsed {@link Context.search} type.
|
|
70
|
+
* @typeParam P - Parsed {@link Context.params} type.
|
|
71
|
+
* @typeParam E - The literal endpoint type, carried so the endpoint stays
|
|
72
|
+
* narrowly typed at the call site.
|
|
73
|
+
*/
|
|
74
|
+
declare class StaticRoute<B = unknown, S = unknown, P = unknown, E extends string = string> extends RouteBase<B, S, P, StaticRouteRes, E> {
|
|
75
|
+
/**
|
|
76
|
+
* Creates a static route for subclasses, which declare
|
|
77
|
+
* {@link StaticRoute.endpoint} and {@link StaticRoute.file} as class fields and
|
|
78
|
+
* call {@link RouteBase.register} themselves.
|
|
79
|
+
*/
|
|
80
|
+
constructor();
|
|
81
|
+
/**
|
|
82
|
+
* Creates a static route, reads its file, and registers it on the nearest
|
|
83
|
+
* {@link App}.
|
|
84
|
+
*
|
|
85
|
+
* @param address - The {@link RouteAddress}: a `"METHOD /endpoint"` string or a
|
|
86
|
+
* method-and-endpoint pair.
|
|
87
|
+
* @param filePath - Path to the file, read now rather than per request.
|
|
88
|
+
* @param callback - Optional {@link StaticRouteCallback} to transform the
|
|
89
|
+
* contents before sending. Omit it to send the file as-is.
|
|
90
|
+
* @param config - Optional {@link StaticRouteConfig} with validation schemas
|
|
91
|
+
* and a caching policy.
|
|
92
|
+
*/
|
|
93
|
+
constructor(address: RouteAddress<E>, filePath: string, callback?: StaticRouteCallback<B, S, P>, config?: StaticRouteConfig<B, S, P>);
|
|
94
|
+
/**
|
|
95
|
+
* The file this route serves. Kept for its mime type and name; the contents
|
|
96
|
+
* live in {@link StaticRoute.bytes}.
|
|
97
|
+
*/
|
|
98
|
+
file: Nullable<XFile>;
|
|
99
|
+
/**
|
|
100
|
+
* The file's contents, read at construction. `null` when the file did not
|
|
101
|
+
* exist then, which is what sends requests to
|
|
102
|
+
* {@link StaticRoute.onFileNotFound}.
|
|
103
|
+
*/
|
|
104
|
+
bytes: Nullable<Uint8Array>;
|
|
105
|
+
/**
|
|
106
|
+
* The `Cache-Control` value sent with the file, rendered from the config at
|
|
107
|
+
* construction rather than per request.
|
|
108
|
+
*/
|
|
109
|
+
cacheHeader: string;
|
|
110
|
+
/**
|
|
111
|
+
* Transforms the file's contents before they are sent. Absent means the bytes
|
|
112
|
+
* are sent unchanged.
|
|
113
|
+
*/
|
|
114
|
+
callback?: StaticRouteCallback<B, S, P>;
|
|
115
|
+
/**
|
|
116
|
+
* Decides what to serve when the file was missing at construction. Replace it
|
|
117
|
+
* to serve a placeholder or redirect instead of throwing.
|
|
118
|
+
*
|
|
119
|
+
* @returns The {@link StaticRouteRes} to send instead.
|
|
120
|
+
* @throws {@link Exception} with {@link Status.NOT_FOUND} by default.
|
|
121
|
+
*/
|
|
122
|
+
onFileNotFound: () => Promise<StaticRouteRes>;
|
|
123
|
+
/** Marks this route as {@link RouteVariant.static} for {@link App} route compilation. */
|
|
124
|
+
readonly variant: RouteVariant;
|
|
125
|
+
/** The method the file is served on. Taken from the {@link RouteAddress}; defaults to {@link Method.GET}. */
|
|
126
|
+
method: Method;
|
|
127
|
+
/** The path the file is served at. */
|
|
128
|
+
endpoint: E;
|
|
129
|
+
/**
|
|
130
|
+
* Validation schemas for the route. The caching policy is stripped out during
|
|
131
|
+
* construction, so what remains is a plain {@link RouteConfig}.
|
|
132
|
+
*/
|
|
133
|
+
config?: RouteConfig<B, S, P, StaticRouteRes>;
|
|
134
|
+
/**
|
|
135
|
+
* Sends the file, or the callback's transformation of it.
|
|
136
|
+
*
|
|
137
|
+
* The content type, caching and length headers are set from the file before
|
|
138
|
+
* the callback runs, so a callback that changes the content's length — or
|
|
139
|
+
* returns a {@link Res} of its own — should set those headers itself.
|
|
140
|
+
*
|
|
141
|
+
* @param c - The {@link Context} for the request.
|
|
142
|
+
* @returns The file's bytes, or whatever the {@link StaticRoute.callback}
|
|
143
|
+
* returned. Falls through to {@link StaticRoute.onFileNotFound} when the file
|
|
144
|
+
* was missing at construction.
|
|
145
|
+
*/
|
|
146
|
+
handler: ContextHandler<B, S, P, StaticRouteRes>;
|
|
147
|
+
}
|
|
148
|
+
export { StaticRoute };
|
|
149
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/RouteBase/StaticRoute/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEzD,OAAO,EAAuC,KAAK,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAC7F,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACnC,OAAO,EAAU,KAAK,GAAG,EAAE,MAAM,OAAO,CAAC;AACzC,OAAO,EAEN,SAAS,EACT,YAAY,EACZ,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,KAAK,QAAQ,EAAY,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AACxE,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC;;;;;;;;;;GAUG;AACH,KAAK,mBAAmB,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO,IAAI,CACjE,OAAO,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,cAAc,CAAC,EACzC,OAAO,EAAE,MAAM,KACX,YAAY,CAAC,cAAc,CAAC,CAAC;AAElC;;;GAGG;AACH,KAAK,cAAc,GAAG,UAAU,GAAG,MAAM,GAAG,GAAG,CAAC;AAEhD;;;;;;GAMG;AACH,UAAU,iBAAiB,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO,CAAE,SAAQ,WAAW,CACrF,CAAC,EACD,CAAC,EACD,CAAC,EACD,cAAc,CACd;IACA;;OAEG;IACH,KAAK,CAAC,EAAE,sBAAsB,CAAC;CAC/B;AAED;;;;;;;;;;;;;GAaG;AACH,cAAM,WAAW,CAChB,CAAC,GAAG,OAAO,EACX,CAAC,GAAG,OAAO,EACX,CAAC,GAAG,OAAO,EACX,CAAC,SAAS,MAAM,GAAG,MAAM,CACxB,SAAQ,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC,CAAC;IAC9C;;;;OAIG;;IAEH;;;;;;;;;;;OAWG;gBAEF,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,EACxB,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,mBAAmB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EACvC,MAAM,CAAC,EAAE,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IA0BpC;;;OAGG;IACH,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAQ;IAE7B;;;;OAIG;IACH,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAQ;IAEnC;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAM;IAEzB;;;OAGG;IACH,QAAQ,CAAC,EAAE,mBAAmB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAExC;;;;;;OAMG;IACH,cAAc,EAAE,MAAM,OAAO,CAAC,cAAc,CAAC,CAE3C;IAEF,yFAAyF;IACzF,SAAkB,OAAO,EAAE,YAAY,CAAuB;IAE9D,6GAA6G;IACpG,MAAM,EAAE,MAAM,CAAc;IAErC,sCAAsC;IAC7B,QAAQ,EAAG,CAAC,CAAC;IAEtB;;;OAGG;IACM,MAAM,CAAC,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,cAAc,CAAC,CAAC;IAEvD;;;;;;;;;;;OAWG;IACM,OAAO,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,cAAc,CAAC,CASvD;CACF;AAED,OAAO,EAAE,WAAW,EAAE,CAAC"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocket endpoints.
|
|
3
|
+
*
|
|
4
|
+
* {@link WebSocketRoute} is the {@link RouteVariant.websocket} member of the
|
|
5
|
+
* {@link RouteBase} family. It is the one route kind that does not produce a
|
|
6
|
+
* response: {@link App.composeRoutes} sees the variant and upgrades the
|
|
7
|
+
* connection instead, storing the route itself as the socket's data so that
|
|
8
|
+
* every later event can be dispatched back to its callbacks.
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { WebSocketRoute } from "@ozanarslan/corpus";
|
|
12
|
+
*
|
|
13
|
+
* new WebSocketRoute("/chat", {
|
|
14
|
+
* onOpen: (ws) => ws.subscribe("room"),
|
|
15
|
+
* onMessage: (ws, message) => ws.publish("room", message),
|
|
16
|
+
* });
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* Since one route instance backs every connection to that endpoint, per-socket
|
|
20
|
+
* state belongs on the socket — through Bun's `subscribe`/`publish` or a map
|
|
21
|
+
* keyed by socket — not on the route.
|
|
22
|
+
*
|
|
23
|
+
* @module WebSocketRoute
|
|
24
|
+
*/
|
|
25
|
+
import type { ContextHandler } from "../../Context";
|
|
26
|
+
import { Method } from "../../Request";
|
|
27
|
+
import { RouteBase, RouteVariant, type RouteConfig } from "..";
|
|
28
|
+
import type { ServerWebSocket } from "../../Server";
|
|
29
|
+
import type { MaybePromise } from "../../utils/is";
|
|
30
|
+
/**
|
|
31
|
+
* Runs once a connection has been upgraded and is ready.
|
|
32
|
+
*
|
|
33
|
+
* @param ws - The newly opened {@link ServerWebSocket}.
|
|
34
|
+
*/
|
|
35
|
+
type WebSocketOnOpen = (ws: ServerWebSocket) => MaybePromise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Runs when a connection closes, whichever side ended it.
|
|
38
|
+
*
|
|
39
|
+
* @param ws - The closing {@link ServerWebSocket}.
|
|
40
|
+
* @param code - The WebSocket close code, when one was sent.
|
|
41
|
+
* @param reason - The accompanying reason, when one was sent.
|
|
42
|
+
*/
|
|
43
|
+
type WebSocketOnClose = (ws: ServerWebSocket, code?: number, reason?: string) => MaybePromise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Runs for each message a client sends.
|
|
46
|
+
*
|
|
47
|
+
* @param ws - The {@link ServerWebSocket} the message arrived on.
|
|
48
|
+
* @param message - The payload: a string for text frames, a `Buffer` for binary
|
|
49
|
+
* ones.
|
|
50
|
+
*/
|
|
51
|
+
type WebSocketOnMessage = (ws: ServerWebSocket, message: string | Buffer) => MaybePromise<void>;
|
|
52
|
+
/** The socket lifecycle callbacks a {@link WebSocketRoute} is built from. */
|
|
53
|
+
interface WebSocketRouteDefinition {
|
|
54
|
+
/** Called once per connection, after the upgrade succeeds. */
|
|
55
|
+
onOpen?: WebSocketOnOpen;
|
|
56
|
+
/** Called once per connection, when it closes. */
|
|
57
|
+
onClose?: WebSocketOnClose;
|
|
58
|
+
/** Called for every message received. The only required callback — a socket that never reads has nothing to do. */
|
|
59
|
+
onMessage: WebSocketOnMessage;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* A WebSocket endpoint.
|
|
63
|
+
*
|
|
64
|
+
* Constructing one registers it on the nearest {@link App}, which upgrades
|
|
65
|
+
* matching requests rather than responding to them. The callbacks are shared by
|
|
66
|
+
* every connection to the endpoint, and each event receives the socket it
|
|
67
|
+
* concerns.
|
|
68
|
+
*
|
|
69
|
+
* @typeParam E - The literal endpoint type, carried so the endpoint stays
|
|
70
|
+
* narrowly typed at the call site.
|
|
71
|
+
*/
|
|
72
|
+
declare class WebSocketRoute<E extends string = string> extends RouteBase<never, never, never, WebSocketRoute, E> {
|
|
73
|
+
/**
|
|
74
|
+
* Creates a websocket route for subclasses, which declare
|
|
75
|
+
* {@link WebSocketRoute.endpoint} and the callbacks as class fields and call
|
|
76
|
+
* {@link RouteBase.register} themselves.
|
|
77
|
+
*/
|
|
78
|
+
constructor();
|
|
79
|
+
/**
|
|
80
|
+
* Creates a websocket route and registers it on the nearest {@link App}.
|
|
81
|
+
*
|
|
82
|
+
* @param endpoint - The path clients connect to.
|
|
83
|
+
* @param definition - The {@link WebSocketRouteDefinition} holding the socket
|
|
84
|
+
* lifecycle callbacks.
|
|
85
|
+
*/
|
|
86
|
+
constructor(endpoint: E, definition: WebSocketRouteDefinition);
|
|
87
|
+
/**
|
|
88
|
+
* Marks this route as {@link RouteVariant.websocket}, which is what tells
|
|
89
|
+
* {@link App.composeRoutes} to upgrade rather than respond.
|
|
90
|
+
*/
|
|
91
|
+
readonly variant: RouteVariant;
|
|
92
|
+
/** Always {@link Method.GET} — an upgrade handshake is a GET request. */
|
|
93
|
+
readonly method: Method;
|
|
94
|
+
/** The path clients connect to. */
|
|
95
|
+
endpoint: E;
|
|
96
|
+
/** No schemas apply: an upgrade request carries no body, search or params to validate. */
|
|
97
|
+
readonly config?: RouteConfig<never, never, never, WebSocketRoute<string>> | undefined;
|
|
98
|
+
/**
|
|
99
|
+
* Returns the route itself, which {@link App.composeRoutes} attaches to the
|
|
100
|
+
* socket as its data — that is how a message arriving minutes later finds its
|
|
101
|
+
* way back to {@link WebSocketRoute.onMessage}.
|
|
102
|
+
*
|
|
103
|
+
* The upgrade itself still happens in {@link App}; this handler only supplies
|
|
104
|
+
* what the socket carries.
|
|
105
|
+
*
|
|
106
|
+
* @returns This route.
|
|
107
|
+
*/
|
|
108
|
+
readonly handler: ContextHandler<never, never, never, WebSocketRoute<string>>;
|
|
109
|
+
/** Called once per connection, after the upgrade succeeds. */
|
|
110
|
+
onOpen?: WebSocketOnOpen | undefined;
|
|
111
|
+
/** Called once per connection, when it closes. */
|
|
112
|
+
onClose?: WebSocketOnClose | undefined;
|
|
113
|
+
/** Called for every message received. */
|
|
114
|
+
onMessage: WebSocketOnMessage;
|
|
115
|
+
}
|
|
116
|
+
export { WebSocketRoute, type WebSocketOnMessage, type WebSocketOnClose, type WebSocketOnOpen, type WebSocketRouteDefinition, };
|
|
117
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/RouteBase/WebSocketRoute/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAEhD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C;;;;GAIG;AACH,KAAK,eAAe,GAAG,CAAC,EAAE,EAAE,eAAe,KAAK,YAAY,CAAC,IAAI,CAAC,CAAC;AAEnE;;;;;;GAMG;AACH,KAAK,gBAAgB,GAAG,CAAC,EAAE,EAAE,eAAe,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,YAAY,CAAC,IAAI,CAAC,CAAC;AAEpG;;;;;;GAMG;AACH,KAAK,kBAAkB,GAAG,CAAC,EAAE,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,KAAK,YAAY,CAAC,IAAI,CAAC,CAAC;AAEhG,6EAA6E;AAC7E,UAAU,wBAAwB;IAEjC,8DAA8D;IAC9D,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,kDAAkD;IAClD,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,mHAAmH;IACnH,SAAS,EAAE,kBAAkB,CAAC;CAC9B;AAED;;;;;;;;;;GAUG;AACH,cAAM,cAAc,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,CAAE,SAAQ,SAAS,CAChE,KAAK,EACL,KAAK,EACL,KAAK,EACL,cAAc,EACd,CAAC,CACD;IACA;;;;OAIG;;IAEH;;;;;;OAMG;gBACS,QAAQ,EAAE,CAAC,EAAE,UAAU,EAAE,wBAAwB;IAc7D;;;OAGG;IACH,SAAkB,OAAO,EAAE,YAAY,CAA0B;IAEjE,yEAAyE;IACzE,SAAkB,MAAM,EAAE,MAAM,CAAc;IAE9C,mCAAmC;IAC1B,QAAQ,EAAG,CAAC,CAAC;IAEtB,0FAA0F;IAC1F,SAAkB,MAAM,CAAC,EAAE,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC,GAAG,SAAS,CACpF;IAGX;;;;;;;;;OASG;IACH,SAAkB,OAAO,EAAE,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC,CAChF;IAEN,8DAA8D;IAC9D,MAAM,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC;IAErC,kDAAkD;IAClD,OAAO,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC;IAEvC,yCAAyC;IACzC,SAAS,EAAG,kBAAkB,CAAC;CAC/B;AAED,OAAO,EACN,cAAc,EACd,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,wBAAwB,GAC7B,CAAC"}
|