@marko/run 0.10.0 → 0.11.0-rc.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.
@@ -1,128 +1,421 @@
1
- import type { HttpVerb } from "../vite";
2
- type OneOrMany<T> = T | T[];
3
- type NoParams = {};
4
- type AllKeys<T> = T extends T ? keyof T : never;
5
- type Simplify<T> = T extends unknown ? {
6
- [K in keyof T]: T[K];
7
- } : never;
8
- type IsObject<T> = T extends object ? T extends any[] ? 0 : T extends (...args: any[]) => any ? 0 : 1 : 0;
9
- type SuperSet<T, U extends T> = T & {
10
- [K in AllKeys<U> as K extends keyof T ? never : K]?: never;
11
- };
12
- type SuperSets<T, U extends T, K extends keyof T> = Omit<T, K> & {
13
- [P in K]: Simplify<SuperSet<T[P], U[P]>>;
14
- };
15
- export type Awaitable<T> = Promise<T> | T;
16
- export type Verb = Uppercase<HttpVerb>;
1
+ import type { StandardSchemaV1 } from "@standard-schema/spec";
2
+ export type ValidatorFn<T = unknown> = (input: T) => any;
3
+ export type Validator<T = unknown> = StandardSchemaV1<T> | ValidatorFn<T>;
4
+ export type JsonBodyValidator = Validator<unknown> | JsonBodyValidatorOptions;
5
+ export type JsonBodyValidatorOptions = {
6
+ validator?: Validator<unknown>;
7
+ maxBytes?: number;
8
+ };
9
+ export type FormBodyValidator<Ctx> = Validator<Record<string, any>> | FormBodyValidatorOptions<Ctx>;
10
+ export type FormBodyValidatorOptions<Ctx> = {
11
+ validator?: Validator<Record<string, any>>;
12
+ maxBytes?: number;
13
+ maxFiles?: number;
14
+ maxParts?: number;
15
+ maxFileBytes?: number;
16
+ onFile?(ctx: Ctx, file: Multipart): any;
17
+ };
18
+ type Schema<I, O> = [O, undefined] | [I, StandardSchemaV1.FailureResult["issues"]];
19
+ type Validated<V, Default = unknown> = V extends StandardSchemaV1<infer I, infer O> ? Schema<I, O> : V extends (...args: any[]) => infer R ? R : Default;
20
+ type Valid<V, Default = unknown> = V extends StandardSchemaV1<infer I> ? I : V extends (...args: any[]) => infer R ? R : Default;
21
+ type HttpVerbWithoutBody = "GET" | "HEAD" | "DELETE" | "OPTIONS";
22
+ type HttpVerbWithBody = "POST" | "PUT" | "PATCH";
23
+ export type HttpVerb = HttpVerbWithoutBody | HttpVerbWithBody;
24
+ export type HttpVerbOrAll = HttpVerb | "ALL";
25
+ type RouteFileType = "handler" | "middleware" | "template" | "meta" | `@${string}`;
26
+ type RouteFileGroup = {
27
+ all: File[];
28
+ handler: File | never;
29
+ template: File[];
30
+ middleware: File[];
31
+ meta: File[];
32
+ partial: File[];
33
+ };
34
+ type Simplify<T> = {
35
+ [Z in keyof T]: T[Z];
36
+ } & {};
37
+ type Keys<T> = [T] extends [never] ? never : keyof T;
38
+ type Union<T> = T[keyof T];
39
+ type IsPlainObject<T> = T extends object ? T extends (...args: any[]) => any ? false : T extends readonly any[] ? false : T extends Date ? false : true : false;
40
+ type Fallback<T, Value> = [T] extends [never] ? Value : T;
41
+ type MapTuple<T extends readonly any[], K extends keyof T[number], Value = never> = {
42
+ [I in keyof T]: Fallback<T[I][K], Value>;
43
+ };
44
+ type FindTuple<T extends readonly unknown[], K extends PropertyKey, V> = T extends readonly [infer H, ...infer R] ? H extends Record<K, V> ? H : FindTuple<R, K, V> : never;
45
+ type FilterTuple<T extends readonly unknown[], K extends PropertyKey, V> = T extends readonly [infer H, ...infer R] ? H extends Record<K, V> ? [H, ...FilterTuple<R, K, V>] : FilterTuple<R, K, V> : [];
46
+ type MergeTwo<A, B> = IsPlainObject<A> extends true ? IsPlainObject<B> extends true ? Simplify<Omit<A, keyof B> & B> : B : IsPlainObject<B> extends true ? B : {};
47
+ type MergeTuple<T extends readonly any[]> = T extends readonly [
48
+ infer A,
49
+ infer B,
50
+ ...infer Rest
51
+ ] ? MergeTuple<[MergeTwo<A, B>, ...Rest]> : T extends readonly [infer Only] ? IsPlainObject<Only> extends true ? Only : {} : {};
52
+ type MergeValidators<A, B> = IsPlainObject<A> extends true ? IsPlainObject<B> extends true ? Simplify<Omit<A, keyof B> & B> : A extends Record<"validator", Validator> ? Simplify<Omit<A, "validator"> & {
53
+ validator: B;
54
+ }> : B : B;
55
+ type MergeHandlerOptions<A, B> = [A] extends [never] ? B : [B] extends [never] ? A : {
56
+ [K in keyof A | keyof B]: K extends keyof A ? K extends keyof B ? K extends "params" | "search" | "form" | "json" ? MergeValidators<A[K], B[K]> : B[K] : A[K] : K extends keyof B ? B[K] : never;
57
+ };
58
+ type MergeHandlerOptionsTuple<T extends readonly any[]> = T extends readonly [
59
+ infer A,
60
+ infer B,
61
+ ...infer Rest
62
+ ] ? MergeHandlerOptionsTuple<[MergeHandlerOptions<A, B>, ...Rest]> : T extends readonly [infer Only] ? Only : never;
63
+ type PathParamKeys<Path extends string> = Path extends `${infer _}$${infer Param}/${infer Rest}` ? [Unescape<Param>, ...PathParamKeys<Rest>] : Path extends `${infer _}$$${infer Param}` ? [Unescape<Param>] : Path extends `${infer _}$${infer Param}` ? [Unescape<Param>] : [];
64
+ type Unescape<Escaped extends string> = Escaped extends `\`${infer Value}\`` ? Value : Escaped;
65
+ type PathParams<Path extends string, Keys extends string[] = PathParamKeys<Path>> = {
66
+ [K in Keys[number]]: string;
67
+ };
68
+ type NormalizedMetaObject<Meta, Verb extends HttpVerb> = IsPlainObject<Meta> extends true ? Verb extends keyof Meta ? Simplify<Omit<Meta, HttpVerb | keyof Meta[Verb]> & Meta[Verb]> : Simplify<Omit<Meta, HttpVerb>> : never;
69
+ export type NormalizedMeta<Meta, Verb extends HttpVerb> = IsPlainObject<Meta> extends true ? {
70
+ [K in Verb]: NormalizedMetaObject<Meta, K>;
71
+ }[Verb] : Meta;
72
+ export type NormalizedMetaLookup<T> = {
73
+ [K in HttpVerb]: IsPlainObject<T> extends 1 ? NormalizedMetaObject<T, K> : T;
74
+ };
75
+ type NormalizedMetaFiles<Files extends readonly File[], Verb extends HttpVerb> = {
76
+ [I in keyof Files]: NormalizedMeta<Files[I]["exports"], Verb>;
77
+ };
78
+ type RouteFiles<Files extends readonly File[]> = {
79
+ [Type in RouteFileType | "all" as Type extends `@${string}` ? "partial" : Type]: Type extends "all" ? Files : Type extends "handler" ? FindTuple<Files, "type", Type> : FilterTuple<Files, "type", Type>;
80
+ };
81
+ type ID = string | number;
82
+ interface File<Id extends ID = ID, Type extends RouteFileType = RouteFileType, Module = any> {
83
+ id: Id;
84
+ type: Type;
85
+ name: Type extends `@${infer P}` ? P : Type;
86
+ module: Module;
87
+ exports: Type extends "handler" ? Module : "default" extends keyof Module ? Module["default"] : Module;
88
+ }
89
+ export type RouteData = Record<string, any>;
90
+ export interface RouteDef<Path extends string = string, Verb extends HttpVerb = HttpVerb, Meta = any, Partials extends Record<string, any> = Record<string, any>, Options = RouteOptionsContainer<Path, Verb>> {
91
+ path: Path;
92
+ method: Verb;
93
+ meta: Meta;
94
+ partials: Partials;
95
+ params: Options extends [
96
+ {
97
+ params: infer T;
98
+ }
99
+ ] ? T : Simplify<PathParams<Path>>;
100
+ search: Options extends [
101
+ {
102
+ search: infer T;
103
+ }
104
+ ] ? T : undefined;
105
+ form: Verb extends HttpVerbWithBody ? Options extends [
106
+ {
107
+ form: infer T;
108
+ }
109
+ ] ? T : never : undefined;
110
+ json: Verb extends HttpVerbWithBody ? Options extends [
111
+ {
112
+ json: infer T;
113
+ }
114
+ ] ? T : never : undefined;
115
+ }
116
+ type RouteOptionsContainer<Path extends string = string, Verb extends HttpVerb = HttpVerb> = [
117
+ Path extends keyof AppPaths ? AppPaths[Path]["verbs"][Verb extends keyof AppPaths[Path]["verbs"] ? Verb : never]["options"] : never
118
+ ];
119
+ export interface Route<Def extends RouteDef = RouteDef, Data = any> {
120
+ path: Def["path"];
121
+ method: Def["method"];
122
+ meta: Def["meta"];
123
+ params: Def["params"];
124
+ search: Def["search"];
125
+ body: Fallback<Def["json"], Fallback<Def["form"], undefined>>;
126
+ data: Data extends [infer T extends RouteData] ? T : RouteData;
127
+ }
128
+ type RouteFileGroupVerb<Group extends RouteFileGroup> = (Keys<Group["handler"]["exports"]> & HttpVerb) | (Group["template"] extends [] ? never : "GET");
129
+ type RouteFileGroupMeta<Group extends RouteFileGroup, Verb extends HttpVerb> = Fallback<MergeTuple<NormalizedMetaFiles<Group["meta"], Verb>>, {}>;
130
+ type RouteFileGroupOptions<Group extends RouteFileGroup, Verb extends HttpVerb> = MergeHandlerOptionsTuple<MapTuple<TypesFromHandlerFiles<[...Group["middleware"], Group["handler"]], Verb>, "options", {}>>;
131
+ type RouteFileGroupData<Group extends RouteFileGroup, Verb extends HttpVerb> = MergeTuple<MapTuple<TypesFromHandlerFiles<[...Group["middleware"], Group["handler"]], Verb>, "data", {}>>;
132
+ type TypesFromHandlerFiles<Files extends File[], Verb extends HttpVerb> = {
133
+ [I in keyof Files]: TypesFromHandlerFile<Files[I], Verb>;
134
+ };
135
+ type TypesFromHandlerFile<F extends File, Verb extends HttpVerb> = TypesFromHandler<F["type"] extends "handler" ? F["exports"][Verb] : F["exports"], Verb>;
136
+ type TypesFromHandler<Handler, Verb extends HttpVerb> = Handler extends Typed<{}, infer Types> ? Types extends {
137
+ verb: infer HVerb;
138
+ } ? HVerb extends Verb | "ALL" ? Types : never : never : never;
139
+ type DefineRoute<Path extends string, Group extends RouteFileGroup> = {
140
+ files: Group;
141
+ verbs: {
142
+ [Verb in RouteFileGroupVerb<Group>]: {
143
+ rawOptions: RouteFileGroupOptions<Group, Verb>;
144
+ options: Fallback<Validation<RouteFileGroupOptions<Group, Verb>>, {}>;
145
+ data: RouteFileGroupData<Group, Verb>;
146
+ def: RouteDef<Path, Verb, RouteFileGroupMeta<Group, Verb>, Verb extends "GET" ? {
147
+ [File in Group["partial"][number] as File["name"] & string]: File["exports"];
148
+ } : {}>;
149
+ };
150
+ };
151
+ };
152
+ type NextHandlerResult<Data> = Typed<Promise<Response>, {
153
+ data: Data;
154
+ }>;
155
+ export type DefinePaths<Groups extends Record<string, RouteFileGroup>> = {
156
+ [Path in keyof Groups & string]: DefineRoute<Path, Groups[Path]>;
157
+ };
158
+ type HandlerFuncData<T> = T extends Typed<{}, {
159
+ data: infer Data;
160
+ }> ? Data : {};
161
+ export interface NormalizedHandlerFunction<Ctx, Options> extends HandlerFunction<Ctx, Promise<Response>> {
162
+ options: Options;
163
+ }
164
+ export type NormalizedHandler<Ctx, Verb extends HttpVerbOrAll, Return, Options> = Typed<NormalizedHandlerFunction<Ctx, Options>, HandlerTypes<Ctx, Verb, Options, Return extends readonly unknown[] ? MergeTuple<{
165
+ [I in keyof Return]: HandlerFuncData<Return[I]>;
166
+ }> : HandlerFuncData<Return>>>;
167
+ type HandlerArray<Ctx, Return extends unknown[]> = {
168
+ [K in keyof Return]: HandlerFunction<Ctx, Return[K]>;
169
+ };
170
+ type Exact<T, Shape> = T & Record<Exclude<keyof T, keyof Shape>, never>;
171
+ type DefineHandlerOptions<Verb extends HttpVerbOrAll, Ctx> = [Verb] extends [
172
+ HttpVerbWithoutBody
173
+ ] ? HandlerOptionsWithoutBody : HandlerOptionsWithBody<Ctx>;
174
+ type TypesFromHandlerFilesWithLocal<Files extends File[], Verb extends HttpVerb, Id extends ID, Options> = {
175
+ [I in keyof Files]: Files[I] extends {
176
+ id: Id;
177
+ } ? HandlerTypes<Context, Verb, Options, {}> : TypesFromHandlerFile<Files[I], Verb>;
178
+ };
179
+ type RouteFileGroupOptionsWithLocal<Group extends RouteFileGroup, Verb extends HttpVerb, Id extends ID, Options> = MergeHandlerOptionsTuple<MapTuple<TypesFromHandlerFilesWithLocal<[
180
+ ...Group["middleware"],
181
+ Group["handler"]
182
+ ], Verb, Id, Options>, "options", {}>>;
183
+ type MergedRouteOptionsForFile<Path extends keyof AppPaths, Verb extends HttpVerb, Id extends ID, Options> = Fallback<Validation<RouteFileGroupOptionsWithLocal<AppPaths[Path]["files"], Verb, Id, Options>>, {}>;
184
+ export interface RouteForFileDef<F extends File, Path extends keyof AppPaths, Verb extends HttpVerb, Options> {
185
+ path: Path;
186
+ method: Verb;
187
+ meta: Verb extends keyof AppPaths[Path]["verbs"] ? AppPaths[Path]["verbs"][Verb]["def"]["meta"] : {};
188
+ params: MergedRouteOptionsForFile<Path, Verb, F["id"], Options> extends {
189
+ params: infer T;
190
+ } ? T : Simplify<PathParams<Path & string>>;
191
+ search: MergedRouteOptionsForFile<Path, Verb, F["id"], Options> extends {
192
+ search: infer T;
193
+ } ? T : undefined;
194
+ body: Verb extends HttpVerbWithBody ? MergedRouteOptionsForFile<Path, Verb, F["id"], Options> extends {
195
+ json: infer T;
196
+ } ? T : MergedRouteOptionsForFile<Path, Verb, F["id"], Options> extends {
197
+ form: infer T;
198
+ } ? T : undefined : undefined;
199
+ data: GetUpstreamData<F, Path, Verb> extends [infer T extends RouteData] ? T : RouteData;
200
+ }
201
+ type ContextForFileWithOptions<F extends File, Verb extends HttpVerbOrAll, Options> = Union<{
202
+ [Path in PathsForFile<F>]: Union<{
203
+ [V in VerbsForPath<Path, Verb>]: V extends HttpVerb ? Context<RouteForFileDef<F, Path & keyof AppPaths, V, Options>> : never;
204
+ }>;
205
+ }>;
206
+ export type DefineHandler<F extends File, Verb extends HttpVerbOrAll> = {
207
+ <Return>(handler: HandlerFunction<ContextForFileWithOptions<F, Verb, {}> & {}, Return>): NormalizedHandler<ContextForFileWithOptions<F, Verb, {}> & {}, Verb, Return, {}>;
208
+ <const Options extends DefineHandlerOptions<Verb, ContextForFileWithOptions<F, Verb, {}> & {}>>(options: Exact<Options, DefineHandlerOptions<Verb, ContextForFileWithOptions<F, Verb, {}> & {}>>): NormalizedHandler<ContextForFileWithOptions<F, Verb, Options> & {}, Verb, {}, Options>;
209
+ <const Options extends DefineHandlerOptions<Verb, ContextForFileWithOptions<F, Verb, {}> & {}>, Return>(options: Exact<Options, DefineHandlerOptions<Verb, ContextForFileWithOptions<F, Verb, {}> & {}>>, handler: HandlerFunction<ContextForFileWithOptions<F, Verb, Options> & {}, Return>): NormalizedHandler<ContextForFileWithOptions<F, Verb, Options> & {}, Verb, Return, Options>;
210
+ <Return extends unknown[]>(handlers: HandlerArray<ContextForFileWithOptions<F, Verb, {}> & {}, Return>): NormalizedHandler<ContextForFileWithOptions<F, Verb, {}> & {}, Verb, Return, {}>;
211
+ <const Options extends DefineHandlerOptions<Verb, ContextForFileWithOptions<F, Verb, {}> & {}>, Return extends unknown[]>(options: Exact<Options, DefineHandlerOptions<Verb, ContextForFileWithOptions<F, Verb, {}> & {}>>, handlers: HandlerArray<ContextForFileWithOptions<F, Verb, Options> & {}, Return>): NormalizedHandler<ContextForFileWithOptions<F, Verb, Options> & {}, Verb, Return, Options>;
212
+ };
213
+ type TakeUntil<Arr extends any[], Id extends ID, Prev extends any[] = []> = Arr extends [infer A, ...infer Rest] ? A extends {
214
+ id: Id;
215
+ } ? Prev : TakeUntil<Rest, Id, [...Prev, A]> : [];
216
+ type GetUpstreamData<F extends File, Path extends PathsForFile<F>, Verb extends HttpVerbOrAll> = Path extends keyof AppPaths ? [
217
+ Union<{
218
+ [V in VerbsForPath<Path, Verb>]: V extends HttpVerb ? MergeTuple<MapTuple<TypesFromHandlerFiles<F["type"] extends "template" ? [
219
+ ...AppPaths[Path]["files"]["middleware"],
220
+ AppPaths[Path]["files"]["handler"]
221
+ ] : TakeUntil<[
222
+ ...AppPaths[Path]["files"]["middleware"],
223
+ AppPaths[Path]["files"]["handler"]
224
+ ], F["id"]>, V>, "data", {}>> : {};
225
+ }>
226
+ ] : {};
227
+ type HandlerReturnValue = void | undefined | null | Response | typeof MarkoRun.NotHandled | typeof MarkoRun.NotMatched;
228
+ type HandlerReturn = HandlerReturnValue | Promise<HandlerReturnValue>;
229
+ export type HandlerFunction<Ctx = Context, Return = HandlerReturn> = (ctx: Ctx, next: NextFunction) => Return extends HandlerReturn ? Return : HandlerReturn;
230
+ export interface HandlerOptionsWithoutBody {
231
+ params?: Validator<Record<string, any>>;
232
+ search?: Validator<Record<string, any>>;
233
+ }
234
+ export interface HandlerOptionsWithBody<Ctx> extends HandlerOptionsWithoutBody {
235
+ json?: JsonBodyValidator;
236
+ form?: FormBodyValidator<Ctx>;
237
+ }
238
+ export type HandlerOptions<Ctx = Context> = [Ctx] extends [
239
+ {
240
+ method: HttpVerbWithoutBody;
241
+ }
242
+ ] ? HandlerOptionsWithoutBody : HandlerOptionsWithBody<Ctx>;
243
+ export type NormalizedHandlerOptions<Ctx extends Context = Context> = {
244
+ params: ValidatorFn<Record<string, any>> | undefined;
245
+ search: ValidatorFn<Record<string, any>> | undefined;
246
+ json: Ctx["method"] extends HttpVerbWithoutBody ? undefined : {
247
+ maxBytes: number;
248
+ validator: ValidatorFn | undefined;
249
+ };
250
+ form: Ctx["method"] extends HttpVerbWithoutBody ? undefined : {
251
+ maxBytes: number;
252
+ maxFiles: number;
253
+ maxParts: number;
254
+ maxFileBytes: number;
255
+ onFile: ((ctx: Ctx, file: Multipart) => any) | undefined;
256
+ validator: ValidatorFn<Record<string, any>> | undefined;
257
+ };
258
+ };
259
+ export interface Multipart extends globalThis.File {
260
+ fieldName: string;
261
+ }
262
+ type Validation<T> = Simplify<{
263
+ [K in "params" | "search" | "form" | "json" as K extends keyof T ? K : never]: T extends Record<K, infer Value> ? Validated<Value, 1> : keyof T;
264
+ }>;
265
+ type RoutesForFile<F extends File> = {
266
+ [K in keyof AppPaths as F["id"] extends AppPaths[K]["files"]["all"][number]["id"] ? K : never]: AppPaths[K];
267
+ };
268
+ type PathsForFile<F extends File> = keyof RoutesForFile<F>;
269
+ type FilterContextByVerb<Ctx extends Context, Verb extends HttpVerbOrAll> = Verb extends HttpVerb ? Extract<Ctx, {
270
+ method: Verb;
271
+ }> : Ctx;
272
+ type MatchedPaths<Path> = Path extends string ? Path extends keyof AppPaths ? Path : Path extends `${infer Root}*` ? keyof AppPaths & `${Root}${string}` : keyof AppPaths : Path;
273
+ type AllVerbs = Union<{
274
+ [Path in keyof AppPaths]: keyof AppPaths[Path]["verbs"];
275
+ }>;
276
+ type AvailableVerbs<Scope extends keyof AppPaths | object> = Scope extends string ? {
277
+ [K in Scope]: keyof AppPaths[K]["verbs"];
278
+ }[Scope] : Scope extends {
279
+ Run: Typed<{}, {
280
+ context: {
281
+ method: infer Verb extends HttpVerb;
282
+ };
283
+ }>;
284
+ } ? Verb : Scope extends Typed<{}, {
285
+ context: {
286
+ method: infer Verb extends HttpVerb;
287
+ };
288
+ }> ? Verb : never;
289
+ type ContextForPath<Path extends keyof AppPaths, Verb extends keyof AppPaths[Path]["verbs"] = keyof AppPaths[Path]["verbs"]> = Verb extends HttpVerb ? Context<Simplify<Route<AppPaths[Path]["verbs"][Verb]["def"], [
290
+ AppPaths[Path]["verbs"][Verb]["data"]
291
+ ]>>> : never;
292
+ export type Typed<Original, Types> = Original & {
293
+ [" ~types"]: Types;
294
+ };
295
+ type VerbsForPath<Path extends keyof AppPaths, Verb extends HttpVerbOrAll = "ALL"> = Verb extends HttpVerb ? keyof AppPaths[Path]["verbs"] & Verb : keyof AppPaths[Path]["verbs"];
296
+ export type PathsForVerb<Verb extends HttpVerbOrAll = "ALL"> = Verb extends HttpVerb ? Union<{
297
+ [Path in keyof AppPaths as Verb extends keyof AppPaths[Path]["verbs"] ? Path : never]: Path;
298
+ }> : keyof AppPaths;
299
+ export type ContextForFile<F extends File, Verb extends HttpVerbOrAll = F["type"] extends "template" ? "GET" : "ALL"> = Union<{
300
+ [Path in PathsForFile<F>]: Union<{
301
+ [V in VerbsForPath<Path, Verb>]: V extends HttpVerb ? Context<Simplify<Route<AppPaths[Path]["verbs"][V]["def"], GetUpstreamData<F, Path, V>>>> : never;
302
+ }>;
303
+ }>;
304
+ export type AppPaths = App extends {
305
+ paths: infer Paths;
306
+ } ? Paths : DefineRoutes["paths"];
307
+ export interface HandlerTypes<Ctx = Context, Verb extends HttpVerbOrAll = HttpVerbOrAll, Options = HandlerOptions<Ctx>, Data = RouteData> {
308
+ context: Ctx;
309
+ verb: Verb;
310
+ options: Options;
311
+ data: Data extends RouteData ? Data : {};
312
+ }
313
+ export type Middleware<Id extends ID, Mod> = File<Id, "middleware", Mod>;
314
+ export type Handler<Id extends ID, Mod> = File<Id, "handler", Mod>;
315
+ export type Template<Id extends ID, Mod> = File<Id, "template", Mod>;
316
+ export type Meta<Id extends ID, Mod> = File<Id, "meta", Mod>;
317
+ export type PartialTemplate<Id extends ID, Name extends string, Mod> = File<Id, `@${Name}`, Mod>;
318
+ export type NamespaceVerb<Verb extends HttpVerbOrAll = "ALL"> = {
319
+ href: Href<Verb>;
320
+ };
321
+ export type GlobalNamespace = {
322
+ [Verb in HttpVerbOrAll]: NamespaceVerb<Verb>;
323
+ } & NamespaceVerb;
324
+ export type Namespace<F extends File> = Typed<(F["type"] extends "middleware" ? {
325
+ [Verb in HttpVerbOrAll]: DefineHandler<F, Verb> & NamespaceVerb<Verb>;
326
+ } : F["type"] extends "handler" ? {
327
+ [Verb in HttpVerb]: DefineHandler<F, Verb> & NamespaceVerb<Verb>;
328
+ } : {
329
+ [Verb in AllVerbs]: NamespaceVerb<Verb>;
330
+ }) & NamespaceVerb, {
331
+ context: ContextForFile<F> & {};
332
+ }>;
333
+ export type DefineRoutes<Paths = void> = {
334
+ paths: [Paths] extends [Record<string, File[]>] ? DefinePaths<{
335
+ [Path in keyof Paths & string]: RouteFiles<Paths[Path]>;
336
+ }> : Record<string, {
337
+ files: any;
338
+ verbs: Record<HttpVerbOrAll, {
339
+ rawOptions: any;
340
+ options: any;
341
+ data: any;
342
+ def: RouteDef;
343
+ }>;
344
+ }>;
345
+ };
17
346
  export interface Platform {
18
347
  }
