effect-start 0.17.0 → 0.17.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Commander.d.ts +103 -0
- package/dist/Commander.js +333 -0
- package/dist/ContentNegotiation.d.ts +13 -0
- package/dist/ContentNegotiation.js +364 -0
- package/dist/Development.d.ts +34 -0
- package/dist/Development.js +52 -0
- package/dist/Entity.d.ts +47 -0
- package/dist/Entity.js +224 -0
- package/dist/FileRouter.d.ts +61 -0
- package/dist/FileRouter.js +203 -0
- package/dist/FileRouterCodegen.d.ts +19 -0
- package/dist/FileRouterCodegen.js +176 -0
- package/dist/FileRouterPattern.d.ts +9 -0
- package/dist/FileRouterPattern.js +35 -0
- package/dist/Http.d.ts +37 -0
- package/dist/Http.js +92 -0
- package/dist/HttpAppExtra.d.ts +7 -0
- package/dist/HttpAppExtra.js +320 -0
- package/dist/HttpUtils.d.ts +3 -0
- package/dist/HttpUtils.js +11 -0
- package/dist/PathPattern.d.ts +134 -0
- package/dist/PathPattern.js +415 -0
- package/dist/Random.d.ts +5 -0
- package/dist/Random.js +49 -0
- package/dist/Route.d.ts +98 -0
- package/dist/Route.js +81 -0
- package/dist/RouteBody.d.ts +53 -0
- package/dist/RouteBody.js +67 -0
- package/dist/RouteHook.d.ts +12 -0
- package/dist/RouteHook.js +45 -0
- package/dist/RouteHttp.d.ts +21 -0
- package/dist/RouteHttp.js +260 -0
- package/dist/RouteHttpTracer.d.ts +10 -0
- package/dist/RouteHttpTracer.js +62 -0
- package/dist/RouteMount.d.ts +119 -0
- package/dist/RouteMount.js +77 -0
- package/dist/RouteSchema.d.ts +65 -0
- package/dist/RouteSchema.js +155 -0
- package/dist/RouteSse.d.ts +21 -0
- package/dist/RouteSse.js +85 -0
- package/dist/RouteTree.d.ts +56 -0
- package/dist/RouteTree.js +91 -0
- package/dist/RouteTrie.d.ts +20 -0
- package/dist/RouteTrie.js +157 -0
- package/dist/RouterPattern.d.ts +118 -0
- package/dist/RouterPattern.js +269 -0
- package/dist/SchemaExtra.d.ts +7 -0
- package/dist/SchemaExtra.js +74 -0
- package/dist/Start.d.ts +19 -0
- package/dist/Start.js +23 -0
- package/dist/StartApp.d.ts +19 -0
- package/dist/StartApp.js +21 -0
- package/dist/StreamExtra.d.ts +28 -0
- package/dist/StreamExtra.js +100 -0
- package/dist/TuplePathPattern.d.ts +9 -0
- package/dist/TuplePathPattern.js +63 -0
- package/dist/Values.d.ts +26 -0
- package/dist/Values.js +30 -0
- package/dist/bun/BunBundle.d.ts +12 -0
- package/dist/bun/BunBundle.js +145 -0
- package/dist/bun/BunHttpServer.d.ts +44 -0
- package/dist/bun/BunHttpServer.js +187 -0
- package/dist/bun/BunHttpServer_web.d.ts +60 -0
- package/dist/bun/BunHttpServer_web.js +252 -0
- package/dist/bun/BunImportTrackerPlugin.d.ts +13 -0
- package/dist/bun/BunImportTrackerPlugin.js +71 -0
- package/dist/bun/BunRoute.d.ts +49 -0
- package/dist/bun/BunRoute.js +131 -0
- package/dist/bun/BunRuntime.d.ts +1 -0
- package/dist/bun/BunRuntime.js +26 -0
- package/dist/bun/BunVirtualFilesPlugin.d.ts +4 -0
- package/dist/bun/BunVirtualFilesPlugin.js +40 -0
- package/dist/bun/_BunEnhancedResolve.d.ts +45 -0
- package/dist/bun/_BunEnhancedResolve.js +104 -0
- package/dist/bun/index.d.ts +4 -0
- package/dist/bun/index.js +4 -0
- package/dist/bundler/Bundle.d.ts +60 -0
- package/dist/bundler/Bundle.js +48 -0
- package/dist/bundler/BundleFiles.d.ts +13 -0
- package/dist/bundler/BundleFiles.js +94 -0
- package/dist/bundler/BundleHttp.d.ts +45 -0
- package/dist/bundler/BundleHttp.js +176 -0
- package/dist/client/Overlay.d.ts +2 -0
- package/dist/client/Overlay.js +32 -0
- package/dist/client/ScrollState.d.ts +6 -0
- package/dist/client/ScrollState.js +98 -0
- package/dist/client/index.d.ts +6 -0
- package/dist/client/index.js +81 -0
- package/dist/experimental/EncryptedCookies.d.ts +51 -0
- package/dist/experimental/EncryptedCookies.js +243 -0
- package/dist/experimental/SseHttpResponse.d.ts +7 -0
- package/dist/experimental/SseHttpResponse.js +28 -0
- package/dist/experimental/index.d.ts +2 -0
- package/dist/experimental/index.js +2 -0
- package/dist/hyper/Hyper.d.ts +32 -0
- package/dist/hyper/Hyper.js +34 -0
- package/dist/hyper/HyperHtml.d.ts +23 -0
- package/dist/hyper/HyperHtml.js +144 -0
- package/dist/hyper/HyperNode.d.ts +14 -0
- package/dist/hyper/HyperNode.js +11 -0
- package/dist/hyper/HyperRoute.d.ts +8 -0
- package/dist/hyper/HyperRoute.js +32 -0
- package/dist/hyper/HyperRoute.test.d.ts +1 -0
- package/dist/hyper/HyperRoute.test.js +72 -0
- package/dist/hyper/index.d.ts +4 -0
- package/dist/hyper/index.js +4 -0
- package/dist/hyper/jsx-runtime.d.ts +7 -0
- package/dist/hyper/jsx-runtime.js +8 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -0
- package/dist/inference_check.d.ts +1 -0
- package/dist/inference_check.js +15 -0
- package/dist/middlewares/BasicAuthMiddleware.d.ts +8 -0
- package/dist/middlewares/BasicAuthMiddleware.js +22 -0
- package/dist/middlewares/index.d.ts +1 -0
- package/dist/middlewares/index.js +1 -0
- package/dist/node/FileSystem.d.ts +9 -0
- package/dist/node/FileSystem.js +440 -0
- package/dist/node/Utils.d.ts +1 -0
- package/dist/node/Utils.js +19 -0
- package/dist/repro_fail.d.ts +1 -0
- package/dist/repro_fail.js +14 -0
- package/dist/testing/TestHttpClient.d.ts +13 -0
- package/dist/testing/TestHttpClient.js +68 -0
- package/dist/testing/TestLogger.d.ts +13 -0
- package/dist/testing/TestLogger.js +29 -0
- package/dist/testing/index.d.ts +3 -0
- package/dist/testing/index.js +3 -0
- package/dist/testing/utils.d.ts +9 -0
- package/dist/testing/utils.js +39 -0
- package/dist/x/cloudflare/CloudflareTunnel.d.ts +13 -0
- package/dist/x/cloudflare/CloudflareTunnel.js +43 -0
- package/dist/x/cloudflare/index.d.ts +1 -0
- package/dist/x/cloudflare/index.js +1 -0
- package/dist/x/datastar/Datastar.d.ts +6 -0
- package/dist/x/datastar/Datastar.js +46 -0
- package/dist/x/datastar/index.d.ts +2 -0
- package/dist/x/datastar/index.js +2 -0
- package/dist/x/tailwind/TailwindPlugin.d.ts +23 -0
- package/dist/x/tailwind/TailwindPlugin.js +219 -0
- package/dist/x/tailwind/compile.d.ts +19 -0
- package/dist/x/tailwind/compile.js +156 -0
- package/dist/x/tailwind/plugin.d.ts +2 -0
- package/dist/x/tailwind/plugin.js +15 -0
- package/package.json +68 -16
- package/src/RouteBody.test.ts +18 -0
- package/src/RouteBody.ts +126 -2
- package/src/x/tailwind/compile.ts +8 -2
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import type * as Stream from "effect/Stream";
|
|
3
|
+
import type * as Utils from "effect/Utils";
|
|
4
|
+
import * as Entity from "./Entity.ts";
|
|
5
|
+
import * as Route from "./Route.ts";
|
|
6
|
+
import type * as Values from "./Values.ts";
|
|
7
|
+
export type Format = "text" | "html" | "json" | "bytes" | "*";
|
|
8
|
+
type UnwrapStream<T> = T extends Stream.Stream<infer V, any, any> ? V : T;
|
|
9
|
+
type YieldError<T> = T extends Utils.YieldWrap<Effect.Effect<any, infer E, any>> ? E : never;
|
|
10
|
+
type YieldContext<T> = T extends Utils.YieldWrap<Effect.Effect<any, any, infer R>> ? R : never;
|
|
11
|
+
export type GeneratorHandler<B, A, Y> = (context: Values.Simplify<B>, next: (context?: Partial<B> & Record<string, unknown>) => Entity.Entity<UnwrapStream<A>>) => Generator<Y, A | Entity.Entity<A>, unknown>;
|
|
12
|
+
export type HandlerInput<B, A, E, R> = A | Entity.Entity<A> | Effect.Effect<A | Entity.Entity<A>, E, R> | ((context: Values.Simplify<B>, next: (context?: Partial<B> & Record<string, unknown>) => Entity.Entity<UnwrapStream<A>>) => Effect.Effect<A | Entity.Entity<A>, E, R> | Generator<Utils.YieldWrap<Effect.Effect<unknown, E, R>>, A | Entity.Entity<A>, unknown>);
|
|
13
|
+
export declare function handle<B, A, Y extends Utils.YieldWrap<Effect.Effect<any, any, any>>>(handler: GeneratorHandler<B, A, Y>): Route.Route.Handler<B, A, YieldError<Y>, YieldContext<Y>>;
|
|
14
|
+
export declare function handle<B, A, E, R>(handler: HandlerInput<B, A, E, R>): Route.Route.Handler<B, A, E, R>;
|
|
15
|
+
export interface BuildReturn<Value, F extends Format> {
|
|
16
|
+
<D extends Route.RouteDescriptor.Any, B, I extends Route.Route.Tuple, A extends F extends "json" ? Value : Value | Stream.Stream<Value, any, any>, Y extends Utils.YieldWrap<Effect.Effect<any, any, any>>>(handler: GeneratorHandler<NoInfer<D & B & Route.ExtractBindings<I> & {
|
|
17
|
+
format: F;
|
|
18
|
+
}>, A, Y>): (self: Route.RouteSet.RouteSet<D, B, I>) => Route.RouteSet.RouteSet<D, B, [
|
|
19
|
+
...I,
|
|
20
|
+
Route.Route.Route<{
|
|
21
|
+
format: F;
|
|
22
|
+
}, {}, A, YieldError<Y>, YieldContext<Y>>
|
|
23
|
+
]>;
|
|
24
|
+
<D extends Route.RouteDescriptor.Any, B, I extends Route.Route.Tuple, A extends F extends "json" ? Value : Value | Stream.Stream<Value, any, any>, E = never, R = never>(handler: HandlerInput<NoInfer<D & B & Route.ExtractBindings<I> & {
|
|
25
|
+
format: F;
|
|
26
|
+
}>, A, E, R>): (self: Route.RouteSet.RouteSet<D, B, I>) => Route.RouteSet.RouteSet<D, B, [
|
|
27
|
+
...I,
|
|
28
|
+
Route.Route.Route<{
|
|
29
|
+
format: F;
|
|
30
|
+
}, {}, A, E, R>
|
|
31
|
+
]>;
|
|
32
|
+
}
|
|
33
|
+
export declare function build<Value, F extends Format>(descriptors: {
|
|
34
|
+
format: F;
|
|
35
|
+
}): BuildReturn<Value, F>;
|
|
36
|
+
export type RenderValue = string | Uint8Array | Stream.Stream<string | Uint8Array, any, any>;
|
|
37
|
+
export declare function render<D extends Route.RouteDescriptor.Any, B extends {}, I extends Route.Route.Tuple, A extends RenderValue, Y extends Utils.YieldWrap<Effect.Effect<any, any, any>>>(handler: GeneratorHandler<NoInfer<D & B & Route.ExtractBindings<I> & {
|
|
38
|
+
format: "*";
|
|
39
|
+
}>, A, Y>): (self: Route.RouteSet.RouteSet<D, B, I>) => Route.RouteSet.RouteSet<D, B, [
|
|
40
|
+
...I,
|
|
41
|
+
Route.Route.Route<{
|
|
42
|
+
format: "*";
|
|
43
|
+
}, {}, A, YieldError<Y>, YieldContext<Y>>
|
|
44
|
+
]>;
|
|
45
|
+
export declare function render<D extends Route.RouteDescriptor.Any, B extends {}, I extends Route.Route.Tuple, A extends RenderValue, E = never, R = never>(handler: HandlerInput<NoInfer<D & B & Route.ExtractBindings<I> & {
|
|
46
|
+
format: "*";
|
|
47
|
+
}>, A, E, R>): (self: Route.RouteSet.RouteSet<D, B, I>) => Route.RouteSet.RouteSet<D, B, [
|
|
48
|
+
...I,
|
|
49
|
+
Route.Route.Route<{
|
|
50
|
+
format: "*";
|
|
51
|
+
}, {}, A, E, R>
|
|
52
|
+
]>;
|
|
53
|
+
export {};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as Entity from "./Entity.js";
|
|
3
|
+
import * as Route from "./Route.js";
|
|
4
|
+
const formatToContentType = {
|
|
5
|
+
text: "text/plain; charset=utf-8",
|
|
6
|
+
html: "text/html; charset=utf-8",
|
|
7
|
+
json: "application/json",
|
|
8
|
+
bytes: "application/octet-stream",
|
|
9
|
+
"*": undefined,
|
|
10
|
+
};
|
|
11
|
+
export function handle(handler) {
|
|
12
|
+
if (typeof handler === "function") {
|
|
13
|
+
return (context, next) => {
|
|
14
|
+
const result = handler(context, next);
|
|
15
|
+
const effect = Effect.isEffect(result)
|
|
16
|
+
? result
|
|
17
|
+
: Effect.gen(function* () {
|
|
18
|
+
return yield* result;
|
|
19
|
+
});
|
|
20
|
+
return Effect.map(effect, normalizeToEntity);
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
if (Effect.isEffect(handler)) {
|
|
24
|
+
return (_context, _next) => Effect.map(handler, normalizeToEntity);
|
|
25
|
+
}
|
|
26
|
+
if (Entity.isEntity(handler)) {
|
|
27
|
+
return (_context, _next) => Effect.succeed(handler);
|
|
28
|
+
}
|
|
29
|
+
return (_context, _next) => Effect.succeed(normalizeToEntity(handler));
|
|
30
|
+
}
|
|
31
|
+
function normalizeToEntity(value) {
|
|
32
|
+
if (Entity.isEntity(value)) {
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
return Entity.make(value, { status: 200 });
|
|
36
|
+
}
|
|
37
|
+
export function build(descriptors) {
|
|
38
|
+
return (function (handler) {
|
|
39
|
+
return function (self) {
|
|
40
|
+
const contentType = formatToContentType[descriptors.format];
|
|
41
|
+
const baseHandler = handle(handler);
|
|
42
|
+
const wrappedHandler = (ctx, next) => Effect.map(baseHandler(ctx, next), (entity) => entity.headers["content-type"]
|
|
43
|
+
? entity
|
|
44
|
+
: Entity.make(entity.body, {
|
|
45
|
+
status: entity.status,
|
|
46
|
+
url: entity.url,
|
|
47
|
+
headers: { ...entity.headers, "content-type": contentType },
|
|
48
|
+
}));
|
|
49
|
+
const route = Route.make(wrappedHandler, descriptors);
|
|
50
|
+
const items = [
|
|
51
|
+
...Route.items(self),
|
|
52
|
+
route,
|
|
53
|
+
];
|
|
54
|
+
return Route.set(items, Route.descriptor(self));
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
export function render(handler) {
|
|
59
|
+
return function (self) {
|
|
60
|
+
const route = Route.make(handle(handler), { format: "*" });
|
|
61
|
+
const items = [
|
|
62
|
+
...Route.items(self),
|
|
63
|
+
route,
|
|
64
|
+
];
|
|
65
|
+
return Route.set(items, Route.descriptor(self));
|
|
66
|
+
};
|
|
67
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import type * as Utils from "effect/Utils";
|
|
3
|
+
import * as Route from "./Route.ts";
|
|
4
|
+
export type FilterResult<BOut, E, R> = {
|
|
5
|
+
context: BOut;
|
|
6
|
+
} | Effect.Effect<{
|
|
7
|
+
context: BOut;
|
|
8
|
+
}, E, R>;
|
|
9
|
+
export type FilterHandlerInput<BIn, BOut, E, R> = FilterResult<BOut, E, R> | ((context: BIn) => FilterResult<BOut, E, R> | Generator<Utils.YieldWrap<Effect.Effect<unknown, E, R>>, {
|
|
10
|
+
context: BOut;
|
|
11
|
+
}, unknown>);
|
|
12
|
+
export declare function filter<D extends Route.RouteDescriptor.Any, SB extends {}, P extends Route.Route.Tuple, BOut extends {}, E = never, R = never, BIn = D & SB & Route.ExtractBindings<P>>(filterHandler: FilterHandlerInput<BIn, BOut, E, R>): (self: Route.RouteSet.RouteSet<D, SB, P>) => Route.RouteSet.RouteSet<D, SB, [...P, Route.Route.Route<{}, BOut, unknown, E, R>]>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as Entity from "./Entity.js";
|
|
3
|
+
import * as Route from "./Route.js";
|
|
4
|
+
export function filter(filterHandler) {
|
|
5
|
+
const normalized = normalizeFilterHandler(filterHandler);
|
|
6
|
+
return function (self) {
|
|
7
|
+
const route = Route.make((context, next) => Effect.gen(function* () {
|
|
8
|
+
const filterResult = yield* normalized(context);
|
|
9
|
+
const mergedContext = filterResult
|
|
10
|
+
? { ...context, ...filterResult.context }
|
|
11
|
+
: context;
|
|
12
|
+
return yield* Entity.resolve(next(mergedContext));
|
|
13
|
+
}));
|
|
14
|
+
return Route.set([
|
|
15
|
+
...Route.items(self),
|
|
16
|
+
route,
|
|
17
|
+
], Route.descriptor(self));
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function isGenerator(value) {
|
|
21
|
+
return (typeof value === "object"
|
|
22
|
+
&& value !== null
|
|
23
|
+
&& Symbol.iterator in value
|
|
24
|
+
&& typeof value.next === "function");
|
|
25
|
+
}
|
|
26
|
+
function normalizeFilterHandler(handler) {
|
|
27
|
+
if (typeof handler === "function") {
|
|
28
|
+
return (context) => {
|
|
29
|
+
const result = handler(context);
|
|
30
|
+
if (Effect.isEffect(result)) {
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
if (isGenerator(result)) {
|
|
34
|
+
return Effect.gen(function* () {
|
|
35
|
+
return yield* result;
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return Effect.succeed(result);
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
if (Effect.isEffect(handler)) {
|
|
42
|
+
return (_context) => handler;
|
|
43
|
+
}
|
|
44
|
+
return (_context) => Effect.succeed(handler);
|
|
45
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as FiberId from "effect/FiberId";
|
|
2
|
+
import * as Runtime from "effect/Runtime";
|
|
3
|
+
import * as Http from "./Http.ts";
|
|
4
|
+
import * as Route from "./Route.ts";
|
|
5
|
+
import * as RouteBody from "./RouteBody.ts";
|
|
6
|
+
import * as RouteMount from "./RouteMount.ts";
|
|
7
|
+
import * as RouteTree from "./RouteTree.ts";
|
|
8
|
+
export { currentSpanNameGenerator, currentTracerDisabledWhen, parentSpanFromHeaders, withSpanNameGenerator, withTracerDisabledWhen, } from "./RouteHttpTracer.ts";
|
|
9
|
+
type UnboundedRouteWithMethod = Route.Route.With<{
|
|
10
|
+
method: RouteMount.RouteMount.Method;
|
|
11
|
+
format?: RouteBody.Format;
|
|
12
|
+
}>;
|
|
13
|
+
/**
|
|
14
|
+
* A synthetic fiber used to tag interruptions caused by client disconnects.
|
|
15
|
+
* Number stands for HTTP status 499 "Client Closed Request".
|
|
16
|
+
* This is what @effect/platform does to signal request cancelation.
|
|
17
|
+
*/
|
|
18
|
+
export declare const clientAbortFiberId: FiberId.Runtime;
|
|
19
|
+
export declare const toWebHandlerRuntime: <R>(runtime: Runtime.Runtime<R>) => (routes: Iterable<UnboundedRouteWithMethod>) => Http.WebHandler;
|
|
20
|
+
export declare const toWebHandler: (routes: Iterable<UnboundedRouteWithMethod>) => Http.WebHandler;
|
|
21
|
+
export declare function walkHandles(tree: RouteTree.RouteTree, runtime?: Runtime.Runtime<never>): Generator<[path: string, handler: Http.WebHandler]>;
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import * as Cause from "effect/Cause";
|
|
2
|
+
import * as Effect from "effect/Effect";
|
|
3
|
+
import * as FiberId from "effect/FiberId";
|
|
4
|
+
import * as FiberRef from "effect/FiberRef";
|
|
5
|
+
import * as HashSet from "effect/HashSet";
|
|
6
|
+
import * as Option from "effect/Option";
|
|
7
|
+
import * as Runtime from "effect/Runtime";
|
|
8
|
+
import * as Stream from "effect/Stream";
|
|
9
|
+
import * as ContentNegotiation from "./ContentNegotiation.js";
|
|
10
|
+
import * as Entity from "./Entity.js";
|
|
11
|
+
import * as Route from "./Route.js";
|
|
12
|
+
import * as RouteHttpTracer from "./RouteHttpTracer.js";
|
|
13
|
+
import * as RouteTree from "./RouteTree.js";
|
|
14
|
+
import * as StreamExtra from "./StreamExtra.js";
|
|
15
|
+
export { currentSpanNameGenerator, currentTracerDisabledWhen, parentSpanFromHeaders, withSpanNameGenerator, withTracerDisabledWhen, } from "./RouteHttpTracer.js";
|
|
16
|
+
// Used to match Accept headers against available route formats.
|
|
17
|
+
// text/* matches any text type (text/plain, text/event-stream, text/markdown, etc.)
|
|
18
|
+
const formatToMediaType = {
|
|
19
|
+
text: "text/*",
|
|
20
|
+
html: "text/html",
|
|
21
|
+
json: "application/json",
|
|
22
|
+
bytes: "application/octet-stream",
|
|
23
|
+
};
|
|
24
|
+
// Used after content negotiation to determine which format was selected.
|
|
25
|
+
const mediaTypeToFormat = {
|
|
26
|
+
"text/*": "text",
|
|
27
|
+
"text/html": "html",
|
|
28
|
+
"application/json": "json",
|
|
29
|
+
"application/octet-stream": "bytes",
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* A synthetic fiber used to tag interruptions caused by client disconnects.
|
|
33
|
+
* Number stands for HTTP status 499 "Client Closed Request".
|
|
34
|
+
* This is what @effect/platform does to signal request cancelation.
|
|
35
|
+
*/
|
|
36
|
+
export const clientAbortFiberId = FiberId.runtime(-499, 0);
|
|
37
|
+
const isClientAbort = (cause) => Cause.isInterruptedOnly(cause)
|
|
38
|
+
&& HashSet.some(Cause.interruptors(cause), (id) => id === clientAbortFiberId);
|
|
39
|
+
const getStatusFromCause = (cause) => {
|
|
40
|
+
const failure = Cause.failureOption(cause);
|
|
41
|
+
if (failure._tag === "Some") {
|
|
42
|
+
const error = failure.value;
|
|
43
|
+
if (error._tag === "ParseError" || error._tag === "RequestBodyError") {
|
|
44
|
+
return 400;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return 500;
|
|
48
|
+
};
|
|
49
|
+
function streamResponse(stream, headers, status, runtime) {
|
|
50
|
+
const encoder = new TextEncoder();
|
|
51
|
+
const byteStream = stream.pipe(Stream.map((chunk) => typeof chunk === "string"
|
|
52
|
+
? encoder.encode(chunk)
|
|
53
|
+
: chunk), Stream.catchAll((error) => Stream.fail(error instanceof Error ? error : new Error(String(error)))));
|
|
54
|
+
return new Response(Stream.toReadableStreamRuntime(byteStream, runtime), { status, headers: headers });
|
|
55
|
+
}
|
|
56
|
+
function toResponse(entity, format, runtime) {
|
|
57
|
+
const contentType = Entity.type(entity);
|
|
58
|
+
const status = entity.status ?? 200;
|
|
59
|
+
const headers = { ...entity.headers, "content-type": contentType };
|
|
60
|
+
if (StreamExtra.isStream(entity.body)) {
|
|
61
|
+
return Effect.succeed(streamResponse(entity.body, headers, status, runtime));
|
|
62
|
+
}
|
|
63
|
+
if (format === "json") {
|
|
64
|
+
return Effect.map(entity.json, (data) => new Response(JSON.stringify(data), { status, headers }));
|
|
65
|
+
}
|
|
66
|
+
if (format === "text" || format === "html") {
|
|
67
|
+
return Effect.map(entity.text, (text) => new Response(text, { status, headers }));
|
|
68
|
+
}
|
|
69
|
+
if (format === "bytes") {
|
|
70
|
+
return Effect.map(entity.bytes, (bytes) => new Response(bytes, { status, headers }));
|
|
71
|
+
}
|
|
72
|
+
return Effect.succeed(streamResponse(entity.stream, headers, status, runtime));
|
|
73
|
+
}
|
|
74
|
+
function determineSelectedFormat(accept, routes) {
|
|
75
|
+
const formats = routes
|
|
76
|
+
.filter((r) => Route.descriptor(r).method !== "*")
|
|
77
|
+
.map((r) => Route.descriptor(r).format)
|
|
78
|
+
.filter((f) => Boolean(f) && f !== "*");
|
|
79
|
+
const uniqueFormats = [...new Set(formats)];
|
|
80
|
+
const mediaTypes = uniqueFormats
|
|
81
|
+
.map((f) => formatToMediaType[f])
|
|
82
|
+
.filter(Boolean);
|
|
83
|
+
if (mediaTypes.length === 0) {
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
if (!accept) {
|
|
87
|
+
return uniqueFormats[0];
|
|
88
|
+
}
|
|
89
|
+
const negotiated = ContentNegotiation.media(accept, mediaTypes);
|
|
90
|
+
if (negotiated.length > 0) {
|
|
91
|
+
return mediaTypeToFormat[negotiated[0]];
|
|
92
|
+
}
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
export const toWebHandlerRuntime = (runtime) => {
|
|
96
|
+
const runFork = Runtime.runFork(runtime);
|
|
97
|
+
return (routes) => {
|
|
98
|
+
const grouped = Object.groupBy(routes, (route) => Route.descriptor(route).method?.toUpperCase() ?? "*");
|
|
99
|
+
const wildcards = grouped["*"] ?? [];
|
|
100
|
+
const methodGroups = {
|
|
101
|
+
GET: undefined,
|
|
102
|
+
POST: undefined,
|
|
103
|
+
PUT: undefined,
|
|
104
|
+
PATCH: undefined,
|
|
105
|
+
DELETE: undefined,
|
|
106
|
+
HEAD: undefined,
|
|
107
|
+
OPTIONS: undefined,
|
|
108
|
+
};
|
|
109
|
+
for (const method in grouped) {
|
|
110
|
+
if (method !== "*") {
|
|
111
|
+
methodGroups[method] = grouped[method];
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return (request) => {
|
|
115
|
+
const method = request.method.toUpperCase();
|
|
116
|
+
const accept = request.headers.get("accept");
|
|
117
|
+
const methodRoutes = methodGroups[method] ?? [];
|
|
118
|
+
if (methodRoutes.length === 0 && wildcards.length === 0) {
|
|
119
|
+
return Promise.resolve(Response.json({ status: 405, message: "method not allowed" }, {
|
|
120
|
+
status: 405,
|
|
121
|
+
}));
|
|
122
|
+
}
|
|
123
|
+
const allRoutes = [...wildcards, ...methodRoutes];
|
|
124
|
+
const selectedFormat = determineSelectedFormat(accept, allRoutes);
|
|
125
|
+
const hasSpecificFormatRoutes = allRoutes.some((r) => {
|
|
126
|
+
const format = Route.descriptor(r).format;
|
|
127
|
+
return format && format !== "*";
|
|
128
|
+
});
|
|
129
|
+
const hasWildcardFormatRoutes = allRoutes.some((r) => Route.descriptor(r).format === "*");
|
|
130
|
+
if (selectedFormat === undefined
|
|
131
|
+
&& hasSpecificFormatRoutes
|
|
132
|
+
&& !hasWildcardFormatRoutes) {
|
|
133
|
+
return Promise.resolve(Response.json({ status: 406, message: "not acceptable" }, {
|
|
134
|
+
status: 406,
|
|
135
|
+
}));
|
|
136
|
+
}
|
|
137
|
+
const createChain = (initialContext) => {
|
|
138
|
+
let index = 0;
|
|
139
|
+
let currentContext = initialContext;
|
|
140
|
+
let routePathSet = false;
|
|
141
|
+
const runNext = (passedContext) => {
|
|
142
|
+
if (passedContext !== undefined) {
|
|
143
|
+
currentContext = passedContext;
|
|
144
|
+
}
|
|
145
|
+
if (index >= allRoutes.length) {
|
|
146
|
+
return Effect.succeed(Entity.make({ status: 404, message: "route not found" }, { status: 404 }));
|
|
147
|
+
}
|
|
148
|
+
const route = allRoutes[index++];
|
|
149
|
+
const descriptor = Route.descriptor(route);
|
|
150
|
+
const format = descriptor.format;
|
|
151
|
+
const handler = route.handler;
|
|
152
|
+
if (format && format !== "*" && format !== selectedFormat) {
|
|
153
|
+
return runNext();
|
|
154
|
+
}
|
|
155
|
+
currentContext = { ...currentContext, ...descriptor };
|
|
156
|
+
const nextArg = (ctx) => Entity.effect(Effect.suspend(() => runNext(ctx)));
|
|
157
|
+
const routePath = descriptor["path"];
|
|
158
|
+
if (!routePathSet && routePath !== undefined) {
|
|
159
|
+
routePathSet = true;
|
|
160
|
+
return Effect.flatMap(Effect.currentSpan.pipe(Effect.option), (spanOption) => {
|
|
161
|
+
if (Option.isSome(spanOption)) {
|
|
162
|
+
spanOption.value.attribute("http.route", routePath);
|
|
163
|
+
}
|
|
164
|
+
return handler(currentContext, nextArg);
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
return handler(currentContext, nextArg);
|
|
168
|
+
};
|
|
169
|
+
return runNext();
|
|
170
|
+
};
|
|
171
|
+
const effect = Effect.withFiberRuntime((fiber) => {
|
|
172
|
+
const tracerDisabled = !fiber.getFiberRef(FiberRef.currentTracerEnabled)
|
|
173
|
+
|| fiber.getFiberRef(RouteHttpTracer.currentTracerDisabledWhen)(request);
|
|
174
|
+
const url = new URL(request.url);
|
|
175
|
+
const innerEffect = Effect.gen(function* () {
|
|
176
|
+
const result = yield* createChain({ request, selectedFormat });
|
|
177
|
+
const entity = Entity.isEntity(result)
|
|
178
|
+
? result
|
|
179
|
+
: Entity.make(result, { status: 200 });
|
|
180
|
+
if (entity.status === 404 && entity.body === undefined) {
|
|
181
|
+
return Response.json({ status: 406, message: "not acceptable" }, {
|
|
182
|
+
status: 406,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
return yield* toResponse(entity, selectedFormat, runtime);
|
|
186
|
+
});
|
|
187
|
+
if (tracerDisabled) {
|
|
188
|
+
return innerEffect;
|
|
189
|
+
}
|
|
190
|
+
const spanNameGenerator = fiber.getFiberRef(RouteHttpTracer.currentSpanNameGenerator);
|
|
191
|
+
return Effect.useSpan(spanNameGenerator(request), {
|
|
192
|
+
parent: Option.getOrUndefined(RouteHttpTracer.parentSpanFromHeaders(request.headers)),
|
|
193
|
+
kind: "server",
|
|
194
|
+
captureStackTrace: false,
|
|
195
|
+
}, (span) => {
|
|
196
|
+
span.attribute("http.request.method", request.method);
|
|
197
|
+
span.attribute("url.full", url.toString());
|
|
198
|
+
span.attribute("url.path", url.pathname);
|
|
199
|
+
const query = url.search.slice(1);
|
|
200
|
+
if (query !== "") {
|
|
201
|
+
span.attribute("url.query", query);
|
|
202
|
+
}
|
|
203
|
+
span.attribute("url.scheme", url.protocol.slice(0, -1));
|
|
204
|
+
const userAgent = request.headers.get("user-agent");
|
|
205
|
+
if (userAgent !== null) {
|
|
206
|
+
span.attribute("user_agent.original", userAgent);
|
|
207
|
+
}
|
|
208
|
+
return Effect.flatMap(Effect.exit(Effect.withParentSpan(innerEffect, span)), (exit) => {
|
|
209
|
+
if (exit._tag === "Success") {
|
|
210
|
+
span.attribute("http.response.status_code", exit.value.status);
|
|
211
|
+
}
|
|
212
|
+
return exit;
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
return new Promise((resolve) => {
|
|
217
|
+
const fiber = runFork(effect.pipe(Effect.scoped, Effect.catchAllCause((cause) => Effect.gen(function* () {
|
|
218
|
+
yield* Effect.logError(cause);
|
|
219
|
+
const status = getStatusFromCause(cause);
|
|
220
|
+
return Response.json({ status, message: Cause.pretty(cause) }, {
|
|
221
|
+
status,
|
|
222
|
+
});
|
|
223
|
+
}))));
|
|
224
|
+
request.signal?.addEventListener("abort", () => {
|
|
225
|
+
fiber.unsafeInterruptAsFork(clientAbortFiberId);
|
|
226
|
+
}, { once: true });
|
|
227
|
+
fiber.addObserver((exit) => {
|
|
228
|
+
if (exit._tag === "Success") {
|
|
229
|
+
resolve(exit.value);
|
|
230
|
+
}
|
|
231
|
+
else if (isClientAbort(exit.cause)) {
|
|
232
|
+
resolve(Response.json({ status: 499, message: "client closed request" }, {
|
|
233
|
+
status: 499,
|
|
234
|
+
}));
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
const status = getStatusFromCause(exit.cause);
|
|
238
|
+
resolve(Response.json({ status, message: Cause.pretty(exit.cause) }, {
|
|
239
|
+
status,
|
|
240
|
+
}));
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
};
|
|
245
|
+
};
|
|
246
|
+
};
|
|
247
|
+
export const toWebHandler = toWebHandlerRuntime(Runtime.defaultRuntime);
|
|
248
|
+
export function* walkHandles(tree, runtime = Runtime.defaultRuntime) {
|
|
249
|
+
const pathGroups = new Map();
|
|
250
|
+
for (const route of RouteTree.walk(tree)) {
|
|
251
|
+
const path = Route.descriptor(route).path;
|
|
252
|
+
const group = pathGroups.get(path) ?? [];
|
|
253
|
+
group.push(route);
|
|
254
|
+
pathGroups.set(path, group);
|
|
255
|
+
}
|
|
256
|
+
const toHandler = toWebHandlerRuntime(runtime);
|
|
257
|
+
for (const [path, routes] of pathGroups) {
|
|
258
|
+
yield [path, toHandler(routes)];
|
|
259
|
+
}
|
|
260
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as FiberRef from "effect/FiberRef";
|
|
3
|
+
import * as Option from "effect/Option";
|
|
4
|
+
import type * as Predicate from "effect/Predicate";
|
|
5
|
+
import * as Tracer from "effect/Tracer";
|
|
6
|
+
export declare const currentTracerDisabledWhen: FiberRef.FiberRef<Predicate.Predicate<Request>>;
|
|
7
|
+
export declare const withTracerDisabledWhen: <A, E, R>(effect: Effect.Effect<A, E, R>, predicate: Predicate.Predicate<Request>) => Effect.Effect<A, E, R>;
|
|
8
|
+
export declare const currentSpanNameGenerator: FiberRef.FiberRef<(request: Request) => string>;
|
|
9
|
+
export declare const withSpanNameGenerator: <A, E, R>(effect: Effect.Effect<A, E, R>, f: (request: Request) => string) => Effect.Effect<A, E, R>;
|
|
10
|
+
export declare const parentSpanFromHeaders: (headers: Headers) => Option.Option<Tracer.ExternalSpan>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as FiberRef from "effect/FiberRef";
|
|
3
|
+
import * as GlobalValue from "effect/GlobalValue";
|
|
4
|
+
import * as Option from "effect/Option";
|
|
5
|
+
import * as Tracer from "effect/Tracer";
|
|
6
|
+
export const currentTracerDisabledWhen = GlobalValue.globalValue(Symbol.for("effect-start/RouteHttp/tracerDisabledWhen"), () => FiberRef.unsafeMake(() => false));
|
|
7
|
+
export const withTracerDisabledWhen = (effect, predicate) => Effect.locally(effect, currentTracerDisabledWhen, predicate);
|
|
8
|
+
export const currentSpanNameGenerator = GlobalValue.globalValue(Symbol.for("effect-start/RouteHttp/spanNameGenerator"), () => FiberRef.unsafeMake((request) => `http.server ${request.method}`));
|
|
9
|
+
export const withSpanNameGenerator = (effect, f) => Effect.locally(effect, currentSpanNameGenerator, f);
|
|
10
|
+
const w3cTraceparent = (headers) => {
|
|
11
|
+
const header = headers.get("traceparent");
|
|
12
|
+
if (header === null)
|
|
13
|
+
return Option.none();
|
|
14
|
+
const parts = header.split("-");
|
|
15
|
+
if (parts.length < 4)
|
|
16
|
+
return Option.none();
|
|
17
|
+
const [_version, traceId, spanId, flags] = parts;
|
|
18
|
+
if (!traceId || !spanId)
|
|
19
|
+
return Option.none();
|
|
20
|
+
return Option.some(Tracer.externalSpan({
|
|
21
|
+
spanId,
|
|
22
|
+
traceId,
|
|
23
|
+
sampled: flags === "01",
|
|
24
|
+
}));
|
|
25
|
+
};
|
|
26
|
+
const b3Single = (headers) => {
|
|
27
|
+
const header = headers.get("b3");
|
|
28
|
+
if (header === null)
|
|
29
|
+
return Option.none();
|
|
30
|
+
const parts = header.split("-");
|
|
31
|
+
if (parts.length < 2)
|
|
32
|
+
return Option.none();
|
|
33
|
+
const [traceId, spanId, sampledStr] = parts;
|
|
34
|
+
if (!traceId || !spanId)
|
|
35
|
+
return Option.none();
|
|
36
|
+
return Option.some(Tracer.externalSpan({
|
|
37
|
+
spanId,
|
|
38
|
+
traceId,
|
|
39
|
+
sampled: sampledStr === "1",
|
|
40
|
+
}));
|
|
41
|
+
};
|
|
42
|
+
const xb3 = (headers) => {
|
|
43
|
+
const traceId = headers.get("x-b3-traceid");
|
|
44
|
+
const spanId = headers.get("x-b3-spanid");
|
|
45
|
+
if (traceId === null || spanId === null)
|
|
46
|
+
return Option.none();
|
|
47
|
+
const sampled = headers.get("x-b3-sampled");
|
|
48
|
+
return Option.some(Tracer.externalSpan({
|
|
49
|
+
spanId,
|
|
50
|
+
traceId,
|
|
51
|
+
sampled: sampled === "1",
|
|
52
|
+
}));
|
|
53
|
+
};
|
|
54
|
+
export const parentSpanFromHeaders = (headers) => {
|
|
55
|
+
let span = w3cTraceparent(headers);
|
|
56
|
+
if (span._tag === "Some")
|
|
57
|
+
return span;
|
|
58
|
+
span = b3Single(headers);
|
|
59
|
+
if (span._tag === "Some")
|
|
60
|
+
return span;
|
|
61
|
+
return xb3(headers);
|
|
62
|
+
};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import * as Types from "effect/Types";
|
|
2
|
+
import * as Http from "./Http.ts";
|
|
3
|
+
import * as PathPattern from "./PathPattern.ts";
|
|
4
|
+
import * as Route from "./Route.ts";
|
|
5
|
+
type Module = typeof import("./RouteMount.ts");
|
|
6
|
+
export type Self = RouteMount.Builder | Module;
|
|
7
|
+
export declare const use: RouteMount.Describer<"*">;
|
|
8
|
+
export declare const get: RouteMount.Describer<"GET">;
|
|
9
|
+
export declare const post: RouteMount.Describer<"POST">;
|
|
10
|
+
export declare const put: RouteMount.Describer<"PUT">;
|
|
11
|
+
export declare const del: RouteMount.Describer<"DELETE">;
|
|
12
|
+
export declare const patch: RouteMount.Describer<"PATCH">;
|
|
13
|
+
export declare const head: RouteMount.Describer<"HEAD">;
|
|
14
|
+
export declare const options: RouteMount.Describer<"OPTIONS">;
|
|
15
|
+
export declare const add: RouteMount.Add;
|
|
16
|
+
export type MountedRoute = Route.Route.Route<{
|
|
17
|
+
method: RouteMount.Method;
|
|
18
|
+
path: PathPattern.PathPattern;
|
|
19
|
+
format?: string;
|
|
20
|
+
}, {}, any, any, any>;
|
|
21
|
+
export declare namespace RouteMount {
|
|
22
|
+
export type Method = "*" | Http.Method;
|
|
23
|
+
export type MountSet = Route.RouteSet.RouteSet<{
|
|
24
|
+
method: Method;
|
|
25
|
+
}, {}, Route.Route.Tuple>;
|
|
26
|
+
export interface Builder<D extends {} = {}, I extends Route.Route.Tuple = []> extends Route.RouteSet.RouteSet<D, {}, I>, Module {
|
|
27
|
+
}
|
|
28
|
+
export type EmptySet<M extends Method, B = {}> = Route.RouteSet.RouteSet<{
|
|
29
|
+
method: M;
|
|
30
|
+
}, B, [
|
|
31
|
+
]>;
|
|
32
|
+
export type Items<S> = S extends Builder<any, infer I> ? I : [];
|
|
33
|
+
export type BuilderBindings<S> = S extends Builder<any, infer I> ? Types.Simplify<WildcardBindings<I>> & {
|
|
34
|
+
request: Request;
|
|
35
|
+
} : {
|
|
36
|
+
request: Request;
|
|
37
|
+
};
|
|
38
|
+
type WildcardBindingsItem<T> = T extends Route.Route.Route<{
|
|
39
|
+
method: "*";
|
|
40
|
+
}, infer B, any, any, any> ? B : {};
|
|
41
|
+
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
|
|
42
|
+
export type WildcardBindings<I extends Route.Route.Tuple> = UnionToIntersection<{
|
|
43
|
+
[K in keyof I]: WildcardBindingsItem<I[K]>;
|
|
44
|
+
}[number]>;
|
|
45
|
+
type PrefixPathItem<Prefix extends string, T> = T extends Route.Route.Route<infer D, infer B, infer A, infer E, infer R> ? D extends {
|
|
46
|
+
path: infer P extends string;
|
|
47
|
+
} ? Route.Route.Route<Omit<D, "path"> & {
|
|
48
|
+
path: `${Prefix}${P}`;
|
|
49
|
+
}, B, A, E, R> : Route.Route.Route<D & {
|
|
50
|
+
path: Prefix;
|
|
51
|
+
}, B, A, E, R> : T;
|
|
52
|
+
export type PrefixPath<Prefix extends string, I extends Route.Route.Tuple> = {
|
|
53
|
+
[K in keyof I]: PrefixPathItem<Prefix, I[K]>;
|
|
54
|
+
} extends infer R extends Route.Route.Tuple ? R : never;
|
|
55
|
+
export interface Add {
|
|
56
|
+
<S extends Self, P extends string, R extends Route.RouteSet.Any>(this: S, path: P, routes: R): Builder<{}, [
|
|
57
|
+
...Items<S>,
|
|
58
|
+
...PrefixPath<P, Route.RouteSet.Items<R>>
|
|
59
|
+
]>;
|
|
60
|
+
<S extends Self, P extends string, R extends Route.RouteSet.Any>(this: S, path: P,
|
|
61
|
+
/**
|
|
62
|
+
* Callback form provides a builder seeded with higher-level bindings so
|
|
63
|
+
* nested routes can type-infer outer context when mounting.
|
|
64
|
+
*/
|
|
65
|
+
routes: (self: Builder<{}, []>) => R): Builder<{}, [
|
|
66
|
+
...Items<S>,
|
|
67
|
+
...PrefixPath<P, Route.RouteSet.Items<R>>
|
|
68
|
+
]>;
|
|
69
|
+
}
|
|
70
|
+
export type FlattenItems<M extends Method, B, I extends Route.Route.Tuple> = I extends [
|
|
71
|
+
Route.Route.Route<infer D, infer RB, infer A, infer E, infer R>,
|
|
72
|
+
...infer Tail extends Route.Route.Tuple
|
|
73
|
+
] ? [
|
|
74
|
+
Route.Route.Route<Types.Simplify<{
|
|
75
|
+
method: M;
|
|
76
|
+
} & D> & {}, Types.Simplify<Omit<B & RB, "request">>, A, E, R>,
|
|
77
|
+
...FlattenItems<M, Types.Simplify<B & RB>, Tail>
|
|
78
|
+
] : [];
|
|
79
|
+
export interface Describer<M extends Method> {
|
|
80
|
+
<S extends Self, A extends Route.RouteSet.Any>(this: S, ab: (a: EmptySet<M, BuilderBindings<S>>) => A): Builder<{}, [
|
|
81
|
+
...Items<S>,
|
|
82
|
+
...FlattenItems<M, BuilderBindings<S>, Route.RouteSet.Items<A>>
|
|
83
|
+
]>;
|
|
84
|
+
<S extends Self, A extends Route.RouteSet.Any, B extends Route.RouteSet.Any>(this: S, ab: (a: EmptySet<M, BuilderBindings<S>>) => A, bc: (b: A) => B): Builder<{}, [
|
|
85
|
+
...Items<S>,
|
|
86
|
+
...FlattenItems<M, BuilderBindings<S>, Route.RouteSet.Items<B>>
|
|
87
|
+
]>;
|
|
88
|
+
<S extends Self, A extends Route.RouteSet.Any, B extends Route.RouteSet.Any, C extends Route.RouteSet.Any>(this: S, ab: (a: EmptySet<M, BuilderBindings<S>>) => A, bc: (b: A) => B, cd: (c: B) => C): Builder<{}, [
|
|
89
|
+
...Items<S>,
|
|
90
|
+
...FlattenItems<M, BuilderBindings<S>, Route.RouteSet.Items<C>>
|
|
91
|
+
]>;
|
|
92
|
+
<S extends Self, A extends Route.RouteSet.Any, B extends Route.RouteSet.Any, C extends Route.RouteSet.Any, D extends Route.RouteSet.Any>(this: S, ab: (a: EmptySet<M, BuilderBindings<S>>) => A, bc: (b: A) => B, cd: (c: B) => C, de: (d: C) => D): Builder<{}, [
|
|
93
|
+
...Items<S>,
|
|
94
|
+
...FlattenItems<M, BuilderBindings<S>, Route.RouteSet.Items<D>>
|
|
95
|
+
]>;
|
|
96
|
+
<S extends Self, A extends Route.RouteSet.Any, B extends Route.RouteSet.Any, C extends Route.RouteSet.Any, D extends Route.RouteSet.Any, E extends Route.RouteSet.Any>(this: S, ab: (a: EmptySet<M, BuilderBindings<S>>) => A, bc: (b: A) => B, cd: (c: B) => C, de: (d: C) => D, ef: (e: D) => E): Builder<{}, [
|
|
97
|
+
...Items<S>,
|
|
98
|
+
...FlattenItems<M, BuilderBindings<S>, Route.RouteSet.Items<E>>
|
|
99
|
+
]>;
|
|
100
|
+
<S extends Self, A extends Route.RouteSet.Any, B extends Route.RouteSet.Any, C extends Route.RouteSet.Any, D extends Route.RouteSet.Any, E extends Route.RouteSet.Any, F extends Route.RouteSet.Any>(this: S, ab: (a: EmptySet<M, BuilderBindings<S>>) => A, bc: (b: A) => B, cd: (c: B) => C, de: (d: C) => D, ef: (e: D) => E, fg: (f: E) => F): Builder<{}, [
|
|
101
|
+
...Items<S>,
|
|
102
|
+
...FlattenItems<M, BuilderBindings<S>, Route.RouteSet.Items<F>>
|
|
103
|
+
]>;
|
|
104
|
+
<S extends Self, A extends Route.RouteSet.Any, B extends Route.RouteSet.Any, C extends Route.RouteSet.Any, D extends Route.RouteSet.Any, E extends Route.RouteSet.Any, F extends Route.RouteSet.Any, G extends Route.RouteSet.Any>(this: S, ab: (a: EmptySet<M, BuilderBindings<S>>) => A, bc: (b: A) => B, cd: (c: B) => C, de: (d: C) => D, ef: (e: D) => E, fg: (f: E) => F, gh: (g: F) => G): Builder<{}, [
|
|
105
|
+
...Items<S>,
|
|
106
|
+
...FlattenItems<M, BuilderBindings<S>, Route.RouteSet.Items<G>>
|
|
107
|
+
]>;
|
|
108
|
+
<S extends Self, A extends Route.RouteSet.Any, B extends Route.RouteSet.Any, C extends Route.RouteSet.Any, D extends Route.RouteSet.Any, E extends Route.RouteSet.Any, F extends Route.RouteSet.Any, G extends Route.RouteSet.Any, H extends Route.RouteSet.Any>(this: S, ab: (a: EmptySet<M, BuilderBindings<S>>) => A, bc: (b: A) => B, cd: (c: B) => C, de: (d: C) => D, ef: (e: D) => E, fg: (f: E) => F, gh: (g: F) => G, hi: (h: G) => H): Builder<{}, [
|
|
109
|
+
...Items<S>,
|
|
110
|
+
...FlattenItems<M, BuilderBindings<S>, Route.RouteSet.Items<H>>
|
|
111
|
+
]>;
|
|
112
|
+
<S extends Self, A extends Route.RouteSet.Any, B extends Route.RouteSet.Any, C extends Route.RouteSet.Any, D extends Route.RouteSet.Any, E extends Route.RouteSet.Any, F extends Route.RouteSet.Any, G extends Route.RouteSet.Any, H extends Route.RouteSet.Any, I extends Route.RouteSet.Any>(this: S, ab: (a: EmptySet<M, BuilderBindings<S>>) => A, bc: (b: A) => B, cd: (c: B) => C, de: (d: C) => D, ef: (e: D) => E, fg: (f: E) => F, gh: (g: F) => G, hi: (h: G) => H, ij: (i: H) => I): Builder<{}, [
|
|
113
|
+
...Items<S>,
|
|
114
|
+
...FlattenItems<M, BuilderBindings<S>, Route.RouteSet.Items<I>>
|
|
115
|
+
]>;
|
|
116
|
+
}
|
|
117
|
+
export {};
|
|
118
|
+
}
|
|
119
|
+
export {};
|