effect-start 0.15.0 → 0.17.0
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/package.json +2 -1
- package/src/ContentNegotiation.test.ts +103 -0
- package/src/ContentNegotiation.ts +10 -3
- package/src/Development.test.ts +119 -0
- package/src/Development.ts +137 -0
- package/src/Entity.test.ts +592 -0
- package/src/Entity.ts +359 -0
- package/src/FileRouter.ts +2 -2
- package/src/Http.test.ts +315 -20
- package/src/Http.ts +153 -11
- package/src/PathPattern.ts +3 -1
- package/src/Route.ts +26 -10
- package/src/RouteBody.test.ts +98 -66
- package/src/RouteBody.ts +125 -35
- package/src/RouteHook.ts +15 -14
- package/src/RouteHttp.test.ts +2549 -83
- package/src/RouteHttp.ts +337 -113
- package/src/RouteHttpTracer.ts +92 -0
- package/src/RouteMount.test.ts +23 -10
- package/src/RouteMount.ts +161 -4
- package/src/RouteSchema.test.ts +346 -0
- package/src/RouteSchema.ts +386 -7
- package/src/RouteSse.test.ts +249 -0
- package/src/RouteSse.ts +195 -0
- package/src/RouteTree.test.ts +233 -85
- package/src/RouteTree.ts +98 -44
- package/src/StreamExtra.ts +21 -1
- package/src/Values.test.ts +263 -0
- package/src/Values.ts +68 -6
- package/src/bun/BunBundle.ts +0 -73
- package/src/bun/BunHttpServer.ts +23 -7
- package/src/bun/BunRoute.test.ts +162 -0
- package/src/bun/BunRoute.ts +144 -105
- package/src/hyper/HyperHtml.test.ts +119 -0
- package/src/hyper/HyperHtml.ts +10 -2
- package/src/hyper/HyperNode.ts +2 -0
- package/src/hyper/HyperRoute.test.tsx +197 -0
- package/src/hyper/HyperRoute.ts +61 -0
- package/src/hyper/index.ts +4 -0
- package/src/hyper/jsx.d.ts +15 -0
- package/src/index.ts +2 -0
- package/src/node/FileSystem.ts +8 -0
- package/src/testing/TestLogger.test.ts +0 -3
- package/src/testing/TestLogger.ts +15 -9
- package/src/FileSystemExtra.test.ts +0 -242
- package/src/FileSystemExtra.ts +0 -66
package/src/RouteBody.test.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import * as test from "bun:test"
|
|
2
2
|
import * as Effect from "effect/Effect"
|
|
3
|
+
import * as ParseResult from "effect/ParseResult"
|
|
4
|
+
import * as Stream from "effect/Stream"
|
|
5
|
+
import * as Entity from "./Entity.ts"
|
|
6
|
+
import * as Route from "./Route.ts"
|
|
3
7
|
import * as RouteBody from "./RouteBody.ts"
|
|
4
8
|
import * as RouteMount from "./RouteMount.ts"
|
|
5
9
|
|
|
6
|
-
const text = RouteBody.build<string, "text">({
|
|
7
|
-
format: "text",
|
|
8
|
-
})
|
|
9
|
-
|
|
10
10
|
test.it("infers parent descriptions", () => {
|
|
11
11
|
RouteMount.get(
|
|
12
|
-
text((ctx) =>
|
|
12
|
+
Route.text((ctx) =>
|
|
13
13
|
Effect.gen(function*() {
|
|
14
14
|
test
|
|
15
15
|
.expectTypeOf(ctx)
|
|
@@ -24,13 +24,12 @@ test.it("infers parent descriptions", () => {
|
|
|
24
24
|
)
|
|
25
25
|
})
|
|
26
26
|
|
|
27
|
-
test.it("
|
|
28
|
-
text((ctx, next) =>
|
|
27
|
+
test.it("next is function returning Entity", () => {
|
|
28
|
+
Route.text((ctx, next) =>
|
|
29
29
|
Effect.gen(function*() {
|
|
30
30
|
test
|
|
31
31
|
.expectTypeOf(next)
|
|
32
|
-
.
|
|
33
|
-
.toEqualTypeOf<[]>()
|
|
32
|
+
.toExtend<() => Entity.Entity<string>>()
|
|
34
33
|
|
|
35
34
|
return "Hello, world!"
|
|
36
35
|
})
|
|
@@ -39,24 +38,66 @@ test.it("cannot modify context", () => {
|
|
|
39
38
|
|
|
40
39
|
test.it("enforces result value", () => {
|
|
41
40
|
// @ts-expect-error must return string
|
|
42
|
-
text((ctx, next) =>
|
|
41
|
+
Route.text((ctx, next) =>
|
|
43
42
|
Effect.gen(function*() {
|
|
44
43
|
return 1337
|
|
45
44
|
})
|
|
46
45
|
)
|
|
47
46
|
})
|
|
48
47
|
|
|
48
|
+
test.it("accepts text stream", () => {
|
|
49
|
+
RouteMount.get(
|
|
50
|
+
Route.text((ctx) =>
|
|
51
|
+
Effect.gen(function*() {
|
|
52
|
+
test
|
|
53
|
+
.expectTypeOf(ctx)
|
|
54
|
+
.toExtend<{
|
|
55
|
+
method: "GET"
|
|
56
|
+
format: "text"
|
|
57
|
+
}>()
|
|
58
|
+
|
|
59
|
+
return Stream.make("Hello", " ", "world!")
|
|
60
|
+
})
|
|
61
|
+
),
|
|
62
|
+
)
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
test.it("accepts Effect<Stream<string>> for html format", () => {
|
|
66
|
+
RouteMount.get(
|
|
67
|
+
Route.html(function*() {
|
|
68
|
+
return Stream.make("<div>", "content", "</div>")
|
|
69
|
+
}),
|
|
70
|
+
)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
test.it("accepts Effect<Stream<Uint8Array>> for bytes format", () => {
|
|
74
|
+
const encoder = new TextEncoder()
|
|
75
|
+
|
|
76
|
+
RouteMount.get(
|
|
77
|
+
Route.bytes(function*() {
|
|
78
|
+
return Stream.make(encoder.encode("chunk"))
|
|
79
|
+
}),
|
|
80
|
+
)
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
test.it("rejects Stream for json format", () => {
|
|
84
|
+
// @ts-expect-error Stream not allowed for json format
|
|
85
|
+
Route.json(function*() {
|
|
86
|
+
return Stream.make({ msg: "hello" })
|
|
87
|
+
})
|
|
88
|
+
})
|
|
89
|
+
|
|
49
90
|
test.it("accepts value directly", () => {
|
|
50
91
|
const value = "Hello, world!"
|
|
51
92
|
|
|
52
93
|
test
|
|
53
|
-
.expectTypeOf(text)
|
|
94
|
+
.expectTypeOf(Route.text)
|
|
54
95
|
.toBeCallableWith(value)
|
|
55
96
|
})
|
|
56
97
|
|
|
57
98
|
test.describe(`${RouteBody.handle.name}()`, () => {
|
|
58
99
|
const ctx = {}
|
|
59
|
-
const next = () => Effect.succeed("next"
|
|
100
|
+
const next = () => Entity.effect(Effect.succeed(Entity.make("next")))
|
|
60
101
|
|
|
61
102
|
test.it("accepts all HandlerInput variants", () => {
|
|
62
103
|
test
|
|
@@ -67,116 +108,107 @@ test.describe(`${RouteBody.handle.name}()`, () => {
|
|
|
67
108
|
})
|
|
68
109
|
|
|
69
110
|
test.it("handles plain value", async () => {
|
|
70
|
-
const handler = RouteBody.handle("hello")
|
|
71
|
-
|
|
72
|
-
test
|
|
73
|
-
.expectTypeOf(handler)
|
|
74
|
-
.returns
|
|
75
|
-
.toEqualTypeOf<
|
|
76
|
-
Effect.Effect<string, never, never>
|
|
77
|
-
>()
|
|
78
|
-
|
|
111
|
+
const handler = RouteBody.handle<{}, string, never, never>("hello")
|
|
79
112
|
const result = await Effect.runPromise(handler(ctx, next))
|
|
80
|
-
test.expect(result).toBe("hello")
|
|
113
|
+
test.expect(result.body).toBe("hello")
|
|
114
|
+
test.expect(result.status).toBe(200)
|
|
81
115
|
})
|
|
82
116
|
|
|
83
117
|
test.it("handles Effect directly", async () => {
|
|
84
|
-
const handler = RouteBody.handle(
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
.expectTypeOf(handler)
|
|
88
|
-
.returns
|
|
89
|
-
.toEqualTypeOf<
|
|
90
|
-
Effect.Effect<string, never, never>
|
|
91
|
-
>()
|
|
92
|
-
|
|
118
|
+
const handler = RouteBody.handle<{}, string, never, never>(
|
|
119
|
+
Effect.succeed("from effect"),
|
|
120
|
+
)
|
|
93
121
|
const result = await Effect.runPromise(handler(ctx, next))
|
|
94
|
-
|
|
95
|
-
test
|
|
96
|
-
.expect(result)
|
|
97
|
-
.toBe("from effect")
|
|
122
|
+
test.expect(result.body).toBe("from effect")
|
|
98
123
|
})
|
|
99
124
|
|
|
100
125
|
test.it("handles Effect with error", async () => {
|
|
101
|
-
const handler = RouteBody.handle
|
|
126
|
+
const handler = RouteBody.handle<{}, never, Error, never>(
|
|
127
|
+
Effect.fail(new Error("oops")),
|
|
128
|
+
)
|
|
102
129
|
|
|
103
130
|
test
|
|
104
131
|
.expectTypeOf(handler)
|
|
105
132
|
.returns
|
|
106
|
-
.
|
|
107
|
-
Effect.Effect<never
|
|
133
|
+
.toExtend<
|
|
134
|
+
Effect.Effect<Entity.Entity<never>, Error, never>
|
|
108
135
|
>()
|
|
109
136
|
})
|
|
110
137
|
|
|
111
138
|
test.it("handles function", async () => {
|
|
112
|
-
const handler = RouteBody.handle(
|
|
113
|
-
(ctx
|
|
139
|
+
const handler = RouteBody.handle<{ id: number }, number, never, never>(
|
|
140
|
+
(ctx) => Effect.succeed(ctx.id),
|
|
114
141
|
)
|
|
115
142
|
|
|
116
143
|
test
|
|
117
144
|
.expectTypeOf(handler)
|
|
118
145
|
.parameters
|
|
119
146
|
.toEqualTypeOf<
|
|
120
|
-
[
|
|
147
|
+
[
|
|
148
|
+
{ id: number },
|
|
149
|
+
(
|
|
150
|
+
context?: Partial<{ id: number }> & Record<string, unknown>,
|
|
151
|
+
) => Entity.Entity<number>,
|
|
152
|
+
]
|
|
121
153
|
>()
|
|
122
154
|
test
|
|
123
155
|
.expectTypeOf(handler)
|
|
124
156
|
.returns
|
|
125
157
|
.toEqualTypeOf<
|
|
126
|
-
Effect.Effect<number
|
|
158
|
+
Effect.Effect<Entity.Entity<number>, never, never>
|
|
127
159
|
>()
|
|
128
160
|
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
)
|
|
161
|
+
const numNext = () => Entity.effect(Effect.succeed(Entity.make(23)))
|
|
162
|
+
const result = await Effect.runPromise(handler({ id: 42 }, numNext))
|
|
132
163
|
|
|
133
|
-
test
|
|
134
|
-
.expect(result)
|
|
135
|
-
.toBe(42)
|
|
164
|
+
test.expect(result.body).toBe(42)
|
|
136
165
|
})
|
|
137
166
|
|
|
138
167
|
test.it("handles generator", async () => {
|
|
139
|
-
const handler = RouteBody.handle
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
168
|
+
const handler = RouteBody.handle<{ id: number }, number, never, never>(
|
|
169
|
+
function*(ctx) {
|
|
170
|
+
const n = yield* Effect.succeed(ctx.id)
|
|
171
|
+
return n * 2
|
|
172
|
+
},
|
|
173
|
+
)
|
|
143
174
|
|
|
144
175
|
test
|
|
145
176
|
.expectTypeOf(handler)
|
|
146
177
|
.parameters
|
|
147
178
|
.toEqualTypeOf<
|
|
148
|
-
[
|
|
179
|
+
[
|
|
180
|
+
{ id: number },
|
|
181
|
+
(
|
|
182
|
+
context?: Partial<{ id: number }> & Record<string, unknown>,
|
|
183
|
+
) => Entity.Entity<number>,
|
|
184
|
+
]
|
|
149
185
|
>()
|
|
150
186
|
|
|
151
187
|
test
|
|
152
188
|
.expectTypeOf(handler)
|
|
153
189
|
.returns
|
|
154
190
|
.toEqualTypeOf<
|
|
155
|
-
Effect.Effect<number
|
|
191
|
+
Effect.Effect<Entity.Entity<number>, never, never>
|
|
156
192
|
>()
|
|
157
193
|
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
handler({ id: 21 }, () => Effect.succeed(23)),
|
|
161
|
-
)
|
|
194
|
+
const numNext = () => Entity.effect(Effect.succeed(Entity.make(23)))
|
|
195
|
+
const result = await Effect.runPromise(handler({ id: 21 }, numNext))
|
|
162
196
|
|
|
163
|
-
test
|
|
164
|
-
.expect(result)
|
|
165
|
-
.toBe(42)
|
|
197
|
+
test.expect(result.body).toBe(42)
|
|
166
198
|
})
|
|
167
199
|
|
|
168
200
|
test.it("generator can call next", async () => {
|
|
169
|
-
const handler = RouteBody.handle(
|
|
170
|
-
function*(_ctx
|
|
171
|
-
const fromNext = yield* next()
|
|
201
|
+
const handler = RouteBody.handle<{}, string, ParseResult.ParseError, never>(
|
|
202
|
+
function*(_ctx, next) {
|
|
203
|
+
const fromNext = yield* next().text
|
|
172
204
|
return `got: ${fromNext}`
|
|
173
205
|
},
|
|
174
206
|
)
|
|
175
207
|
|
|
176
|
-
const result = await Effect.runPromise(handler(ctx, next))
|
|
208
|
+
const result = await Effect.runPromise(Effect.orDie(handler(ctx, next)))
|
|
177
209
|
|
|
178
210
|
test
|
|
179
|
-
.expect(result)
|
|
211
|
+
.expect(result.body)
|
|
180
212
|
.toBe("got: next")
|
|
181
213
|
})
|
|
182
214
|
})
|
package/src/RouteBody.ts
CHANGED
|
@@ -1,52 +1,83 @@
|
|
|
1
1
|
import * as Effect from "effect/Effect"
|
|
2
|
+
import type * as Stream from "effect/Stream"
|
|
2
3
|
import type * as Utils from "effect/Utils"
|
|
4
|
+
import * as Entity from "./Entity.ts"
|
|
3
5
|
import * as Route from "./Route.ts"
|
|
6
|
+
import type * as Values from "./Values.ts"
|
|
4
7
|
|
|
5
8
|
export type Format =
|
|
6
9
|
| "text"
|
|
7
10
|
| "html"
|
|
8
11
|
| "json"
|
|
9
12
|
| "bytes"
|
|
13
|
+
| "*"
|
|
14
|
+
|
|
15
|
+
const formatToContentType: Record<Format, string | undefined> = {
|
|
16
|
+
text: "text/plain; charset=utf-8",
|
|
17
|
+
html: "text/html; charset=utf-8",
|
|
18
|
+
json: "application/json",
|
|
19
|
+
bytes: "application/octet-stream",
|
|
20
|
+
"*": undefined,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
type UnwrapStream<T> = T extends Stream.Stream<infer V, any, any> ? V : T
|
|
10
24
|
|
|
11
25
|
export type HandlerInput<B, A, E, R> =
|
|
12
26
|
| A
|
|
13
|
-
|
|
|
14
|
-
|
|
|
15
|
-
|
|
16
|
-
|
|
27
|
+
| Entity.Entity<A>
|
|
28
|
+
| Effect.Effect<A | Entity.Entity<A>, E, R>
|
|
29
|
+
| ((
|
|
30
|
+
context: Values.Simplify<B>,
|
|
31
|
+
next: (
|
|
32
|
+
context?: Partial<B> & Record<string, unknown>,
|
|
33
|
+
) => Entity.Entity<UnwrapStream<A>>,
|
|
34
|
+
) =>
|
|
35
|
+
| Effect.Effect<A | Entity.Entity<A>, E, R>
|
|
36
|
+
| Generator<
|
|
37
|
+
Utils.YieldWrap<Effect.Effect<unknown, E, R>>,
|
|
38
|
+
A | Entity.Entity<A>,
|
|
39
|
+
unknown
|
|
40
|
+
>)
|
|
17
41
|
|
|
18
|
-
export function handle<B, A, E, R>(
|
|
19
|
-
handler: (context: B, next: () => Effect.Effect<A>) =>
|
|
20
|
-
| Effect.Effect<A, E, R>
|
|
21
|
-
| Generator<Utils.YieldWrap<Effect.Effect<any, E, R>>, A, any>,
|
|
22
|
-
): Route.Route.HandlerImmutable<B, A, E, R>
|
|
23
|
-
export function handle<A, E, R>(
|
|
24
|
-
handler: Effect.Effect<A, E, R>,
|
|
25
|
-
): Route.Route.HandlerImmutable<{}, A, E, R>
|
|
26
|
-
export function handle<A>(
|
|
27
|
-
handler: A,
|
|
28
|
-
): Route.Route.HandlerImmutable<{}, A, never, never>
|
|
29
42
|
export function handle<B, A, E, R>(
|
|
30
43
|
handler: HandlerInput<B, A, E, R>,
|
|
31
|
-
): Route.Route.
|
|
44
|
+
): Route.Route.Handler<B, A, E, R> {
|
|
32
45
|
if (typeof handler === "function") {
|
|
33
46
|
return (
|
|
34
47
|
context: B,
|
|
35
|
-
next: (
|
|
36
|
-
|
|
48
|
+
next: (
|
|
49
|
+
context?: Partial<B> & Record<string, unknown>,
|
|
50
|
+
) => Entity.Entity<A>,
|
|
51
|
+
): Effect.Effect<Entity.Entity<A>, E, R> => {
|
|
37
52
|
const result = (handler as Function)(context, next)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
53
|
+
const effect = Effect.isEffect(result)
|
|
54
|
+
? result as Effect.Effect<A | Entity.Entity<A>, E, R>
|
|
55
|
+
: Effect.gen(function*() {
|
|
56
|
+
return yield* result
|
|
57
|
+
}) as Effect.Effect<A | Entity.Entity<A>, E, R>
|
|
58
|
+
return Effect.map(effect, normalizeToEntity)
|
|
44
59
|
}
|
|
45
60
|
}
|
|
46
61
|
if (Effect.isEffect(handler)) {
|
|
47
|
-
return (_context, _next) =>
|
|
62
|
+
return (_context, _next) =>
|
|
63
|
+
Effect.map(handler, normalizeToEntity) as Effect.Effect<
|
|
64
|
+
Entity.Entity<A>,
|
|
65
|
+
E,
|
|
66
|
+
R
|
|
67
|
+
>
|
|
68
|
+
}
|
|
69
|
+
if (Entity.isEntity(handler)) {
|
|
70
|
+
return (_context, _next) => Effect.succeed(handler as Entity.Entity<A>)
|
|
48
71
|
}
|
|
49
|
-
return (_context, _next) =>
|
|
72
|
+
return (_context, _next) =>
|
|
73
|
+
Effect.succeed(normalizeToEntity(handler as A) as Entity.Entity<A>)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function normalizeToEntity<A>(value: A | Entity.Entity<A>): Entity.Entity<A> {
|
|
77
|
+
if (Entity.isEntity(value)) {
|
|
78
|
+
return value as Entity.Entity<A>
|
|
79
|
+
}
|
|
80
|
+
return Entity.make(value as A, { status: 200 })
|
|
50
81
|
}
|
|
51
82
|
|
|
52
83
|
export function build<
|
|
@@ -59,7 +90,8 @@ export function build<
|
|
|
59
90
|
D extends Route.RouteDescriptor.Any,
|
|
60
91
|
B extends {},
|
|
61
92
|
I extends Route.Route.Tuple,
|
|
62
|
-
A extends Value
|
|
93
|
+
A extends F extends "json" ? Value
|
|
94
|
+
: Value | Stream.Stream<Value, any, any>,
|
|
63
95
|
E = never,
|
|
64
96
|
R = never,
|
|
65
97
|
>(
|
|
@@ -75,8 +107,28 @@ export function build<
|
|
|
75
107
|
return function(
|
|
76
108
|
self: Route.RouteSet.RouteSet<D, B, I>,
|
|
77
109
|
) {
|
|
110
|
+
const contentType = formatToContentType[descriptors.format]
|
|
111
|
+
const baseHandler = handle(handler)
|
|
112
|
+
const wrappedHandler: Route.Route.Handler<
|
|
113
|
+
D & B & Route.ExtractBindings<I> & { format: F },
|
|
114
|
+
A,
|
|
115
|
+
E,
|
|
116
|
+
R
|
|
117
|
+
> = (ctx, next) =>
|
|
118
|
+
Effect.map(
|
|
119
|
+
baseHandler(ctx as any, next as any),
|
|
120
|
+
(entity) =>
|
|
121
|
+
entity.headers["content-type"]
|
|
122
|
+
? entity
|
|
123
|
+
: Entity.make(entity.body, {
|
|
124
|
+
status: entity.status,
|
|
125
|
+
url: entity.url,
|
|
126
|
+
headers: { ...entity.headers, "content-type": contentType },
|
|
127
|
+
}),
|
|
128
|
+
)
|
|
129
|
+
|
|
78
130
|
const route = Route.make<{ format: F }, {}, A, E, R>(
|
|
79
|
-
|
|
131
|
+
wrappedHandler as any,
|
|
80
132
|
descriptors,
|
|
81
133
|
)
|
|
82
134
|
|
|
@@ -97,10 +149,48 @@ export function build<
|
|
|
97
149
|
}
|
|
98
150
|
}
|
|
99
151
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
152
|
+
export type RenderValue =
|
|
153
|
+
| string
|
|
154
|
+
| Uint8Array
|
|
155
|
+
| Stream.Stream<string | Uint8Array, any, any>
|
|
156
|
+
|
|
157
|
+
export function render<
|
|
158
|
+
D extends Route.RouteDescriptor.Any,
|
|
159
|
+
B extends {},
|
|
160
|
+
I extends Route.Route.Tuple,
|
|
161
|
+
A extends RenderValue,
|
|
162
|
+
E = never,
|
|
163
|
+
R = never,
|
|
164
|
+
>(
|
|
165
|
+
handler: HandlerInput<
|
|
166
|
+
NoInfer<
|
|
167
|
+
D & B & Route.ExtractBindings<I> & { format: "*" }
|
|
168
|
+
>,
|
|
169
|
+
A,
|
|
170
|
+
E,
|
|
171
|
+
R
|
|
172
|
+
>,
|
|
173
|
+
) {
|
|
174
|
+
return function(
|
|
175
|
+
self: Route.RouteSet.RouteSet<D, B, I>,
|
|
176
|
+
) {
|
|
177
|
+
const route = Route.make<{ format: "*" }, {}, A, E, R>(
|
|
178
|
+
handle(handler) as any,
|
|
179
|
+
{ format: "*" },
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
const items: [...I, Route.Route.Route<{ format: "*" }, {}, A, E, R>] = [
|
|
183
|
+
...Route.items(self),
|
|
184
|
+
route,
|
|
185
|
+
]
|
|
186
|
+
|
|
187
|
+
return Route.set<
|
|
188
|
+
D,
|
|
189
|
+
B,
|
|
190
|
+
[...I, Route.Route.Route<{ format: "*" }, {}, A, E, R>]
|
|
191
|
+
>(
|
|
192
|
+
items,
|
|
193
|
+
Route.descriptor(self),
|
|
194
|
+
)
|
|
195
|
+
}
|
|
196
|
+
}
|
package/src/RouteHook.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as Effect from "effect/Effect"
|
|
2
2
|
import type * as Utils from "effect/Utils"
|
|
3
|
+
import * as Entity from "./Entity.ts"
|
|
3
4
|
import * as Route from "./Route.ts"
|
|
4
5
|
|
|
5
6
|
export type FilterResult<BOut, E, R> =
|
|
@@ -11,9 +12,9 @@ export type FilterHandlerInput<BIn, BOut, E, R> =
|
|
|
11
12
|
| ((context: BIn) =>
|
|
12
13
|
| FilterResult<BOut, E, R>
|
|
13
14
|
| Generator<
|
|
14
|
-
Utils.YieldWrap<Effect.Effect<
|
|
15
|
+
Utils.YieldWrap<Effect.Effect<unknown, E, R>>,
|
|
15
16
|
{ context: BOut },
|
|
16
|
-
|
|
17
|
+
unknown
|
|
17
18
|
>)
|
|
18
19
|
|
|
19
20
|
export function filter<
|
|
@@ -34,26 +35,26 @@ export function filter<
|
|
|
34
35
|
): Route.RouteSet.RouteSet<
|
|
35
36
|
D,
|
|
36
37
|
SB,
|
|
37
|
-
[
|
|
38
|
+
[
|
|
39
|
+
...P,
|
|
40
|
+
Route.Route.Route<{}, BOut, unknown, E, R>,
|
|
41
|
+
]
|
|
38
42
|
> {
|
|
39
43
|
const route = Route.make<
|
|
40
44
|
{},
|
|
41
45
|
BOut,
|
|
42
|
-
|
|
46
|
+
unknown,
|
|
43
47
|
E,
|
|
44
48
|
R
|
|
45
|
-
>((context: BOut, next) =>
|
|
49
|
+
>((context: BOut, next: (ctx?: Partial<BOut>) => Entity.Entity<unknown>) =>
|
|
46
50
|
Effect.gen(function*() {
|
|
47
51
|
const filterResult = yield* normalized(context as unknown as BIn)
|
|
48
52
|
|
|
49
|
-
|
|
50
|
-
filterResult
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
: context,
|
|
56
|
-
)
|
|
53
|
+
const mergedContext = filterResult
|
|
54
|
+
? { ...context, ...filterResult.context }
|
|
55
|
+
: context
|
|
56
|
+
|
|
57
|
+
return yield* Entity.resolve(next(mergedContext as Partial<BOut>))
|
|
57
58
|
})
|
|
58
59
|
)
|
|
59
60
|
|
|
@@ -61,7 +62,7 @@ export function filter<
|
|
|
61
62
|
[
|
|
62
63
|
...Route.items(self),
|
|
63
64
|
route,
|
|
64
|
-
] as [...P, Route.Route.Route<{}, BOut,
|
|
65
|
+
] as [...P, Route.Route.Route<{}, BOut, unknown, E, R>],
|
|
65
66
|
Route.descriptor(self),
|
|
66
67
|
)
|
|
67
68
|
}
|