19
- export interface Context<TRoute extends Route = AnyRoute, TVerb extends Verb = Verb> {
348
+ export interface Context<T extends Route = Route> {
349
+ readonly route: T["path"];
350
+ readonly method: T["method"];
351
+ readonly meta: T["meta"];
352
+ readonly params: T["params"];
353
+ readonly search: T["search"];
354
+ readonly body: T["body"];
355
+ readonly data: T["data"];
20
356
  readonly url: URL;
21
357
  readonly request: Request;
22
- readonly method: TVerb;
23
- readonly route: TRoute["path"];
24
- readonly params: TRoute["params"];
25
- readonly meta: NormalizedMeta<TRoute["meta"], TVerb>;
26
358
  readonly platform: Platform;
27
359
  readonly serializedGlobals: Record<string, boolean>;
28
360
  readonly parent: Context | undefined;
29
- render<T>(template: Marko.Template<T>, input: T, init?: ResponseInit): Response;
30
361
  fetch(resource: string | URL | Request, init?: RequestInit): Promise<Response>;
362
+ render<T>(template: Marko.Template<T>, input: T, init?: ResponseInit): Response;
31
363
  redirect(to: string | URL, status?: number): Response;
32
364
  back(fallback?: string | URL, status?: number): Response;
33
365
  }
34
- export type MultiRouteContext<TRoute extends Route, TVerb extends Verb = Verb, _Preserved extends TRoute = TRoute> = TRoute extends any ? TVerb extends any ? Context<Simplify<SuperSets<TRoute, _Preserved, "params">>, TVerb> : never : never;
35
- export type ParamsObject = Record<string, string>;
36
- export type InputObject = Record<PropertyKey, any>;
37
- export type NextFunction = () => Awaitable<Response>;
38
- export type HandlerLike<TRoute extends Route = AnyRoute, TVerb extends Verb = Verb> = Awaitable<OneOrMany<RouteHandler<TRoute, TVerb>>>;
39
- export type RouteHandlerResult = Response | typeof MarkoRun.NotHandled | typeof MarkoRun.NotMatched | null | void;
40
- export type RouteHandler<TRoute extends Route = AnyRoute, TVerb extends Verb = Verb> = (context: MultiRouteContext<TRoute, TVerb>, next: NextFunction) => Awaitable<RouteHandlerResult>;
41
- export interface Route<Params extends ParamsObject = ParamsObject, Meta = any, Path extends string = string> {
42
- path: Path;
43
- params: Params;
44
- meta: Meta;
45
- }
46
- type DefineRoutes<T extends Record<string, {
47
- meta?: unknown;
48
- }>> = {
49
- [K in keyof T]: K extends string ? T[K] extends {
50
- meta: infer Meta;
51
- } ? Route<PathParams<K>, Meta, K> : Route<PathParams<K>, any, K> : never;
52
- };
53
- type DefinePaths<T extends Record<string, {
54
- verb: unknown;
55
- }>, TVerb extends "get" | "post"> = {
56
- [K in keyof T]: K extends string ? T[K] extends {
57
- verb: infer V;
58
- } ? V extends TVerb ? K : never : never : never;
59
- }[keyof T];
60
- export type DefineApp<T extends {
61
- routes: Record<string, {
62
- verb: "get" | "post";
63
- meta?: unknown;
366
+ export type GetContext<Scope extends keyof AppPaths | `*` | `/${string}*` | object = "*", Verb extends AvailableVerbs<Scope extends string ? MatchedPaths<Scope> : Scope> | "ALL" = "ALL"> = Scope extends string ? {
367
+ [Path in MatchedPaths<Scope>]: Path extends keyof AppPaths ? ContextForPath<Path, Verb extends HttpVerb ? Verb & keyof AppPaths[Path]["verbs"] : keyof AppPaths[Path]["verbs"]> : never;
368
+ }[MatchedPaths<Scope>] : Scope extends {
369
+ Run: Typed<{}, {
370
+ context: infer Ctx extends Context;
64
371
  }>;
65
- }> = {
66
- routes: DefineRoutes<T["routes"]>;
67
- getPaths: DefinePaths<T["routes"], "get">;
68
- postPaths: DefinePaths<T["routes"], "post">;
69
- };
70
- export interface RouteWithHandler<Params extends ParamsObject = ParamsObject, Meta = unknown, Path extends string = string> extends Route<Params, Meta, Path> {
71
- handler: RouteHandler<this>;
372
+ } ? FilterContextByVerb<Ctx, Verb> : Scope extends Typed<{}, {
373
+ context: infer Ctx extends Context;
374
+ }> ? FilterContextByVerb<Ctx, Verb> : never;
375
+ export type NextFunction = <Data extends RouteData = RouteData>(data?: Data) => NextHandlerResult<Data>;
376
+ export interface App {
377
+ }
378
+ export interface RouteMatch<Ctx extends Context = Context> {
379
+ handler: HandlerFunction<Ctx, Promise<Response>>;
380
+ path: Ctx["route"];
381
+ params: Ctx["params"];
382
+ options: NormalizedHandlerOptions<Ctx>;
383
+ meta: Ctx["meta"];
72
384
  }
73
385
  export type Fetch<TPlatform extends Platform = Platform> = (request: Request, platform: TPlatform) => Promise<Response | void>;
74
- export type Match = (method: string, pathname: string) => RouteWithHandler | null;
75
- export type Invoke<TPlatform extends Platform = Platform> = (route: RouteWithHandler | null, request: Request, platform: TPlatform) => Promise<Response | void>;
386
+ export type Match = (method: string, pathname: string) => RouteMatch | null;
387
+ export type Invoke<TPlatform extends Platform = Platform> = (route: RouteMatch | null, request: Request, platform: TPlatform) => Promise<Response | void>;
76
388
  export interface RuntimeModule {
77
389
  fetch<TPlatform extends Platform = Platform>(...args: Parameters<Fetch<TPlatform>>): ReturnType<Fetch<TPlatform>>;
78
390
  match: Match;
79
391
  invoke<TPlatform extends Platform = Platform>(...args: Parameters<Invoke<TPlatform>>): ReturnType<Invoke<TPlatform>>;
80
392
  }
81
- type Member<T, U> = T extends T ? (U extends T ? T : never) : never;
82
- type PathParamKeys<Path extends string> = Path extends `${infer _}$${infer Param}/${infer Rest}` ? [Unescape<Param>, ...PathParamKeys<Rest>] : Path extends `${infer _}$$${infer Param}` ? [Unescape<Param>] : Path extends `${infer _}$${infer Param}` ? [Unescape<Param>] : [];
83
- type Unescape<Escaped extends string> = Escaped extends `\`${infer Value}\`` ? Value : Escaped;
84
- type PathParams<Path extends string, Keys extends string[] = PathParamKeys<Path>> = 0 extends Keys["length"] ? NoParams : {
85
- [K in Keys[number]]: string;
86
- };
87
- type Segments<T extends string, Acc extends string[] = []> = T extends "" ? Acc : T extends `${infer Left}/${infer Rest}` ? Segments<Rest, [...Acc, Left]> : [...Acc, T];
88
- type GTE<A extends any[], B extends any[]> = A["length"] extends B["length"] ? 1 : A extends [infer _Ha, ...infer Ta] ? B extends [infer _Hb, ...infer Tb] ? GTE<Ta, Tb> : 1 : 0;
89
- type MatchSegments<A extends string, B extends string> = A extends `${infer P}/${string}*` ? 1 extends GTE<Segments<B>, Segments<P>> ? `${P}/${string}` : never : Segments<B>["length"] extends Segments<A>["length"] ? A : never;
90
- type PathPattern<T extends string> = T extends `${infer Left}/\${${string}}/${infer Rest}` ? PathPattern<`${Left}/${string}/${Rest}`> : T extends `${infer Left}/\${...${string}}` ? PathPattern<`${Left}/${string}*`> : T extends `${infer Left}/\${${string}}` ? PathPattern<`${Left}/${string}`> : T;
91
- type ValidatePath<Paths extends string, Path extends string> = Paths | (Path extends `/${string}` ? MatchSegments<Member<PathPattern<Paths>, Path>, Path> : Path);
92
- type ValidateHref<Paths extends string, Href extends string> = Href extends `${infer P}#${infer H}?${infer Q}` ? `${ValidatePath<Paths, P>}#${H}?${Q}` : Href extends `${infer P}?${infer Q}` ? `${ValidatePath<Paths, P>}?${Q}` : Href extends `${infer P}#${infer H}` ? `${ValidatePath<Paths, P>}#${H}` : ValidatePath<Paths, Href>;
93
- type NormalizedMetaObject<T, TVerb extends Verb = Verb> = IsObject<T> extends 1 ? TVerb extends keyof T ? Simplify<Omit<T, Verb | keyof T[TVerb]> & T[TVerb]> : Simplify<Omit<T, Verb>> : never;
94
- export type NormalizedMeta<T, TVerb extends Verb = Verb> = IsObject<T> extends 1 ? {
95
- [K in TVerb]: NormalizedMetaObject<T, K>;
96
- }[TVerb] : T;
97
- export type NormalizedMetaLookup<T> = {
98
- [K in Verb]: IsObject<T> extends 1 ? NormalizedMetaObject<T, K> : T;
99
- };
100
- export interface AppData {
101
- }
102
- export type Routes = AppData extends {
103
- routes: infer T;
104
- } ? T : Record<string, Route>;
105
- export type AnyRoute = Routes[keyof Routes];
106
- export type HandlerTypeFn<TRoute extends Route = AnyRoute> = AppData extends {
107
- routes: any;
108
- } ? <Params extends ParamsObject = ParamsObject, Meta = any, T extends HandlerLike<Route<Params, Meta>> = HandlerLike<Route<Params, Meta>>>(handler: T) => T : <T extends HandlerLike<TRoute>>(handler: T) => T;
109
393
  type DefaultAPI = keyof Exclude<Marko.Renderable, Marko.Template<any, any> | Marko.Body<any, any> | string> extends "content" ? "tags" : "class";
110
394
  type TemplateAPI<T> = T extends {
111
395
  api: infer API;
112
396
  } ? API : DefaultAPI;
113
- export type LayoutInput<T> = TemplateAPI<T> extends "tags" ? {
397
+ export type LayoutInput<F extends File> = TemplateAPI<F["module"]> extends "tags" ? {
114
398
  content: Marko.Body;
115
399
  } : {
116
400
  renderBody: Marko.Body;
117
401
  };
118
- export type GetPaths = AppData extends {
119
- getPaths: infer T;
120
- } ? T : string;
121
- export type PostPaths = AppData extends {
122
- postPaths: infer T;
123
- } ? T : string;
124
- export type GetablePath<T extends string> = ValidatePath<GetPaths, T>;
125
- export type GetableHref<T extends string> = ValidateHref<GetPaths, T>;
126
- export type PostablePath<T extends string> = ValidatePath<PostPaths, T>;
127
- export type PostableHref<T extends string> = ValidateHref<PostPaths, T>;
402
+ type GetProperty<Obj, Prop> = Prop extends keyof Obj ? Obj[Prop] : never;
403
+ type GetRawSearchValidator<Path extends string, Verb extends HttpVerb = "GET"> = Path extends keyof AppPaths ? Verb extends keyof AppPaths[Path]["verbs"] ? GetProperty<AppPaths[Path]["verbs"][Verb]["rawOptions"], "search"> : never : never;
404
+ type ParamObject<T> = {
405
+ [K in keyof T]: string | number;
406
+ };
407
+ export type HrefParams<Path extends `${string}/$${string}`> = {
408
+ [Param in PathParamKeys<Path>[number]]: Path extends `${string}/$$${Param}` ? string | number | (string | number)[] : string | number;
409
+ };
410
+ export type HrefOptions<Path extends string = `${string}/$${string}` | `${string}/$$${string}`> = Path extends `${string}/$${string}` ? HrefParamsOptions<Path> : HrefBaseOptions<Path>;
411
+ interface HrefBaseOptions<Path extends string> {
412
+ search?: ParamObject<Valid<GetRawSearchValidator<Path>>>;
413
+ hash?: string | number;
414
+ }
415
+ interface HrefParamsOptions<Path extends `${string}/$${string}`> extends HrefBaseOptions<Path> {
416
+ params: HrefParams<Path>;
417
+ }
418
+ export type Href<Verb extends HttpVerbOrAll = "ALL"> = {
419
+ <Path extends PathsForVerb<Verb>>(path: Path, ...args: Path extends `${string}/$${string}` ? [options: HrefOptions<Path>] : [options?: HrefOptions<Path>]): string;
420
+ };
128
421
  export {};
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/runtime/url-builder.ts
21
+ var url_builder_exports = {};
22
+ __export(url_builder_exports, {
23
+ href: () => href,
24
+ href_keys: () => href_keys,
25
+ href_path: () => href_path,
26
+ href_values: () => href_values,
27
+ parsePathParts: () => parsePathParts
28
+ });
29
+ module.exports = __toCommonJS(url_builder_exports);
30
+
31
+ // scripts/importMetaURL.js
32
+ var import_url = require("url");
33
+ var __importMetaURL = (0, import_url.pathToFileURL)(__filename);
34
+
35
+ // src/runtime/url-builder.ts
36
+ var encode = encodeURIComponent;
37
+ var pathParts = /* @__PURE__ */ new Map();
38
+ function parsePathParts(path) {
39
+ let parts = pathParts.get(path);
40
+ if (!parts) {
41
+ let lastEnd = 0;
42
+ let paramStart;
43
+ pathParts.set(path, parts = [[]]);
44
+ while (lastEnd >= 0 && (paramStart = path.indexOf("/$", lastEnd) + 1)) {
45
+ parts.push(path.slice(lastEnd, paramStart++));
46
+ if (path.charAt(paramStart) === "$") {
47
+ paramStart++;
48
+ lastEnd = -1;
49
+ } else {
50
+ lastEnd = path.indexOf("/", paramStart);
51
+ }
52
+ parts[0].push(path.slice(paramStart, lastEnd < 0 ? void 0 : lastEnd));
53
+ }
54
+ parts.push(lastEnd >= 0 ? path.slice(lastEnd) : "");
55
+ }
56
+ return parts;
57
+ }
58
+ function joinHref(path, options) {
59
+ let result = path;
60
+ if (options.search) {
61
+ const query = "" + new URLSearchParams(options.search);
62
+ if (query) result += "?" + query;
63
+ }
64
+ if (options.hash) result += "#" + encode(options.hash);
65
+ return result;
66
+ }
67
+ function href(path, ...[options]) {
68
+ return options ? "params" in options ? ((parts) => href_keys(parts, options, ...parts[0]))(
69
+ parsePathParts(path)
70
+ ) : joinHref(path, options) : path;
71
+ }
72
+ function href_path(strings, ...params) {
73
+ let i = 0;
74
+ let j = 0;
75
+ let result = strings[i++];
76
+ if (!result || Array.isArray(result)) result = strings[i++];
77
+ while (i < strings.length) {
78
+ const param = params[j++];
79
+ result += (Array.isArray(param) ? param.map(encode).join("/") : encode(param)) + strings[i++];
80
+ }
81
+ return result;
82
+ }
83
+ function href_values(strings, options, ...params) {
84
+ return joinHref(href_path(strings, ...params), options);
85
+ }
86
+ function href_keys(strings, options, ...keys) {
87
+ return href_values(strings, options, ...keys.map((k) => options.params[k]));
88
+ }
89
+ // Annotate the CommonJS export names for ESM import in node:
90
+ 0 && (module.exports = {
91
+ href,
92
+ href_keys,
93
+ href_path,
94
+ href_values,
95
+ parsePathParts
96
+ });
@@ -0,0 +1,6 @@
1
+ import type { HrefOptions, PathsForVerb } from "./types";
2
+ export declare function parsePathParts(path: string): [string[], ...string[]];
3
+ export declare function href<Path extends PathsForVerb>(path: Path, ...[options]: Path extends `${string}/$${string}` ? [options: HrefOptions<Path>] : [options?: HrefOptions<Path>]): string;
4
+ export declare function href_path(strings: TemplateStringsArray, ...params: (string | number | (string | number)[])[]): string;
5
+ export declare function href_values(strings: TemplateStringsArray, options: HrefOptions<any>, ...params: (string | number | (string | number)[])[]): string;
6
+ export declare function href_keys(strings: TemplateStringsArray, options: HrefOptions, ...keys: string[]): string;