@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,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The base every route kind extends, and the address and config types they
|
|
3
|
+
* share.
|
|
4
|
+
*
|
|
5
|
+
* {@link RouteBase} defines what {@link App} needs from a route to compile it —
|
|
6
|
+
* a {@link RouteVariant}, a {@link Method}, an endpoint, an optional
|
|
7
|
+
* {@link RouteConfig}, and a handler — plus registration and the direct-call
|
|
8
|
+
* helpers. The concrete kinds are {@link Route}, {@link StaticRoute},
|
|
9
|
+
* {@link FileRoute}, {@link BundleRoute} and {@link WebSocketRoute}; extend this
|
|
10
|
+
* class only to add a kind of your own.
|
|
11
|
+
*
|
|
12
|
+
* {@link RouteBase.handle} is worth knowing about even if you never subclass:
|
|
13
|
+
* it invokes a route's handler directly, without a server, which is how routes
|
|
14
|
+
* are unit tested and how one route can call another in process.
|
|
15
|
+
*
|
|
16
|
+
* @module RouteBase
|
|
17
|
+
*/
|
|
18
|
+
import { type ContextHandler } from "../Context";
|
|
19
|
+
import type { Schema } from "../ParserBase/SchemaParser";
|
|
20
|
+
import { Method } from "../Request";
|
|
21
|
+
import { type MaybePromise } from "../utils/is";
|
|
22
|
+
import type { ValueOf } from "../utils/object";
|
|
23
|
+
/**
|
|
24
|
+
* What kind of route this is. {@link App.composeRoutes} branches on it — a
|
|
25
|
+
* `websocket` route upgrades instead of responding, and a `bundle` route is
|
|
26
|
+
* excluded from {@link RateLimiter} by default.
|
|
27
|
+
*/
|
|
28
|
+
declare const RouteVariant: {
|
|
29
|
+
/** A file whose contents feed a handler. See {@link StaticRoute}. */
|
|
30
|
+
readonly static: "static";
|
|
31
|
+
/** A single file served as-is. See {@link FileRoute}. */
|
|
32
|
+
readonly file: "file";
|
|
33
|
+
/** A handler function. See {@link Route}. */
|
|
34
|
+
readonly dynamic: "dynamic";
|
|
35
|
+
/** A connection upgrade. See {@link WebSocketRoute}. */
|
|
36
|
+
readonly websocket: "websocket";
|
|
37
|
+
/** A directory of built files. See {@link BundleRoute}. */
|
|
38
|
+
readonly bundle: "bundle";
|
|
39
|
+
};
|
|
40
|
+
/** One of the {@link RouteVariant} values. */
|
|
41
|
+
type RouteVariant = ValueOf<typeof RouteVariant>;
|
|
42
|
+
/**
|
|
43
|
+
* The request to simulate when calling a route directly through
|
|
44
|
+
* {@link RouteBase.handle}. Every field is optional — supply only what the
|
|
45
|
+
* handler reads.
|
|
46
|
+
*
|
|
47
|
+
* @typeParam B - Body type.
|
|
48
|
+
* @typeParam S - Search type.
|
|
49
|
+
* @typeParam P - Params type.
|
|
50
|
+
*/
|
|
51
|
+
type RouteHandleInput<B, S, P> = {
|
|
52
|
+
/** The request body, already in parsed form. */
|
|
53
|
+
body?: B;
|
|
54
|
+
/** The query values, already in parsed form. */
|
|
55
|
+
search?: S;
|
|
56
|
+
/** The path parameters, which are also substituted into the endpoint. */
|
|
57
|
+
params?: P;
|
|
58
|
+
/** Headers for the synthesized request. */
|
|
59
|
+
headers?: HeadersInit;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* A route's schemas and per-route limits.
|
|
63
|
+
*
|
|
64
|
+
* The schemas do double duty: {@link SchemaParser} validates against them at
|
|
65
|
+
* request time, and their inferred output types become the {@link Context}
|
|
66
|
+
* types the handler sees. {@link getContextAccess} also reads this to decide
|
|
67
|
+
* what to parse — a surface with a schema is always parsed, since it must be
|
|
68
|
+
* validated.
|
|
69
|
+
*
|
|
70
|
+
* @typeParam B - Body type.
|
|
71
|
+
* @typeParam S - Search type.
|
|
72
|
+
* @typeParam P - Params type.
|
|
73
|
+
* @typeParam R - Response type.
|
|
74
|
+
*/
|
|
75
|
+
type RouteConfig<B = unknown, S = unknown, P = unknown, R = unknown> = {
|
|
76
|
+
/**
|
|
77
|
+
* Body size ceiling in bytes for this route, enforced by
|
|
78
|
+
* {@link enforceBodyLimit}. Tightens {@link App.maxRequestBodySize} for a
|
|
79
|
+
* single endpoint — an upload route and a JSON route rarely want the same
|
|
80
|
+
* limit.
|
|
81
|
+
*/
|
|
82
|
+
maxRequestBodySize?: number;
|
|
83
|
+
/** Schema for the response body. Types the handler's return value. */
|
|
84
|
+
response?: Schema<R>;
|
|
85
|
+
/** Schema for the request body. Validated before the handler runs. */
|
|
86
|
+
body?: Schema<B>;
|
|
87
|
+
/** Schema for the query string. Validated before the handler runs. */
|
|
88
|
+
search?: Schema<S>;
|
|
89
|
+
/** Schema for the path parameters. Validated before the handler runs. */
|
|
90
|
+
params?: Schema<P>;
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Where a route lives, in any of the forms the constructors accept.
|
|
94
|
+
*
|
|
95
|
+
* A bare path means {@link Method.GET}. A `"METHOD /path"` string is the usual
|
|
96
|
+
* form, and the verb may be written in either case. The object form is what
|
|
97
|
+
* {@link resolveRouteAddress} normalizes everything into, and what
|
|
98
|
+
* {@link Controller} passes through once it has joined its prefix on.
|
|
99
|
+
*
|
|
100
|
+
* @typeParam E - The literal endpoint type.
|
|
101
|
+
*/
|
|
102
|
+
type RouteAddress<E extends string = string> = E | `${Method} ${E}` | `${Lowercase<Method>} ${E}` | {
|
|
103
|
+
method: Method;
|
|
104
|
+
endpoint: E;
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Normalizes any {@link RouteAddress} form into a method and an endpoint.
|
|
108
|
+
*
|
|
109
|
+
* The space in `"POST /users"` is what separates the verb from the path, so a
|
|
110
|
+
* string containing a space must start with a valid verb — otherwise it is a
|
|
111
|
+
* malformed address rather than a path that happens to contain a space, and it
|
|
112
|
+
* is rejected loudly at registration time instead of quietly never matching.
|
|
113
|
+
*
|
|
114
|
+
* @param address - The address to resolve, in any accepted form.
|
|
115
|
+
* @returns The endpoint and its {@link Method}, with the verb uppercased.
|
|
116
|
+
* @throws {@link Error} when a string contains a space but does not begin with
|
|
117
|
+
* an HTTP verb followed by a path.
|
|
118
|
+
*/
|
|
119
|
+
declare function resolveRouteAddress<E extends string>(address: RouteAddress<E>): {
|
|
120
|
+
endpoint: E;
|
|
121
|
+
method: Method;
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* The contract every route kind implements.
|
|
125
|
+
*
|
|
126
|
+
* Subclasses declare what they are and how they answer; this class supplies
|
|
127
|
+
* {@link RouteBase.id}, registration, and the direct-invocation helpers.
|
|
128
|
+
*
|
|
129
|
+
* The abstract members exist because {@link App} reads them while compiling —
|
|
130
|
+
* {@link RouteBase.variant} decides the pipeline shape,
|
|
131
|
+
* {@link RouteBase.config} decides what gets parsed and validated, and the rest
|
|
132
|
+
* decide where the route sits in the route map.
|
|
133
|
+
*
|
|
134
|
+
* @typeParam B - Parsed {@link Context.body} type.
|
|
135
|
+
* @typeParam S - Parsed {@link Context.search} type.
|
|
136
|
+
* @typeParam P - Parsed {@link Context.params} type.
|
|
137
|
+
* @typeParam R - Response body type.
|
|
138
|
+
* @typeParam E - The literal endpoint type.
|
|
139
|
+
*/
|
|
140
|
+
declare abstract class RouteBase<B = any, S = any, P = any, R = any, E extends string = string> {
|
|
141
|
+
/** Which kind of route this is. */
|
|
142
|
+
abstract readonly variant: RouteVariant;
|
|
143
|
+
/** The HTTP method this route answers. */
|
|
144
|
+
abstract readonly method: Method;
|
|
145
|
+
/** The path this route answers, before {@link App.prefix} is applied. */
|
|
146
|
+
abstract readonly endpoint: E;
|
|
147
|
+
/** Schemas and limits for this route, if any. */
|
|
148
|
+
abstract readonly config?: RouteConfig<B, S, P, R>;
|
|
149
|
+
/**
|
|
150
|
+
* Answers the request. Declared as a method rather than a property so
|
|
151
|
+
* subclasses can narrow its parameter types — a property declaration would
|
|
152
|
+
* make the variance error out on routes that take `never` for their inputs.
|
|
153
|
+
*
|
|
154
|
+
* @param args - The {@link ContextHandler} arguments: the {@link Context} for
|
|
155
|
+
* the request.
|
|
156
|
+
* @returns The response body, a {@link Res}, or nothing.
|
|
157
|
+
*/
|
|
158
|
+
abstract handler(...args: Parameters<ContextHandler<B, S, P, R>>): ReturnType<ContextHandler<B, S, P, R>>;
|
|
159
|
+
/**
|
|
160
|
+
* The route's identity, as `"METHOD /endpoint"`.
|
|
161
|
+
*
|
|
162
|
+
* This is what {@link Middleware.useOn} targets and what
|
|
163
|
+
* {@link Controller.routeIds} collects, so two routes sharing a method and
|
|
164
|
+
* endpoint share middlewares as well.
|
|
165
|
+
*
|
|
166
|
+
* @returns The id.
|
|
167
|
+
*/
|
|
168
|
+
get id(): string;
|
|
169
|
+
/**
|
|
170
|
+
* Appends this route to the nearest {@link App}. Called by every concrete
|
|
171
|
+
* route's constructor; a subclass that declares its members as class fields
|
|
172
|
+
* must call it itself, after those fields are initialized.
|
|
173
|
+
*/
|
|
174
|
+
register(): void;
|
|
175
|
+
/**
|
|
176
|
+
* Invokes the route's handler directly, with no server and no HTTP.
|
|
177
|
+
*
|
|
178
|
+
* The inputs are taken as already-parsed values, so nothing is decoded or
|
|
179
|
+
* validated — and no {@link Middleware} runs, since middlewares are folded in
|
|
180
|
+
* by {@link App} at compile time, not by the route. What this exercises is the
|
|
181
|
+
* handler itself, which is what makes it useful for unit tests and for calling
|
|
182
|
+
* one route's logic from another.
|
|
183
|
+
*
|
|
184
|
+
* @param data - The {@link RouteHandleInput} to build the {@link Context}
|
|
185
|
+
* from.
|
|
186
|
+
* @returns Whatever the handler returns.
|
|
187
|
+
*/
|
|
188
|
+
handle(data: RouteHandleInput<B, S, P>): MaybePromise<R>;
|
|
189
|
+
/**
|
|
190
|
+
* Builds the request a {@link RouteHandleInput} describes, so the
|
|
191
|
+
* {@link Context} that {@link RouteBase.handle} creates has a real request
|
|
192
|
+
* behind it — a handler reading {@link Context.url} or a header gets what it
|
|
193
|
+
* would have got over the wire.
|
|
194
|
+
*
|
|
195
|
+
* Params are substituted into the endpoint, so `/users/:id` becomes a concrete
|
|
196
|
+
* URL. A `FormData` body is passed through untouched, since the runtime sets
|
|
197
|
+
* its own multipart content type with the boundary; anything else is
|
|
198
|
+
* JSON-encoded.
|
|
199
|
+
*
|
|
200
|
+
* @param data - The {@link RouteHandleInput} to build from.
|
|
201
|
+
* @returns The synthesized request, addressed against {@link App.baseUrl}.
|
|
202
|
+
*/
|
|
203
|
+
request(data: RouteHandleInput<B, S, P>): Request;
|
|
204
|
+
}
|
|
205
|
+
export { RouteBase, RouteVariant, type RouteConfig, type RouteAddress, resolveRouteAddress };
|
|
206
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/RouteBase/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAW,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAGzD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAEnC,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAClE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAG9C;;;;GAIG;AACH,QAAA,MAAM,YAAY;IACjB,qEAAqE;;IAErE,yDAAyD;;IAEzD,6CAA6C;;IAE7C,wDAAwD;;IAExD,2DAA2D;;CAElD,CAAC;AAEX,8CAA8C;AAC9C,KAAK,YAAY,GAAG,OAAO,CAAC,OAAO,YAAY,CAAC,CAAC;AAEjD;;;;;;;;GAQG;AACH,KAAK,gBAAgB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI;IAChC,gDAAgD;IAChD,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,gDAAgD;IAChD,MAAM,CAAC,EAAE,CAAC,CAAC;IACX,yEAAyE;IACzE,MAAM,CAAC,EAAE,CAAC,CAAC;IACX,2CAA2C;IAC3C,OAAO,CAAC,EAAE,WAAW,CAAC;CACtB,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,KAAK,WAAW,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO,IAAI;IACtE;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IACrB,sEAAsE;IACtE,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IACjB,sEAAsE;IACtE,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IACnB,yEAAyE;IACzE,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;CACnB,CAAC;AAEF;;;;;;;;;GASG;AACH,KAAK,YAAY,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IACxC,CAAC,GACD,GAAG,MAAM,IAAI,CAAC,EAAE,GAChB,GAAG,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,GAC3B;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,CAAC,CAAA;CAAE,CAAC;AAEnC;;;;;;;;;;;;GAYG;AACH,iBAAS,mBAAmB,CAAC,CAAC,SAAS,MAAM,EAC5C,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,GACtB;IAAE,QAAQ,EAAE,CAAC,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAcjC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,uBAAe,SAAS,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM;IACrF,mCAAmC;IACnC,QAAQ,CAAC,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAExC,0CAA0C;IAC1C,QAAQ,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAEjC,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC;IAE9B,iDAAiD;IACjD,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAGnD;;;;;;;;OAQG;IACH,QAAQ,CAAC,OAAO,CACf,GAAG,IAAI,EAAE,UAAU,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,GAC7C,UAAU,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAEzC;;;;;;;;OAQG;IACH,IAAI,EAAE,IAAI,MAAM,CAEf;IAED;;;;OAIG;IACH,QAAQ;IAIR;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC;IAUxD;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,OAAO;CA+BjD;AAED,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,mBAAmB,EAAE,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type aliases for Bun's server primitives, parameterized for corpus.
|
|
3
|
+
*
|
|
4
|
+
* Bun's server and socket types take the per-connection data type as a
|
|
5
|
+
* parameter. Corpus always stores a {@link WebSocketRoute} there — that is how a
|
|
6
|
+
* live socket knows which route's callbacks to invoke — so these aliases pin it
|
|
7
|
+
* once instead of at every use site.
|
|
8
|
+
*
|
|
9
|
+
* Nothing here is a runtime construct; these are the shapes {@link App} builds
|
|
10
|
+
* and hands to `Bun.serve`.
|
|
11
|
+
*
|
|
12
|
+
* @module Server
|
|
13
|
+
*/
|
|
14
|
+
import type { Method } from "../Request";
|
|
15
|
+
import type { WebSocketRoute } from "../RouteBase/WebSocketRoute";
|
|
16
|
+
import type { Maybe, Optional, MaybePromise } from "../utils/is";
|
|
17
|
+
/**
|
|
18
|
+
* A live WebSocket connection. Its `data` is the {@link WebSocketRoute} that
|
|
19
|
+
* accepted the upgrade, which is what {@link App.createServer} dispatches the
|
|
20
|
+
* open, message and close events through.
|
|
21
|
+
*/
|
|
22
|
+
type ServerWebSocket = Bun.ServerWebSocket<WebSocketRoute>;
|
|
23
|
+
/** The running Bun server, as held by {@link App.server}. */
|
|
24
|
+
type Server = Bun.Server<WebSocketRoute>;
|
|
25
|
+
/**
|
|
26
|
+
* A compiled request handler, as produced by {@link App.finalize}.
|
|
27
|
+
*
|
|
28
|
+
* This is the form both a route map entry and the `fetch` fallback take. The
|
|
29
|
+
* response is optional because a {@link WebSocketRoute} upgrades the connection
|
|
30
|
+
* instead of responding.
|
|
31
|
+
*
|
|
32
|
+
* @param request - The incoming request.
|
|
33
|
+
* @param server - The {@link Server} that accepted it.
|
|
34
|
+
* @returns The response, or nothing when the connection was upgraded.
|
|
35
|
+
*/
|
|
36
|
+
type ServerHandler = (request: Request, server: Maybe<Server>) => MaybePromise<Optional<Response>>;
|
|
37
|
+
/**
|
|
38
|
+
* The route table handed to `Bun.serve`, keyed by endpoint and then by
|
|
39
|
+
* {@link Method}. Built by {@link App.composeRoutes}; anything it does not match
|
|
40
|
+
* falls through to {@link App.composeFetch}.
|
|
41
|
+
*/
|
|
42
|
+
type ServerRouteMap = Record<string, Partial<Record<Method, ServerHandler>>>;
|
|
43
|
+
export type { Server, ServerHandler, ServerRouteMap, ServerWebSocket };
|
|
44
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/Server/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEhE;;;;GAIG;AACH,KAAK,eAAe,GAAG,GAAG,CAAC,eAAe,CAAC,cAAc,CAAC,CAAC;AAE3D,6DAA6D;AAC7D,KAAK,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;AAEzC;;;;;;;;;;GAUG;AACH,KAAK,aAAa,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,YAAY,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;AAEnG;;;;GAIG;AACH,KAAK,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;AAE7E,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,cAAc,EAAE,eAAe,EAAE,CAAC"}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File handling for the routes that serve files.
|
|
3
|
+
*
|
|
4
|
+
* {@link XFile} wraps a path with the reads, writes and path manipulation the
|
|
5
|
+
* framework needs, so {@link FileRoute}, {@link StaticRoute},
|
|
6
|
+
* {@link BundleRoute} and {@link Res.file} all go through one place instead of
|
|
7
|
+
* each reaching for `fs` and `path` themselves.
|
|
8
|
+
*
|
|
9
|
+
* It sits on both Bun's file API and Node's `fs`, choosing per operation: Bun's
|
|
10
|
+
* for streaming, Node's for everything where Bun's caching would give a stale
|
|
11
|
+
* answer.
|
|
12
|
+
*
|
|
13
|
+
* @module XFile
|
|
14
|
+
*/
|
|
15
|
+
import fs from "fs";
|
|
16
|
+
/**
|
|
17
|
+
* A file at a path.
|
|
18
|
+
*
|
|
19
|
+
* The path is the only state; nothing is read at construction, so an XFile
|
|
20
|
+
* doesn't officially exist (get it?) and can be written from scratch.
|
|
21
|
+
* The path-manipulation members — {@link XFile.name}, {@link XFile.extension},
|
|
22
|
+
* {@link XFile.sibling} — are pure string work and never touch the disk.
|
|
23
|
+
*
|
|
24
|
+
* Reads are synchronous. The routes that use it read either once at startup or
|
|
25
|
+
* per request from the OS page cache, so the simpler API is worth more than the
|
|
26
|
+
* async one.
|
|
27
|
+
*/
|
|
28
|
+
declare class XFile {
|
|
29
|
+
/** Fallback extension for extension-less files, defaults to "txt" */
|
|
30
|
+
private readonly fallbackExtension;
|
|
31
|
+
/**
|
|
32
|
+
* Creates a file handle. Nothing is read or checked until an operation asks
|
|
33
|
+
* for it.
|
|
34
|
+
*
|
|
35
|
+
* @param pathOrBunFile - The path of the file or BunFile directly.
|
|
36
|
+
* @param fallbackExtension - Fallback extension for extension-less files,
|
|
37
|
+
* defaults to "txt". It decides what {@link XFile.mimeType} reports for a file
|
|
38
|
+
* whose name carries no extension.
|
|
39
|
+
*/
|
|
40
|
+
constructor(
|
|
41
|
+
/** The path of the file or BunFile directly. */
|
|
42
|
+
pathOrBunFile: string | Bun.BunFile,
|
|
43
|
+
/** Fallback extension for extension-less files, defaults to "txt" */
|
|
44
|
+
fallbackExtension?: string);
|
|
45
|
+
/** The underlying Bun file, used for streaming. */
|
|
46
|
+
readonly bunFile: Bun.BunFile;
|
|
47
|
+
/** The path this handle points at, as given. */
|
|
48
|
+
readonly path: string;
|
|
49
|
+
/** Matches either path separator, so paths split correctly on any platform. */
|
|
50
|
+
private readonly SEP;
|
|
51
|
+
/** The extension separator. */
|
|
52
|
+
private readonly DOT;
|
|
53
|
+
/** The empty string, used as a join separator and a replacement target. */
|
|
54
|
+
private readonly EMPTY;
|
|
55
|
+
/**
|
|
56
|
+
* Joins parts with no separator.
|
|
57
|
+
*
|
|
58
|
+
* @param parts - The strings to concatenate.
|
|
59
|
+
* @returns The joined string.
|
|
60
|
+
*/
|
|
61
|
+
private readonly concat;
|
|
62
|
+
/**
|
|
63
|
+
* Reads the file content and returns it as a string.
|
|
64
|
+
* @param encoding defaults to "utf8"
|
|
65
|
+
* @returns The decoded contents.
|
|
66
|
+
* @throws {@link Error} when the file does not exist.
|
|
67
|
+
*/
|
|
68
|
+
text(encoding?: BufferEncoding): string;
|
|
69
|
+
/**
|
|
70
|
+
* Opens a readable stream to the file's content.
|
|
71
|
+
*
|
|
72
|
+
* @returns The stream. This is what the file-serving routes return for large
|
|
73
|
+
* bodies, so nothing is buffered in memory.
|
|
74
|
+
*/
|
|
75
|
+
stream(): ReadableStream<Uint8Array>;
|
|
76
|
+
/**
|
|
77
|
+
* Checks if the file exists in the file system.
|
|
78
|
+
*
|
|
79
|
+
* Deliberately uses Node's `fs` rather than Bun's: `Bun.file().exists()`
|
|
80
|
+
* caches, and this handle's `BunFile` was created before the file may have
|
|
81
|
+
* been deleted, so it would report a stale answer.
|
|
82
|
+
*
|
|
83
|
+
* @returns `true` when the file exists right now.
|
|
84
|
+
*/
|
|
85
|
+
exists(): boolean;
|
|
86
|
+
/**
|
|
87
|
+
* Writes to the file, directories are created recursively.
|
|
88
|
+
*
|
|
89
|
+
* @param data - The contents to write, replacing anything already there.
|
|
90
|
+
*/
|
|
91
|
+
write(data: string | ArrayBuffer | Uint8Array): void;
|
|
92
|
+
/**
|
|
93
|
+
* Deletes the file.
|
|
94
|
+
*
|
|
95
|
+
* @throws {@link Error} when the file does not exist.
|
|
96
|
+
*/
|
|
97
|
+
unlink(): void;
|
|
98
|
+
/**
|
|
99
|
+
* Reads the file content and returns it as a Uint8Array.
|
|
100
|
+
*
|
|
101
|
+
* @returns The raw bytes. Used where an exact `Content-Length` is wanted; see
|
|
102
|
+
* {@link XFile.stream} for the alternative.
|
|
103
|
+
* @throws {@link Error} when the file does not exist.
|
|
104
|
+
*/
|
|
105
|
+
bytes(): Buffer<ArrayBuffer>;
|
|
106
|
+
/**
|
|
107
|
+
* Returns file metadata (size, dates, etc.)
|
|
108
|
+
*
|
|
109
|
+
* @returns The stats.
|
|
110
|
+
* @throws {@link Error} when the file does not exist.
|
|
111
|
+
*/
|
|
112
|
+
stat(): fs.Stats;
|
|
113
|
+
/**
|
|
114
|
+
* Returns the file size in bytes, or null if the file doesn't exist. Unlike
|
|
115
|
+
* {@link XFile.stat}, a missing file is not an error here.
|
|
116
|
+
*
|
|
117
|
+
* @returns The size in bytes, or `null`.
|
|
118
|
+
*/
|
|
119
|
+
size(): number | null;
|
|
120
|
+
/**
|
|
121
|
+
* Copies the file to a destination path, creating directories recursively.
|
|
122
|
+
*
|
|
123
|
+
* @param dest - Where to copy it.
|
|
124
|
+
* @returns A handle to the copy, carrying this handle's fallback extension.
|
|
125
|
+
*/
|
|
126
|
+
copyTo(dest: string): XFile;
|
|
127
|
+
/**
|
|
128
|
+
* Moves (renames) the file to a destination path, creating directories recursively.
|
|
129
|
+
*
|
|
130
|
+
* @param dest - Where to move it.
|
|
131
|
+
* @returns A handle to the new location. This handle still points at the old
|
|
132
|
+
* path, which no longer exists.
|
|
133
|
+
*/
|
|
134
|
+
moveTo(dest: string): XFile;
|
|
135
|
+
/**
|
|
136
|
+
* Appends data to the file.
|
|
137
|
+
*
|
|
138
|
+
* @param data - The contents to add at the end. Unlike {@link XFile.write},
|
|
139
|
+
* parent directories are not created.
|
|
140
|
+
*/
|
|
141
|
+
append(data: string | Uint8Array): void;
|
|
142
|
+
/**
|
|
143
|
+
* Returns a new XFile pointing to a sibling path (same directory, different name).
|
|
144
|
+
*
|
|
145
|
+
* @param filename - The sibling's full name, extension included.
|
|
146
|
+
* @returns A handle to the sibling. Nothing is created on disk.
|
|
147
|
+
*/
|
|
148
|
+
sibling(filename: string): XFile;
|
|
149
|
+
/**
|
|
150
|
+
* Returns a new XFile with a different extension.
|
|
151
|
+
*
|
|
152
|
+
* @param ext - The new extension, without the leading dot.
|
|
153
|
+
* @returns A handle to the renamed path. Nothing is moved on disk.
|
|
154
|
+
*/
|
|
155
|
+
withExtension(ext: string): XFile;
|
|
156
|
+
/**
|
|
157
|
+
* The absolute directory path containing this file.
|
|
158
|
+
*
|
|
159
|
+
* @returns The directory path.
|
|
160
|
+
*/
|
|
161
|
+
get dir(): string;
|
|
162
|
+
/**
|
|
163
|
+
* The name of the file without the extension.
|
|
164
|
+
*
|
|
165
|
+
* @returns The bare name.
|
|
166
|
+
*/
|
|
167
|
+
get name(): string;
|
|
168
|
+
/**
|
|
169
|
+
* The file extension (e.g., "html", "md"), excluding the leading dot.
|
|
170
|
+
*
|
|
171
|
+
* @returns The lowercased extension, or the fallback extension when the name
|
|
172
|
+
* has none.
|
|
173
|
+
*/
|
|
174
|
+
get extension(): string;
|
|
175
|
+
/**
|
|
176
|
+
* The full name of the file, including the extension.
|
|
177
|
+
*
|
|
178
|
+
* @returns The name with its extension. This is what the file-serving routes
|
|
179
|
+
* send as the `Content-Disposition` filename.
|
|
180
|
+
*/
|
|
181
|
+
get fullname(): string;
|
|
182
|
+
/**
|
|
183
|
+
* Gets the parent directory names as an array, ordered from the immediate parent up to the root.
|
|
184
|
+
*
|
|
185
|
+
* @returns The directory names, nearest first. Empty segments are dropped, so
|
|
186
|
+
* a leading or doubled separator does not produce blanks.
|
|
187
|
+
*/
|
|
188
|
+
get parentDirs(): string[];
|
|
189
|
+
/**
|
|
190
|
+
* The standard MIME type associated with the file's extension.
|
|
191
|
+
*
|
|
192
|
+
* Resolved from the extension alone — the file's contents are never read, and
|
|
193
|
+
* it need not exist. Any parameters such as `charset` are stripped, so the
|
|
194
|
+
* result is safe to use as a bare `Content-Type`.
|
|
195
|
+
*
|
|
196
|
+
* @returns The MIME type, or `"application/octet-stream"` when the extension
|
|
197
|
+
* maps to nothing known.
|
|
198
|
+
*/
|
|
199
|
+
get mimeType(): string;
|
|
200
|
+
}
|
|
201
|
+
export { XFile };
|
|
202
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/XFile/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,MAAM,IAAI,CAAC;AAGpB;;;;;;;;;;;GAWG;AACH,cAAM,KAAK;IAaT,qEAAqE;IACrE,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAbnC;;;;;;;;OAQG;;IAEF,gDAAgD;IAChD,aAAa,EAAE,MAAM,GAAG,GAAG,CAAC,OAAO;IACnC,qEAAqE;IACpD,iBAAiB,GAAE,MAAc;IAWnD,mDAAmD;IACnD,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC;IAE9B,gDAAgD;IAChD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,+EAA+E;IAC/E,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAW;IAE/B,+BAA+B;IAC/B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAO;IAE3B,2EAA2E;IAC3E,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAM;IAE5B;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkD;IAEzE;;;;;OAKG;IACH,IAAI,CAAC,QAAQ,GAAE,cAAuB,GAAG,MAAM;IAI/C;;;;;OAKG;IACH,MAAM,IAAI,cAAc,CAAC,UAAU,CAAC;IAIpC;;;;;;;;OAQG;IACH,MAAM,IAAI,OAAO;IAOjB;;;;OAIG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,GAAG,IAAI;IAKpD;;;;OAIG;IACH,MAAM,IAAI,IAAI;IAId;;;;;;OAMG;IACH,KAAK,IAAI,MAAM,CAAC,WAAW,CAAC;IAI5B;;;;;OAKG;IACH,IAAI,IAAI,EAAE,CAAC,KAAK;IAIhB;;;;;OAKG;IACH,IAAI,IAAI,MAAM,GAAG,IAAI;IAKrB;;;;;OAKG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK;IAM3B;;;;;;OAMG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK;IAM3B;;;;;OAKG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAIvC;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK;IAIhC;;;;;OAKG;IACH,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK;IAOjC;;;;OAIG;IACH,IAAI,GAAG,IAAI,MAAM,CAEhB;IAED;;;;OAIG;IACH,IAAI,IAAI,IAAI,MAAM,CAGjB;IAED;;;;;OAKG;IACH,IAAI,SAAS,IAAI,MAAM,CAKtB;IAED;;;;;OAKG;IACH,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED;;;;;OAKG;IACH,IAAI,UAAU,IAAI,MAAM,EAAE,CAIzB;IAED;;;;;;;;;OASG;IACH,IAAI,QAAQ,IAAI,MAAM,CAIrB;CACD;AAED,OAAO,EAAE,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type { Env } from "./Config";
|
|
2
|
+
export type { ContextDataInterface } from "./Context";
|
|
3
|
+
export { parseCookieHeader, parseSetCookieHeaders } from "./Cookies";
|
|
4
|
+
export { getOrInitAppsRegistry, registerApp, getNearestApp, type AppsRegistry } from "./Globals/AppsRegistry";
|
|
5
|
+
export { getOrInitParsersRegistry, setParsersRegistry, type ParsersRegistry } from "./Globals/ParsersRegistry";
|
|
6
|
+
export { GLOBAL_SYMBOLS, Globals, type GlobalRegistry } from "./Globals";
|
|
7
|
+
export { createCacheControlHeader, createContentDispositionHeader, readHeader, patchGlobalHeaders } from "./Headers";
|
|
8
|
+
export { patchGlobalRequest } from "./Request";
|
|
9
|
+
export { resolveRouteAddress } from "./RouteBase";
|
|
10
|
+
export type { Schema, InferSchemaIn, InferSchemaOut, ValidationIssues } from "./ParserBase/SchemaParser";
|
|
11
|
+
//# sourceMappingURL=exports.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exports.d.ts","sourceRoot":"","sources":["../src/exports.ts"],"names":[],"mappings":"AAOA,YAAY,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAEpC,YAAY,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAItD,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAUrE,OAAO,EAAE,qBAAqB,EAAE,WAAW,EAAE,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAE9G,OAAO,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAE/G,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAEzE,OAAO,EAAE,wBAAwB,EAAE,8BAA8B,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAQrH,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAM/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAElD,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,cAAc,WAAW,CAAC;AAG1B,cAAc,eAAe,CAAC;AAG9B,OAAO,KAAK,CAAC,MAAM,eAAe,CAAC;AAGnC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
var $e=Object.defineProperty;var Ve=(e)=>e;function Ge(e,t){this[e]=Ve.bind(null,t)}var Ye=(e,t)=>{for(var r in t)$e(e,r,{get:t[r],enumerable:!0,configurable:!0,set:Ge.bind(t,r)})};var H=Symbol("empty");function g(e){return e!==void 0&&e!==null&&e!==H}function S(e){return!g(e)}function He(e){return ne(typeof e,["string","number","boolean","bigint"])}function _(e){if(S(e)||typeof e!=="object"||Array.isArray(e))return!1;return Object.getPrototypeOf(e)===Object.prototype}function re(e){if(S(e))return!0;if(typeof e==="string")return e.trim()==="";if(typeof e==="number")return e===0;if(_(e))return Object.keys(e).length===0;if(Array.isArray(e))return e.length===0;return!1}function ne(e,t){return t.includes(e)}function pe(e){return g(e)&&Array.isArray(e)&&e.length>0}function Xe(e,t){if(!e)throw Error(t)}function Je(e,t){if(S(e))throw Error(t)}var h=Object.assign(Xe,{present:Je});var De={$schema:"https://www.schemastore.org/package.json",name:"@ozanarslan/corpus",version:"0.0.0",description:"Small Typescript backend framework with only core utilities",keywords:["backend framework","bun serve","simple"],homepage:"https://corpus-docs.fly.dev/",bugs:{url:"https://github.com/ozanArslan2424/corpus.git/issues"},license:"MIT",author:"Ozan Arslan <ozanarslanwork@gmail.com>",repository:{type:"git",url:"git+https://github.com/ozanArslan2424/corpus.git"},files:["dist","LICENSE.txt"],type:"module",exports:{".":{types:"./dist/index.d.ts",default:"./dist/index.js"},"./package.json":"./package.json"},publishConfig:{access:"public"},scripts:{build:"bun run ./scripts/build.ts",fm:"oxfmt --write",lint:"oxlint --fix","test:simulations":"bun run ./test/ws-simulation.ts -s && bun run ./test/http-simulation.ts -s","test:all":"bun test --only-failures && bun run test:simulations"},devDependencies:{"@standard-schema/spec":"^1.1.0","@types/bun":"^1.4.0",arktype:"^2.2.3","oxc-parser":"^0.147.0","tsc-alias":"^1.9.4",zod:"^4.5.4"},peerDependencies:{typescript:"6.0.3"},inlinedDependencies:{"@standard-schema/spec":"1.1.0"}};var Re=(e)=>`${De.name}:${e}`,z={initialized:Symbol.for(Re("initialized")),apps:Symbol.for(Re("apps")),parsers:Symbol.for(Re("parsers"))};class O{static store=globalThis;static getSymbol(e){return z[e]}static create(e,t){let r=z[e];if(!(r in this.store))this.store[r]=t();return this.store[r]}static get(e){let t=z[e],r=this.store[t];return h.present(r,`Global "${String(e)}" was accessed before being created`),r}static set(e,t){let r=z[e];this.store[r]=t}static has(e){return z[e]in this.store}static delete(e){let t=z[e];delete this.store[t]}}function oe(){try{return O.get("apps")}catch{return O.create("apps",()=>[])}}function M(){let e=oe(),t=e[e.length-1];return h.present(t,"No active App, instantiate one first"),t}function be(e){oe().push(e)}function fe(e){let t=[],r=e.matchAll(/([^=;\s]+)=([^;]*)/g);for(let[,n,o]of r){if(!n)continue;t.push(Bun.Cookie.parse(`${n}=${o}`))}return t}function Ne(e){let t=[];for(let r of e)t.push(Bun.Cookie.parse(r));return t}class D extends Bun.CookieMap{constructor(...e){super(...e);Object.setPrototypeOf(this,new.target.prototype)}static fromHeader(e){let t=new D;for(let r of fe(e))t.set(r);return t}static fromSetCookieHeaders(e){let t=new D;for(let r of Ne(e))t.set(r);return t}}var a={CacheControl:"Cache-Control",ContentType:"Content-Type",ContentLength:"Content-Length",ContentDisposition:"Content-Disposition",AcceptEncoding:"Accept-Encoding",Accept:"Accept",Authorization:"Authorization",UserAgent:"User-Agent",Host:"Host",Referer:"Referer",Connection:"Connection",Upgrade:"Upgrade",Pragma:"Pragma",Date:"Date",IfNoneMatch:"If-None-Match",IfModifiedSince:"If-Modified-Since",ETag:"ETag",Expires:"Expires",LastModified:"Last-Modified",Location:"Location",WWWAuthenticate:"WWW-Authenticate",AccessControlMaxAge:"Access-Control-Max-Age",AccessControlAllowCredentials:"Access-Control-Allow-Credentials",AccessControlRequestMethod:"Access-Control-Request-Method",AccessControlExposeHeaders:"Access-Control-Expose-Headers",AccessControlAllowOrigin:"Access-Control-Allow-Origin",AccessControlAllowMethods:"Access-Control-Allow-Methods",AccessControlAllowHeaders:"Access-Control-Allow-Headers",SetCookie:"Set-Cookie",Cookie:"Cookie",Vary:"Vary",XContentTypeOptions:"X-Content-Type-Options"};function I(e){if(e.noStore)return"no-store";if(e.noCache)return"no-cache";let t=[];if(e.public)t.push("public");if(e.maxAge!==void 0)t.push(`max-age=${e.maxAge}`);if(e.immutable)t.push("immutable");return t.join(", ")}function U(e){if(e.filename===void 0)return e.disposition;return`${e.disposition}; filename="${e.filename}"`}function xe(e,t){if(!e)return null;if(e instanceof Headers)return e.get(t)??e.get(t.toLowerCase());let r=t.toLowerCase();if(Array.isArray(e)){for(let[n,o]of e)if(n.toLowerCase()===r)return o;return null}for(let n in e)if(n.toLowerCase()===r)return e[n]??null;return null}function Se(){let e=globalThis.Headers,t=e.prototype.set,r=e.prototype.get,n=Headers.prototype.append,o=Headers.prototype.has;function s(c){if(typeof c==="string")return c;else if(typeof c==="number")return c.toString();else return String(c)}function i(c){return o.call(this,c)??o.call(this,c.toLowerCase())}function d(c){return r.call(this,c)??r.call(this,c.toLowerCase())}function l(c,b){t.call(this,c,s(b))}function u(c,b){if(Array.isArray(b))for(let A of b)n.call(this,c,s(A));else n.call(this,c,s(b))}function m(c){if(c instanceof Headers)c.forEach((b,A)=>{if(A.toLowerCase()===a.SetCookie.toLowerCase())this.append(A,b);else this.set(A,b)});else{let b=Array.isArray(c)?c:Object.entries(c);for(let[A,ue]of b){let ge=s(ue);if(!ge||!ge.trim())continue;this.set(A,ge)}}}function p(c){this.set(a.CacheControl,I(c))}function L(c){this.set(a.ContentDisposition,U(c))}Headers.prototype.get=d,Headers.prototype.set=l,Headers.prototype.append=u,Headers.prototype.setMany=m,Headers.prototype.setCacheControl=p,Headers.prototype.setContentDisposition=L,globalThis.Headers=class extends e{static[Symbol.hasInstance](c){return c instanceof e}has(c){return i.call(this,c)}get(c){return d.call(this,c)}set(c,b){l.call(this,c,b)}append(c,b){u.call(this,c,b)}setMany(c){m.call(this,c)}setCacheControl(c){p.call(this,c)}setContentDisposition(c){L.call(this,c)}}}function Ze(e){let t=H;return()=>{if(t===H)t=e();return t}}function et(e){let t=H,r=()=>{if(t===H)t=e();return t};return r.set=(n)=>{t=n},r}function tt({init:e,onGet:t,onSet:r}){let n=H,o=()=>{if(n===H)n=e();if(t)n=t(n);return n};return o.set=(s)=>{if(n===H)n=e();n=r?r(s,n):s},o}var F=Object.assign(Ze,{mut:et,synced:tt});function x(e,t){return[e,t]}import E from"fs";import K from"path";class C{fallbackExtension;constructor(e,t="txt"){this.fallbackExtension=t;if(typeof e==="string")this.path=e,this.bunFile=Bun.file(e);else this.path=e.name??"",this.bunFile=e}bunFile;path;SEP=/[\\/]/;DOT=".";EMPTY="";concat=(...e)=>e.join(this.EMPTY);text(e="utf8"){return E.readFileSync(this.path,{encoding:e})}stream(){return this.bunFile.stream()}exists(){return E.existsSync(this.path)}write(e){E.mkdirSync(K.dirname(this.path),{recursive:!0}),E.writeFileSync(this.path,e instanceof ArrayBuffer?Buffer.from(e):e)}unlink(){E.unlinkSync(this.path)}bytes(){return E.readFileSync(this.path)}stat(){return E.statSync(this.path)}size(){if(!E.existsSync(this.path))return null;return E.statSync(this.path).size}copyTo(e){return E.mkdirSync(K.dirname(e),{recursive:!0}),E.copyFileSync(this.path,e),new C(e,this.fallbackExtension)}moveTo(e){return E.mkdirSync(K.dirname(e),{recursive:!0}),E.renameSync(this.path,e),new C(e,this.fallbackExtension)}append(e){E.appendFileSync(this.path,e)}sibling(e){return new C(K.join(K.dirname(this.path),e),this.fallbackExtension)}withExtension(e){return new C(K.join(K.dirname(this.path),this.concat(this.name,this.DOT,e)),this.fallbackExtension)}get dir(){return K.dirname(this.path)}get name(){return(this.path.split(this.SEP).pop()??this.path).replace(this.concat(this.DOT,this.extension),this.EMPTY)}get extension(){let e=this.path.split(this.SEP).pop()??this.EMPTY;if(!e.includes(this.DOT))return this.fallbackExtension.toLowerCase();return(e.split(this.DOT).pop()??this.fallbackExtension).toLowerCase()}get fullname(){return this.concat(this.name,this.DOT,this.extension)}get parentDirs(){let e=this.path.split(this.SEP);return e.pop(),e.filter((t)=>t.length>0).reverse()}get mimeType(){let e=Bun.file(`file.${this.extension}`).type;if(!e||e==="application/octet-stream")return"application/octet-stream";return e.split(";")[0]?.trim()??"application/octet-stream"}}var f={CONTINUE:100,SWITCHING_PROTOCOLS:101,PROCESSING:102,EARLY_HINTS:103,OK:200,CREATED:201,ACCEPTED:202,NON_AUTHORITATIVE_INFORMATION:203,NO_CONTENT:204,RESET_CONTENT:205,PARTIAL_CONTENT:206,MULTI_STATUS:207,ALREADY_REPORTED:208,IM_USED:226,MULTIPLE_CHOICES:300,MOVED_PERMANENTLY:301,FOUND:302,SEE_OTHER:303,NOT_MODIFIED:304,USE_PROXY:305,TEMPORARY_REDIRECT:307,PERMANENT_REDIRECT:308,BAD_REQUEST:400,UNAUTHORIZED:401,PAYMENT_REQUIRED:402,FORBIDDEN:403,NOT_FOUND:404,METHOD_NOT_ALLOWED:405,NOT_ACCEPTABLE:406,PROXY_AUTHENTICATION_REQUIRED:407,REQUEST_TIMEOUT:408,CONFLICT:409,GONE:410,LENGTH_REQUIRED:411,PRECONDITION_FAILED:412,PAYLOAD_TOO_LARGE:413,URI_TOO_LONG:414,UNSUPPORTED_MEDIA_TYPE:415,RANGE_NOT_SATISFIABLE:416,EXPECTATION_FAILED:417,IM_A_TEAPOT:418,MISDIRECTED_REQUEST:421,UNPROCESSABLE_ENTITY:422,LOCKED:423,FAILED_DEPENDENCY:424,TOO_EARLY:425,UPGRADE_REQUIRED:426,PRECONDITION_REQUIRED:428,TOO_MANY_REQUESTS:429,REQUEST_HEADER_FIELDS_TOO_LARGE:431,UNAVAILABLE_FOR_LEGAL_REASONS:451,INTERNAL_SERVER_ERROR:500,NOT_IMPLEMENTED:501,BAD_GATEWAY:502,SERVICE_UNAVAILABLE:503,GATEWAY_TIMEOUT:504,HTTP_VERSION_NOT_SUPPORTED:505,VARIANT_ALSO_NEGOTIATES:506,INSUFFICIENT_STORAGE:507,LOOP_DETECTED:508,NOT_EXTENDED:510,NETWORK_AUTHENTICATION_REQUIRED:511};function rt(e){if(S(e))return x(null,null);if(He(e))return x(String(e),"text/plain");if(ArrayBuffer.isView(e))return x(e,"application/octet-stream");if(typeof e!=="object")return x(String(e),null);if(e instanceof ArrayBuffer)return x(e,"application/octet-stream");if(e instanceof Blob)return x(e,e.type||null);if(e instanceof FormData)return x(e,"multipart/form-data");if(e instanceof URLSearchParams)return x(e,"application/x-www-form-urlencoded");if(e instanceof ReadableStream)return x(e,null);if(e instanceof Date)return x(e.toISOString(),"text/plain");return x(JSON.stringify(e),"application/json")}function Be(e){let t=!1,r;return new ReadableStream({start(n){r=(async()=>{try{let o=await e(n,()=>t);if(typeof o!=="function")n.close();return o}catch(o){n.error(o)}})()},async cancel(){t=!0,(await r)?.()}})}function Le(e){let t=e instanceof C?e:new C(e);if(!t.exists())throw new y(f.NOT_FOUND.toString(),f.NOT_FOUND,{filePath:t.path});return t}function nt(e,t){let r=e.set.bind(e),n=e.append.bind(e);function o(s){t().set(Bun.Cookie.parse(s))}return e.set=(...s)=>{if(r(...s),s[0].toLowerCase()===a.SetCookie.toLowerCase())o(String(s[1]))},e.append=(...s)=>{if(n(...s),s[0].toLowerCase()===a.SetCookie.toLowerCase())if(Array.isArray(s[1]))for(let i of s[1])o(String(i));else o(String(s[1]))},e}class T{constructor(e,t){this.body=S(e)?null:e,this.status=t?.status??f.OK,this.statusText=t?.statusText??"",this._cookies=F(()=>t?.cookies??new D),this._headers=F.synced({init:()=>nt(t?.headers instanceof Headers?t.headers:new Headers(t?.headers),()=>this._cookies()),onGet:(r)=>{let n=this._cookies();Headers.prototype.delete.call(r,a.SetCookie);for(let o of n.toSetCookieHeaders())Headers.prototype.append.call(r,a.SetCookie,o);return r}})}body=null;status;statusText;_headers;get headers(){return this._headers()}_cookies;get cookies(){return this._cookies()}toNativeResponse(){let e=this.body,t=this.headers,r=this.status,n=this.statusText,[o,s]=rt(e);if(g(s)&&!t.has(a.ContentType))t.set(a.ContentType,s);if(!t.has(a.XContentTypeOptions))t.set(a.XContentTypeOptions,"nosniff");return new Response(o,{headers:t,status:r,statusText:n})}sse(e,t){let r=new TextEncoder,n=Be((o,s)=>e((i)=>{if(s())return;let d="";if(g(t))d+=`retry: ${t}
|
|
3
|
+
`;if(i.id)d+=`id: ${i.id}
|
|
4
|
+
`;if(i.event)d+=`event: ${i.event}
|
|
5
|
+
`;d+=`data: ${JSON.stringify(i.data)}
|
|
6
|
+
|
|
7
|
+
`,o.enqueue(r.encode(d))}));return this.body=n,this.headers.set(a.ContentType,"text/event-stream"),this.headers.set(a.CacheControl,"no-cache"),this.headers.set(a.Connection,"keep-alive"),this}ndjson(e){let t=new TextEncoder,r=Be((n,o)=>e((s)=>{if(o())return;n.enqueue(t.encode(`${JSON.stringify(s)}
|
|
8
|
+
`))}));return this.body=r,this.headers.set(a.ContentType,"application/x-ndjson"),this.headers.set(a.CacheControl,"no-cache"),this}streamFile(e,t){let r=Le(e),n=r.stream();return this.body=n,this.headers.set(a.ContentType,r.mimeType),this.headers.set(a.ContentDisposition,U({disposition:t,filename:r.fullname})),this}file(e){let t=Le(e),r=t.bytes();return this.body=r,this.headers.set(a.ContentType,t.mimeType),this.headers.set(a.ContentLength,r.byteLength.toString()),this}redirect(e,t=302){this.status=t;let r=e instanceof URL?e.toString():e;return this.headers.set(a.Location,r),this}permanentRedirect(e){return this.redirect(e,f.MOVED_PERMANENTLY)}temporaryRedirect(e){return this.redirect(e,f.TEMPORARY_REDIRECT)}seeOther(e){return this.redirect(e,f.SEE_OTHER)}}class y extends Error{constructor(e,t,r){super(e);if(new.target!==y)return;let n="Exception must be constructed with (message, status, data?) or extended.";h.present(e,n),h.present(t,n),this.message=e,this.status=t,this.data=r}message;status;data;toRes(){if(this.data instanceof T)return this.data.status=this.status,this.data;return new T({error:this.data,message:this.message},{status:this.status})}isStatusOf(e){return typeof e==="number"?this.status===e:this.status===f[e]}}function R(){return Object.create(null)}var ot=[["json",/application\/json/],["form-urlencoded",/application\/x-www-form-urlencoded/],["form-data",/multipart\/form-data/],["text",/text\/plain/],["xml",/application\/xml|text\/xml/],["binary",/application\/octet-stream|application\/pdf|^image\/|^audio\/|^video\//]];function st(e){for(let[t,r]of ot)if(r.test(e))return t;return null}class se{async parse(e){let t=e instanceof T,r=t?e.toNativeResponse():e,n=r.headers.get(a.ContentType)??"",o=st(n);if(!r.body)return R();let s=t?r:r.clone();try{switch(o){case"json":return await this.getJsonBody(s);case"form-urlencoded":return await this.getFormUrlEncodedBody(s);case"form-data":return await this.getFormDataBody(s);case"text":case"xml":return await this.getTextBody(s,n);case"binary":return this.getBinaryBody(s);default:return await this.getUnknownBody(s,n)}}catch(i){if(i instanceof SyntaxError)throw new y(i.message,f.BAD_REQUEST,{contentType:n});throw i}}async getJsonBody(e){let t=await e.text();if(!t||t.trim().length===0)return R();return JSON.parse(t)}async getFormUrlEncodedBody(e){let t=await e.text();if(!t||t.trim().length===0)return R();let r=new URLSearchParams(t),n=N().searchParamsParser;if(!n)return Object.fromEntries(r.entries());return n.parse(r)}async getFormDataBody(e){let t=await e.formData(),r=N().formDataParser;if(!r)return Object.fromEntries(t.entries());return r.parse(t)}async getTextBody(e,t){let r=t.match(/charset=([^;]+)/i)?.[1]?.trim().toLowerCase()??null;if(!r||r==="utf-8"||r==="utf8")return e.text();let n;try{n=new TextDecoder(r)}catch{n=new TextDecoder("utf-8")}return n.decode(await e.arrayBuffer())}getBinaryBody(e){return e.body}async getUnknownBody(e,t){let r=await this.getTextBody(e,t);if(!r||r.trim().length===0)return R();try{return JSON.parse(r)}catch{return r}}}class B{newContainer(e){return e}parseKey(e){let t=[];for(let r of e.split(/[.[\]]+/).filter(Boolean)){if(!/^\d+$/.test(r)){t.push(r);continue}let n=parseInt(r);t.push(n<=1000?n:r)}return t}tryParseJSON(e){try{return JSON.parse(e)}catch{return e}}}class ie extends B{parse(e){let t=R();return e.forEach((r,n)=>{let o=this.parseKey(n),s=r instanceof File?r:this.tryParseJSON(r);this.setDeep(t,o,s)}),t}setDeep(e,t,r){let n=e;for(let d=0;d<t.length-1;d++){let l=t[d],u=t[d+1],m=this.newContainer(n);if(m[l]===void 0){let p=typeof u==="number";m[l]=p?[]:R()}n=m[l]}let o=t[t.length-1],s=this.newContainer(n),i=s[o];if(i===void 0)s[o]=r;else if(Array.isArray(i))s[o]=[...i,r];else s[o]=[i,r]}}class ae{async parse(e,t,r){if(!r)return t;let n=await r["~standard"].validate(t);if(n.issues!==void 0){let o=this.issuesToErrorMessage(e,t,n.issues);throw new y(o,f.UNPROCESSABLE_ENTITY,t)}return n.value}parseSync(e,t,r){if(!r)return t;let n=r["~standard"].validate(t),o="then"in n&&typeof n?.then==="function";if(n instanceof Promise||o)throw Error("parseSync called with async validator \u2014 use a sync schema library");if(n.issues!==void 0){let s=this.issuesToErrorMessage(e,t,n.issues);throw new y(s,f.UNPROCESSABLE_ENTITY,t)}return n.value}issuesToErrorMessage(e,t,r){if(r.length===0)return"";return r.map((n)=>{if(!n.path||n.path.length===0)return n.message;let o=n.path.map((l)=>typeof l==="object"&&l!==null&&("key"in l)?String(l.key):String(l)),s=o.join("."),i=o.reduce((l,u)=>{if(l&&typeof l==="object")return l[u];return},t),d=i!==void 0?` (received ${JSON.stringify(i)})`:"";return`in ${e} ${s}${d}: ${n.message}`}).join(`
|
|
9
|
+
`)}}class ce extends B{parse(e){let t=R();return e.forEach((r,n)=>{let o=this.parseKey(n),s=this.tryParseJSON(r);this.setDeep(t,o,s)}),t}setDeep(e,t,r){let n=e;for(let d=0;d<t.length-1;d++){let l=t[d],u=t[d+1],m=this.newContainer(n),p=typeof u==="number";if(m[l]===void 0)m[l]=p?[]:R();else if(typeof m[l]!=="object"||m[l]===null)m[l]=p?[]:R();n=m[l]}let o=t[t.length-1],s=this.newContainer(n),i=s[o];if(i===void 0)s[o]=r;else if(Array.isArray(i))s[o]=[...i,r];else s[o]=[i,r]}}class le extends B{parse(e){let t=R();for(let[r,n]of Object.entries(e))t[r]=this.tryParseJSON(decodeURIComponent(n));return t}}function N(){try{return O.get("parsers")}catch{return O.create("parsers",()=>{let e=new le,t=new ce,r=new ie,n=new se,o=new ae;return{urlParamsParser:e,searchParamsParser:t,formDataParser:r,bodyParser:n,schemaParser:o}})}}function it(e){Object.assign(N(),e)}var w={GET:"GET",POST:"POST",PUT:"PUT",PATCH:"PATCH",DELETE:"DELETE",HEAD:"HEAD",OPTIONS:"OPTIONS",CONNECT:"CONNECT",TRACE:"TRACE"};function Ce(e){return F.mut(()=>{let t=e?.cookies??new D,r=xe(e?.headers,a.Cookie);if(!r)return t;for(let n of fe(r))t.set(n);return t})}function Te(){let e=globalThis.Request;Object.defineProperties(Request.prototype,{params:{configurable:!0,enumerable:!1,writable:!0,value:R()},_cookies:{configurable:!0,enumerable:!1,writable:!0,value:void 0},cookies:{configurable:!0,enumerable:!1,get(){if(!this._cookies)this._cookies=Ce({headers:this.headers});return this._cookies()},set(t){if(!this._cookies)this._cookies=Ce({headers:this.headers});this._cookies.set(t)}}}),globalThis.Request=class extends e{constructor(t,r){super(t,r);this._cookies=Ce(r),this.params=R()}static[Symbol.hasInstance](t){return t instanceof e}params;_cookies;get cookies(){return this._cookies()}set cookies(t){this._cookies.set(t)}}}function _e(){if(O.has("initialized"))return;O.set("initialized",!0),oe(),N(),Te(),Se()}class q{constructor(e,t){this.req=e,this.server=t,this._res=F.mut(()=>new T),this._url=F(()=>new URL(this.req.url)),this.body=R(),this.params=R(),this.search=R(),this.data=R()}body;params;search;data;server;req;_res;get res(){return this._res()}set res(e){this._res.set(e)}_url;get url(){return this._url()}}function W(...e){return`/${e.map((r)=>typeof r==="number"?`${r}`:r).filter((r)=>!!r).map((r)=>r.replace(/^\/+|\/+$/g,"")).filter((r)=>r.length>0).join("/")}`}function Ue(e){return e.startsWith("/")?e:`/${e}`}var P={static:"static",file:"file",dynamic:"dynamic",websocket:"websocket",bundle:"bundle"};function k(e){if(typeof e!=="string")return e;if(!e.includes(" "))return{method:w.GET,endpoint:e};let[t,r]=e.split(" ");return h(ne(t?.toUpperCase(),Object.values(w)),`Route address cannot include whitespaces unless it starts with an HTTP verb. Received: ${e}`),h(typeof r==="string"&&r.trim()!=="",`Route address cannot include whitespaces unless it starts with an HTTP verb and ends with a path. Received: ${e}`),{method:t.toUpperCase(),endpoint:r}}class v{get id(){return`${this.method.toUpperCase()} ${this.endpoint}`}register(){M().routes.push(this)}handle(e){let t=new q(this.request(e),null);if(_(e.body))t.body=e.body;if(_(e.params))t.params=e.params;if(_(e.search))t.search=e.search;return this.handler(t)}request(e){let t=M(),r=W(t.prefix,this.endpoint);if(_(e.params))for(let[i,d]of Object.entries(e.params))r=r.replace(`:${String(i)}`,String(d));let n=new URL(r,t.baseUrl);if(_(e.search))for(let[i,d]of Object.entries(e.search))n.searchParams.set(String(i),String(d));let o=new Headers(e.headers),s=void 0;if(e.body instanceof FormData)s=e.body;else if(_(e.body))s=JSON.stringify(e.body),o.set(a.ContentType,"application/json");return new Request(n,{method:this.method,body:s,headers:o})}}var Ie={};Ye(Ie,{App:()=>Ee,BodyParser:()=>se,BundleRoute:()=>X,Config:()=>de,Context:()=>q,Controller:()=>ve,Cookies:()=>D,Cors:()=>Oe,Exception:()=>y,FileRoute:()=>J,FormDataParser:()=>ie,HeaderKey:()=>a,Method:()=>w,Middleware:()=>te,ParserBase:()=>B,RateLimiter:()=>Me,RateLimiterMemoryStore:()=>ye,Res:()=>T,Route:()=>Q,RouteBase:()=>v,RouteVariant:()=>P,SchemaParser:()=>ae,SearchParamsParser:()=>ce,StaticRoute:()=>Z,Status:()=>f,URLParamsParser:()=>le,WebSocketRoute:()=>ee,XFile:()=>C});class de{static get env(){return process.env}static get nodeEnv(){return this.env.NODE_ENV??"development"}static get isProd(){return this.nodeEnv==="production"}static get isDev(){return this.nodeEnv==="development"}static get isTest(){return this.nodeEnv==="test"}static has(e){return g(this.env[e])}static get(e,t){let r=this.env[e];if(g(r))return t?.parser?t.parser(r):r;if(t&&"fallback"in t)return t.fallback;return}static require(e,t){let r=t?this.get(e,{parser:t}):this.get(e);if(S(r))throw Error(`Required environment variable "${e}" is not set`);return r}static set(e,t){this.env[e]=String(t)}}var G=["body","search","params"];function V(){return{body:!0,search:!0,params:!0}}function we(){return{body:!1,search:!1,params:!1}}function Fe(e,t,r){let n=0,o="";for(let s=t;s<e.length;s++){let i=e[s];if(o){if(i==="\\")s++;else if(i===o)o="";continue}if(i==='"'||i==="'"||i==="`"){o=i;continue}if(i==="("||i==="["||i==="{"){n++;continue}if(i===")"||i==="]"||i==="}"){if(n--,n===0&&r(i,n)!==null)return s;continue}if(r(i,n)!==null)return s}return-1}function at(e){let t=/^\s*(?:async\s+)?([A-Za-z_$][\w$]*)\s*=>/.exec(e);if(t&&t[1]){let l=t[1].trim(),u=e.slice(t[0].length);return{firstParam:l,body:u}}let r=e.indexOf("(");if(r===-1)return null;let n=Fe(e,r,(l,u)=>u===0?-1:null);if(n===-1)return null;let o=e.slice(r+1,n),s=Fe(o,0,(l,u)=>l===","&&u===0?-1:null),i=(s===-1?o:o.slice(0,s)).trim(),d=e.slice(n+1);return{firstParam:i,body:d}}function Ke(e){if(e.includes("..."))return null;let t=we();for(let r of G)if(new RegExp(`(?<![\\w$.])${r}(?![\\w$])\\s*[,:}=]`).test(e))t[r]=!0;return t}function ct(e,t){let r=0;for(let n=t;n>=0;n--){let o=e[n];if(o==="}"||o===")"||o==="]")r++;else if(o==="{"||o==="("||o==="["){if(r--,r===0)return o==="{"?n:-1}}return-1}function lt(e){let t=e.toString();if(t.includes("[native code]"))return V();let r=at(t);if(r===null)return V();let{firstParam:n,body:o}=r;if(n.startsWith("{"))return Ke(n)??V();let s=n.split(/[\s=]/)[0]??"";if(!/^[A-Za-z_$][\w$]*$/.test(s))return V();let i=we(),d=new RegExp(`(?<![\\w$])${s}(?![\\w$])`,"g");for(let l of o.matchAll(d)){let u=o.slice(0,l.index).trimEnd();if(u.endsWith(".")&&!u.endsWith("..."))continue;let m=o.slice(l.index+s.length),p=/^\s*\??\.\s*([A-Za-z_$][\w$]*)/.exec(m);if(p){let c=p[1];if(G.includes(c))i[c]=!0;continue}let L=/^\s*\??\.?\[\s*(["'])([^"'\\]*)\1\s*\]/.exec(m);if(L){let c=L[2];if(G.includes(c))i[c]=!0;continue}if(u.endsWith("=")&&!/[=!<>]=$/.test(u)){let c=u.slice(0,-1).trimEnd();if(c.endsWith("}")){let b=ct(c,c.length-1);if(b!==-1){let A=Ke(c.slice(b));if(A===null)return V();for(let ue of G)i[ue]||=A[ue];continue}}}return V()}return i}function We(e,t){let r=we();for(let n of e){let o=lt(n);for(let s of G)r[s]||=o[s];if(G.every((s)=>r[s]))break}return{params:r.params||g(t?.params),search:r.search||g(t?.search),body:r.body||g(t?.body)}}var me={reset:"\x1B[0m",green:"\x1B[32m",red:"\x1B[31m",cyan:"\x1B[36m",yellow:"\x1B[33m",gray:"\x1B[90m",bold:"\x1B[1m",magenta:"\x1B[35m",blue:"\x1B[34m"};function Y(e,t){return me[e]+t+me.reset}function dt(){let e={};return e.log=(...t)=>console.log(...t),e.bold=(...t)=>console.log(me.bold,...t,me.reset),e.info=(...t)=>console.log(Y("cyan","i"),...t),e.success=(...t)=>console.log(Y("green","\u2713"),...t),e.error=(...t)=>console.error(Y("red","\u2717"),...t),e.debug=(...t)=>console.log(Y("gray","\xB7"),...t),e.warn=(...t)=>console.warn(Y("yellow","\u26A0"),...t),e.step=(...t)=>console.log(Y("magenta",">"),...t),e}var ut=dt(),he=new Proxy({},{get(e,t){return ut[t]}});var Pe=()=>{};function ze(...e){return(t,r)=>{let n=-1,o=(s)=>{if(s<=n)throw new y("next() called multiple times",f.INTERNAL_SERVER_ERROR);n=s;let i=e[s];if(!i)return r();let d=!1,l,u=async()=>(d=!0,l=await o(s+1),l);return(async()=>{let m=t.res,p=await i(t,u);if(p!==void 0)return p;if(!d)return await u();if(t.res!==m)return t.res;return l})()};return o(0)}}async function pt(e,t,r){let n=e.headers.get(a.ContentLength),o=n===null?NaN:parseInt(n);if(!isNaN(o)){if(o>t)throw new y("Payload too large",f.PAYLOAD_TOO_LARGE);return e}if(!e.body)return e;let s=e.headers.get(a.ContentType)??"";if(/application\/octet-stream|application\/pdf|^image\/|^audio\/|^video\//.test(s))return e;let i=e.body.getReader(),d=[],l=0;while(!0){let{done:u,value:m}=await i.read();if(u)break;if(l+=m.byteLength,l>t)throw await i.cancel(),new y("Payload too large",f.PAYLOAD_TOO_LARGE);if(r)d.push(m)}if(!r)return e;return new Response(new Blob(d),{headers:e.headers})}class Ee{constructor(e){if(e?.port)this.port=e.port;if(e?.hostname)this.hostname=e.hostname;if(e?.idleTimeout)this.idleTimeout=e.idleTimeout;if(e?.tls)this.tls=e.tls;if(e?.prefix)this.prefix=e.prefix;if(e?.maxRequestBodySize)this.maxRequestBodySize=e.maxRequestBodySize;be(this)}server=null;cors;routes=[];middlewares=new Map;port=3000;prefix="";hostname="0.0.0.0";idleTimeout;tls;maxRequestBodySize;get baseUrl(){if(g(this.server))return this.server.url.toString();return`${this.tls?"https":"http"}://${this.hostname}${this.port?`:${this.port}`:""}`}createServer(){if(g(this.server))return this.server;return this.warnUnmatchedMiddlewares(),this.server=Bun.serve({port:this.port,hostname:this.hostname,idleTimeout:this?.idleTimeout,tls:this?.tls,maxRequestBodySize:this.maxRequestBodySize,fetch:this.composeFetch(),routes:this.composeRoutes(),websocket:{open:(e)=>e.data.onOpen?.(e),message:(e,t)=>e.data.onMessage?.(e,t),close:(e,t,r)=>e.data.onClose?.(e,t,r)}}),this.server}async listen(){try{process.on("SIGINT",()=>this.close()),process.on("SIGTERM",()=>this.close()),await this.handleBeforeListen?.(),this.createServer()}catch(e){he.error(e),await this.close()}}async close(e=!0){if(await this.handleBeforeClose?.(),await this.server?.stop(e),this.server=null,de.nodeEnv!=="test")process.exit(0)}composeRoutes(){let e={};for(let t of this.routes){let r=Ue(t.endpoint),n=t.variant===P.websocket,o=r.endsWith("*"),s=ne(t.method,[w.GET,w.HEAD]),i=t.config?.maxRequestBodySize,d=[...this.findMiddlewares(t.id).map((p)=>p.handler),t.handler],l=We(d,t.config),u=N(),m=ze(...d);e[r]??={},e[r][t.method]=this.finalize(async(p)=>{if(o){let c=r.slice(0,-1),b=p.req.url.indexOf(c),A=p.req.url.slice(b+c.length).split("?")[0];if(A)p.req.params["*"]=decodeURIComponent(A)}if(l.params&&!re(p.req.params))p.params=u.urlParamsParser.parse(p.req.params),p.params=await u.schemaParser.parse("params",p.params,t.config?.params);let L=l.search?p.req.url.indexOf("?"):-1;if(L!==-1){let c=new URLSearchParams(p.req.url.slice(L+1));p.search=u.searchParamsParser.parse(c),p.search=await u.schemaParser.parse("search",p.search,t.config?.search)}if(n){if(p.server?.upgrade(p.req,{data:await m(p,Pe)})===!1)throw new y("Upgrade failed",f.UPGRADE_REQUIRED);return}if(!s){let c=p.req;if(g(i))c=await pt(p.req,i,l.body);if(l.body)p.body=await u.bodyParser.parse(c),p.body=await u.schemaParser.parse("body",p.body,t.config?.body)}return await m(p,Pe)})}return e}composeFetch(){let e=ze(...this.findMiddlewares("*").map((t)=>t.handler),this.handleNotFound);return this.finalize((t)=>{if(t.req.method===w.OPTIONS&&t.req.headers.has(a.AccessControlRequestMethod))return this.handlePreflight(t);return e(t,Pe)})}finalize(e){return async(t,r)=>{let n=this.contextFactory(t,r);try{return await this.respond(n,await e(n))}catch(o){return await this.respondWithError(n,o)}}}async respond(e,t){if(t instanceof T)e.res=t;else if(t!==void 0)e.res.body=t;return await this.cors?.handler(e),e.res.toNativeResponse()}async respondWithError(e,t){try{return await this.respond(e,await this.handleError(t,e))}catch(r){return he.error(r),new Response(null,{status:f.INTERNAL_SERVER_ERROR})}}handleBeforeListen;handleBeforeClose;handleError=(e)=>{if(e instanceof y)return e.toRes();return new T({message:"INTERNAL_SERVER_ERROR"},{status:f.INTERNAL_SERVER_ERROR})};handleNotFound=(e)=>new T({message:`${e.req.method} on ${e.req.url} does not exist.`},{status:f.NOT_FOUND});handlePreflight=(e)=>{if(S(this.cors))return new T(void 0,{status:f.NO_CONTENT});return this.cors.handlePreflight(e)};contextFactory=(e,t)=>new q(e,t);addMiddleware(e){for(let t of e.routeIds){let r=this.middlewares.get(t);if(r)r.push(e);else this.middlewares.set(t,[e])}}findMiddlewares(e){let t=e==="*"?[]:this.middlewares.get("*")??[],r=this.middlewares.get(e)??[];return[...t,...r]}warnUnmatchedMiddlewares(){let e=new Set(this.routes.map((t)=>t.id));for(let t of this.middlewares.keys()){if(t==="*"||e.has(t))continue;he.warn(`Middleware targets route id "${t}", which is not registered on this app. It will never run.`)}}}import qe from"fs";import j from"path";var Ae={assetsDir:{path:"assets",public:!0,maxAge:31536000,immutable:!0},indexHtml:{path:"index.html",noCache:!0},fallback:{public:!0,noCache:!0}};class X extends v{constructor(e,t,r){super();if(new.target!==X)return;if(h.present(e,"endpoint is required when BundleRoute is constructed directly."),h.present(t,"dir is required when BundleRoute is constructed directly."),this.endpoint=e,this.dir=t,g(r))this.definition=r;this.register()}dir;ignore=[];definition=Ae;get indexHtmlPath(){return this.definition.indexHtml.path??Ae.indexHtml.path}get assetsDirPath(){return this.definition.assetsDir.path??Ae.assetsDir.path}getEndpoints(){return qe.readdirSync(this.dir,{recursive:!0,encoding:"utf8"}).filter((e)=>qe.statSync(j.join(this.dir,e)).isFile()).map((e)=>`/${e.split(j.sep).join("/")}`)}onFileNotFound=(e)=>{throw new y(`${e} file was not found.`,f.NOT_FOUND)};resolveFile(e){let t=new C(e),r=t.exists();if(!r&&t.extension!=="html"){let n=j.join(this.dir,this.indexHtmlPath),o=new C(n);if(o.exists())t=o,r=!0}return r?t:null}resolveSubPath(e){let t=this.endpoint.endsWith("/*")?this.endpoint.slice(0,-2):this.endpoint.endsWith("*")?this.endpoint.slice(0,-1):this.endpoint,r=t&&e.startsWith(t)?e.slice(t.length):e;try{return decodeURIComponent(r)}catch{return r}}resolveTargetPath(e){let t=this.indexHtmlPath,r=e===""||e==="/"?t:e,n=this.ignore.some((o)=>{if(o.endsWith("*")){let s=o.slice(0,-1);return r.startsWith(s)||r.startsWith(`/${s}`)}return r===o||r===`/${o}`});return j.join(this.dir,n?t:r)}isTraversalAttempt(e){let t=j.resolve(this.dir),r=j.resolve(e);return r!==t&&!r.startsWith(t+j.sep)}resolveResponseData(e){let t="";if(e.fullname===this.indexHtmlPath)t=I(this.definition.indexHtml);else if(e.path.includes(`/${this.assetsDirPath}/`))t=I(this.definition.assetsDir);else if(this.definition.fallback)t=I(this.definition.fallback);if(e.extension!=="html"){let n=e.stream();return x(n,{[a.ContentType]:e.mimeType,[a.CacheControl]:t,[a.ContentDisposition]:U({disposition:"inline",filename:e.fullname})})}let r=e.bytes();return x(r,{[a.ContentType]:e.mimeType,[a.CacheControl]:t,[a.ContentLength]:r.byteLength.toString()})}variant=P.bundle;method=w.GET;endpoint;config;handler=(e)=>{let t=this.resolveSubPath(e.url.pathname),r=this.resolveTargetPath(t);if(this.isTraversalAttempt(r))return this.onFileNotFound(t);let n=this.resolveFile(r);if(S(n))return this.onFileNotFound(t);let[o,s]=this.resolveResponseData(n);return e.res.headers.setMany(s),o}}class J extends v{constructor(e,t){super();if(new.target!==J)return;h.present(e,"address is required when FileRoute is constructed directly."),h.present(t,"definition is required when FileRoute is constructed directly.");let r=k(e);if(this.endpoint=r.endpoint,this.method=r.method,typeof t==="string")this.filePath=t;else{if(this.filePath=t.filePath,g(t.disposition))this.disposition=t.disposition;if(g(t.cache))this.cache=t.cache}this.register()}filePath;disposition;cache={public:!0,maxAge:3600,noCache:!1};onFileNotFound=()=>{throw new y(f.NOT_FOUND.toString(),f.NOT_FOUND)};variant=P.file;method=w.GET;endpoint;config;handler=async(e)=>{let t=new C(this.filePath);if(!t.exists())return await this.onFileNotFound();let n=I(this.cache);if(g(this.disposition)){let s=t.stream();return e.res.headers.setMany({[a.ContentType]:t.mimeType,[a.CacheControl]:n,[a.ContentDisposition]:U({disposition:this.disposition,filename:t.fullname})}),s}let o=t.bytes();return e.res.headers.setMany({[a.ContentType]:t.mimeType,[a.CacheControl]:n,[a.ContentLength]:o.byteLength.toString()}),o}}class Q extends v{constructor(e,t,r){super();if(new.target!==Q)return;h.present(e,"address is required when Route is constructed directly."),h.present(t,"callback is required when Route is constructed directly.");let n=k(e);this.method=n.method,this.endpoint=n.endpoint,this.config=r,this.handler=t,this.register()}variant=P.dynamic;method;endpoint;config=void 0;handler}class Z extends v{constructor(e,t,r,n){super();if(new.target!==Z)return;h.present(e,"address is required when StaticRoute is constructed directly."),h.present(t,"filePath is required when StaticRoute is constructed directly.");let o=k(e);this.endpoint=o.endpoint,this.method=o.method;let{cache:s,...i}=n??{};if(this.config=i,this.cacheHeader=I(s??{public:!0,maxAge:3600,noCache:!1}),this.callback=r,this.file=new C(t),this.file.exists())this.bytes=this.file.bytes();this.register()}file=null;bytes=null;cacheHeader="";callback;onFileNotFound=()=>{throw new y(f.NOT_FOUND.toString(),f.NOT_FOUND)};variant=P.static;method=w.GET;endpoint;config;handler=(e)=>{if(S(this.file))return this.onFileNotFound();if(S(this.bytes))return this.onFileNotFound();if(e.res.headers.set(a.ContentType,this.file.mimeType),e.res.headers.set(a.CacheControl,this.cacheHeader),e.res.headers.set(a.ContentLength,this.bytes.byteLength.toString()),S(this.callback))return this.bytes;let t=new TextDecoder;return this.callback(e,t.decode(this.bytes))}}class ee extends v{constructor(e,t){super();if(new.target!==ee)return;let r="WebSocketRoute must be constructed with (path, definition) or extended.";h.present(e,r),h.present(t,r),this.endpoint=e,this.onOpen=t.onOpen,this.onClose=t.onClose,this.onMessage=t.onMessage,this.register()}variant=P.websocket;method=w.GET;endpoint;config=void 0;handler=()=>this;onOpen;onClose;onMessage}class ve{prefix;constructor(e){this.prefix=e}routeIds=new Set;beforeEach;route(...e){let[t,r,n]=e,o=k(t),s=o.method,i=W(this.prefix,o.endpoint),d=new Q({method:s,endpoint:i},async(l)=>(await this.beforeEach?.(l),await r(l)),n);return this.routeIds.add(d.id),d}staticRoute(...e){let[t,r,n,o]=e,s=k(t),i=s.method,d=W(this.prefix,s.endpoint),l=new Z({method:i,endpoint:d},r,n===void 0?void 0:async(u,m)=>(await this.beforeEach?.(u),await n(u,m)),o);return this.routeIds.add(l.id),l}fileRoute(...e){let[t,r]=e,n=k(t),o=n.method,s=W(this.prefix,n.endpoint),i=new J({method:o,endpoint:s},r);return this.routeIds.add(i.id),i}websocketRoute(...e){let[t,...r]=e,n=W(this.prefix,t),o=new ee(n,...r);return this.routeIds.add(o.id),o}bundleRoute(...e){let[t,r,n]=e,o=W(this.prefix,t),s=new X(o,r,n);return this.routeIds.add(s.id),s}}class Oe{opts;constructor(e){this.opts=e;this.register()}register(){M().cors=this}handler=(e)=>{this.applyHeaders(e.res.headers,e.req.headers.get("origin")??"")};handlePreflight=(e)=>{let t=new T(void 0,{status:f.NO_CONTENT});return this.applyHeaders(t.headers,e.req.headers.get("origin")??"",!0),t};applyHeaders(e,t,r=!1){let{allowedOrigins:n,allowedMethods:o,allowedHeaders:s,exposedHeaders:i,credentials:d,maxAge:l=86400}=this.opts??{},u=!n||n.includes("*");if(!u&&n.includes(t)||u&&d&&t)e.set(a.AccessControlAllowOrigin,t),e.append(a.Vary,"Origin");else if(u)e.set(a.AccessControlAllowOrigin,"*");if(pe(o))e.set(a.AccessControlAllowMethods,o.join(", "));if(pe(s))e.set(a.AccessControlAllowHeaders,s.join(", "));if(pe(i))e.set(a.AccessControlExposeHeaders,i.join(", "));if(r)e.set(a.AccessControlMaxAge,l);e.set(a.AccessControlAllowCredentials,g(d)?d:!1)}}class te{constructor(e){if(new.target!==te)return;h.present(e,"definition is required when Middleware is constructed directly."),this.useOn=e.useOn??"*",this.handler=e.handler,this.register()}register(){M().addMiddleware(this)}useOn="*";handler;get routeIds(){if(this.useOn==="*")return["*"];let e=Array.isArray(this.useOn)?this.useOn:[this.useOn],t=new Set;for(let r of e)if(typeof r==="string")t.add(r);else if("id"in r)t.add(r.id);else r.routeIds.forEach((n)=>t.add(n));return Array.from(t)}}import{hash as ft,randomBytes as mt}from"crypto";class ye{map=new Map;locks=new Map;get(e){return this.map.get(e)}async set(e,t){while(this.locks.has(e))await this.locks.get(e);let r;this.locks.set(e,new Promise((n)=>{r=n}));try{this.map.set(e,t)}finally{this.locks.delete(e),r()}}delete(e){this.map.delete(e)}cleanup(e){for(let[t,r]of this.map)if(r.resetAt<=e)this.delete(t)}clear(){this.map.clear()}size(){return this.map.size}}function ht(e){if(re(e)||e.length===0)return!1;if(e.includes(".")){let t=e.split(".");if(t.length!==4)return!1;return t.every((r)=>{if(!/^\d+$/.test(r))return!1;let n=Number(r);return n>=0&&n<=255&&r===String(n)})}if(e.includes(":"))try{return new URL(`http://[${e}]`),!0}catch{return!1}return!1}function ke(e,t){return ft("sha256",e).slice(0,t)}function je(){return mt(16).toString("hex")}var yt={windowMs:60000,saltRotateMs:86400000,cleanProbability:0.005,maxStoreSize:50000,limits:{authenticated:120,ipBased:60,fingerprint:20},headerNames:{limit:"RateLimit-Limit",remaining:"RateLimit-Remaining",reset:"RateLimit-Reset",retryAfter:"Retry-After"}};class Me extends te{constructor(e={}){super();this.config={...yt,...e},this.store=this.config.store??new ye,this.storedSalt=je(),this.saltRotatesAt=Date.now()+this.config.saltRotateMs,this.useOn=M().routes.filter((t)=>t.variant!==P.bundle).map((t)=>t.id),this.register()}handler=async(e,t)=>{if(!await this.getResult(e.req.headers,e.res.headers))throw new y("Too many requests",f.TOO_MANY_REQUESTS,e.res);await t()};async getResult(e,t){await this.maybeCleanStore();let[r,n]=this.getIdAndLimit(e),o=Date.now(),s=await this.store.get(r);if(s&&s.resetAt>o)s.hits++;else s={hits:1,resetAt:o+this.config.windowMs};await this.store.set(r,s);let i=s.hits<=n,d=Math.max(0,n-s.hits),l=Math.ceil(s.resetAt/1000),u=this.config.headerNames;t.set(u.limit,n.toString()),t.set(u.remaining,d.toString()),t.set(u.reset,l.toString());for(let m of Object.values(u))t.append(a.AccessControlExposeHeaders,m);if(!i){let m=Math.ceil((s.resetAt-o)/1000);t.set(u.retryAfter,m.toString())}return i}config;store;storedSalt;saltRotatesAt;getIdAndLimit(e){let t=e.get(this.config.authHeader??a.Authorization),r=t?.includes("earer ")?t.slice(7):t;if(!re(r)&&r.length>=20&&r.length<=2048)return x(`u:${ke(r,16)}`,this.config.limits.authenticated);let n=e.get("cf-connecting-ip")??e.get("x-real-ip")??e.get("x-forwarded-for")?.split(",")[0]?.trim();if(ht(n))return x(`i:${ke(n+this.salt(),16)}`,this.config.limits.ipBased);let o=[e.get("user-agent")??"no-ua",e.get("accept-language")??"no-lang",e.get("accept-encoding")??"no-enc"];return x(`f:${ke(o.join("|")+this.salt(),16)}`,this.config.limits.fingerprint)}salt(){if(Date.now()>this.saltRotatesAt)this.storedSalt=je(),this.saltRotatesAt=Date.now()+this.config.saltRotateMs;return this.storedSalt}async maybeCleanStore(){let e=await this.store.size();if(Math.random()<this.config.cleanProbability||e>this.config.maxStoreSize)await this.cleanStore()}async cleanStore(){let e=Date.now();return await this.store.cleanup(e),this.store.size()}async clearStore(){await this.store.clear()}async getStoreSize(){return this.store.size()}}_e();export{Ee as App,se as BodyParser,X as BundleRoute,Ie as C,de as Config,q as Context,ve as Controller,D as Cookies,Ie as Corpus,Oe as Cors,y as Exception,J as FileRoute,ie as FormDataParser,z as GLOBAL_SYMBOLS,O as Globals,a as HeaderKey,w as Method,te as Middleware,B as ParserBase,Me as RateLimiter,ye as RateLimiterMemoryStore,T as Res,Q as Route,v as RouteBase,P as RouteVariant,ae as SchemaParser,ce as SearchParamsParser,Z as StaticRoute,f as Status,le as URLParamsParser,ee as WebSocketRoute,C as XFile,I as createCacheControlHeader,U as createContentDispositionHeader,M as getNearestApp,oe as getOrInitAppsRegistry,N as getOrInitParsersRegistry,fe as parseCookieHeader,Ne as parseSetCookieHeaders,Se as patchGlobalHeaders,Te as patchGlobalRequest,xe as readHeader,be as registerApp,k as resolveRouteAddress,it as setParsersRegistry};
|
|
10
|
+
|
|
11
|
+
//# debugId=3549DB2BDA93F8FB64756E2164756E21
|
|
12
|
+
//# sourceMappingURL=index.js.map
|