effect-start 0.21.0 → 0.22.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/README.md +1 -4
- package/dist/Cookies.js +392 -0
- package/dist/FileSystem.js +131 -0
- package/dist/Socket.js +37 -0
- package/package.json +35 -36
- package/src/Commander.ts +73 -130
- package/src/ContentNegotiation.ts +64 -95
- package/src/Cookies.ts +36 -57
- package/src/Development.ts +47 -62
- package/src/Effectify.ts +222 -206
- package/src/Entity.ts +59 -86
- package/src/FilePathPattern.ts +5 -5
- package/src/FileRouter.ts +37 -62
- package/src/FileRouterCodegen.ts +63 -55
- package/src/FileSystem.ts +46 -59
- package/src/Http.ts +17 -50
- package/src/PathPattern.ts +33 -41
- package/src/PlatformError.ts +29 -50
- package/src/PlatformRuntime.ts +39 -47
- package/src/Route.ts +68 -187
- package/src/RouteBody.ts +45 -161
- package/src/RouteHook.ts +22 -45
- package/src/RouteHttp.ts +88 -142
- package/src/RouteHttpTracer.ts +25 -26
- package/src/RouteMount.ts +100 -238
- package/src/RouteSchema.ts +67 -201
- package/src/RouteSse.ts +28 -82
- package/src/RouteTree.ts +31 -79
- package/src/RouteTrie.ts +13 -32
- package/src/SchemaExtra.ts +3 -5
- package/src/Socket.ts +5 -2
- package/src/Start.ts +20 -21
- package/src/StreamExtra.ts +93 -96
- package/src/TuplePathPattern.ts +54 -43
- package/src/Unique.ts +9 -15
- package/src/Values.ts +26 -30
- package/src/bun/BunBundle.ts +27 -73
- package/src/bun/BunImportTrackerPlugin.ts +67 -65
- package/src/bun/BunRoute.ts +12 -31
- package/src/bun/BunRuntime.ts +3 -10
- package/src/bun/BunServer.ts +55 -91
- package/src/bun/BunVirtualFilesPlugin.ts +1 -4
- package/src/bun/_BunEnhancedResolve.ts +17 -42
- package/src/bun/_empty.html +0 -1
- package/src/bundler/Bundle.ts +20 -36
- package/src/bundler/BundleFiles.ts +35 -55
- package/src/client/Overlay.ts +1 -2
- package/src/client/ScrollState.ts +5 -9
- package/src/client/index.ts +10 -13
- package/src/datastar/actions/fetch.ts +29 -48
- package/src/datastar/actions/peek.ts +1 -5
- package/src/datastar/actions/setAll.ts +2 -2
- package/src/datastar/actions/toggleAll.ts +2 -2
- package/src/datastar/attributes/attr.ts +17 -18
- package/src/datastar/attributes/bind.ts +41 -61
- package/src/datastar/attributes/class.ts +2 -5
- package/src/datastar/attributes/computed.ts +2 -10
- package/src/datastar/attributes/effect.ts +1 -2
- package/src/datastar/attributes/indicator.ts +2 -8
- package/src/datastar/attributes/init.ts +2 -10
- package/src/datastar/attributes/jsonSignals.ts +1 -6
- package/src/datastar/attributes/on.ts +4 -13
- package/src/datastar/attributes/onIntersect.ts +10 -22
- package/src/datastar/attributes/onInterval.ts +2 -10
- package/src/datastar/attributes/onSignalPatch.ts +18 -28
- package/src/datastar/attributes/ref.ts +1 -2
- package/src/datastar/attributes/show.ts +1 -2
- package/src/datastar/attributes/signals.ts +1 -5
- package/src/datastar/attributes/style.ts +6 -12
- package/src/datastar/attributes/text.ts +1 -2
- package/src/datastar/engine.ts +102 -158
- package/src/datastar/index.ts +2 -2
- package/src/datastar/utils.ts +16 -51
- package/src/datastar/watchers/patchElements.ts +35 -93
- package/src/datastar/watchers/patchSignals.ts +1 -2
- package/src/experimental/EncryptedCookies.ts +79 -142
- package/src/hyper/Hyper.ts +14 -33
- package/src/hyper/HyperHtml.ts +9 -10
- package/src/hyper/HyperNode.ts +2 -7
- package/src/hyper/HyperRoute.ts +2 -5
- package/src/hyper/jsx-runtime.ts +2 -10
- package/src/hyper/jsx.d.ts +171 -440
- package/src/lint/plugin.js +276 -0
- package/src/node/NodeFileSystem.ts +138 -186
- package/src/node/NodeUtils.ts +1 -3
- package/src/testing/TestLogger.ts +9 -22
- package/src/testing/utils.ts +30 -31
- package/src/x/cloudflare/CloudflareTunnel.ts +37 -54
- package/src/x/datastar/Datastar.ts +3 -10
- package/src/x/datastar/index.ts +1 -3
- package/src/x/datastar/jsx-datastar.d.ts +1 -4
- package/src/x/tailwind/TailwindPlugin.ts +119 -112
- package/src/x/tailwind/compile.ts +10 -33
- package/src/x/tailwind/plugin.ts +2 -2
package/src/RouteSchema.ts
CHANGED
|
@@ -1,19 +1,15 @@
|
|
|
1
1
|
import * as Effect from "effect/Effect"
|
|
2
|
-
import * as ParseResult from "effect/ParseResult"
|
|
2
|
+
import type * as ParseResult from "effect/ParseResult"
|
|
3
3
|
import * as Schema from "effect/Schema"
|
|
4
4
|
import type * as Scope from "effect/Scope"
|
|
5
5
|
import * as Http from "./Http.ts"
|
|
6
6
|
import * as PathPattern from "./PathPattern.ts"
|
|
7
|
-
import * as Route from "./Route.ts"
|
|
7
|
+
import type * as Route from "./Route.ts"
|
|
8
8
|
import * as RouteHook from "./RouteHook.ts"
|
|
9
9
|
|
|
10
10
|
export interface RequestBodyError {
|
|
11
11
|
readonly _tag: "RequestBodyError"
|
|
12
|
-
readonly reason:
|
|
13
|
-
| "JsonError"
|
|
14
|
-
| "UrlParamsError"
|
|
15
|
-
| "MultipartError"
|
|
16
|
-
| "FormDataError"
|
|
12
|
+
readonly reason: "JsonError" | "UrlParamsError" | "MultipartError" | "FormDataError"
|
|
17
13
|
readonly cause: unknown
|
|
18
14
|
}
|
|
19
15
|
|
|
@@ -29,211 +25,114 @@ export const File = Schema.TaggedStruct("File", {
|
|
|
29
25
|
content: Schema.Uint8ArrayFromSelf,
|
|
30
26
|
})
|
|
31
27
|
|
|
32
|
-
export function schemaHeaders<
|
|
33
|
-
A,
|
|
34
|
-
I extends Readonly<Record<string, string | undefined>>,
|
|
35
|
-
R,
|
|
36
|
-
>(
|
|
28
|
+
export function schemaHeaders<A, I extends Readonly<Record<string, string | undefined>>, R>(
|
|
37
29
|
fields: Schema.Schema<A, I, R>,
|
|
38
|
-
): <
|
|
39
|
-
D extends Route.RouteDescriptor.Any,
|
|
40
|
-
SB extends {},
|
|
41
|
-
P extends Route.Route.Tuple,
|
|
42
|
-
>(
|
|
30
|
+
): <D extends Route.RouteDescriptor.Any, SB extends {}, P extends Route.Route.Tuple>(
|
|
43
31
|
self: Route.RouteSet.RouteSet<D, SB, P>,
|
|
44
32
|
) => Route.RouteSet.RouteSet<
|
|
45
33
|
D,
|
|
46
34
|
SB,
|
|
47
|
-
[
|
|
48
|
-
...P,
|
|
49
|
-
Route.Route.Route<
|
|
50
|
-
{},
|
|
51
|
-
{ headers: A },
|
|
52
|
-
unknown,
|
|
53
|
-
ParseResult.ParseError,
|
|
54
|
-
R
|
|
55
|
-
>,
|
|
56
|
-
]
|
|
35
|
+
[...P, Route.Route.Route<{}, { headers: A }, unknown, ParseResult.ParseError, R>]
|
|
57
36
|
> {
|
|
58
37
|
const decode = Schema.decodeUnknown(fields)
|
|
59
38
|
return RouteHook.filter((ctx: { request: Request; headers?: {} }) =>
|
|
60
|
-
Effect.map(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
...ctx.headers,
|
|
66
|
-
...parsed,
|
|
67
|
-
},
|
|
39
|
+
Effect.map(decode(Http.mapHeaders(ctx.request.headers)), (parsed) => ({
|
|
40
|
+
context: {
|
|
41
|
+
headers: {
|
|
42
|
+
...ctx.headers,
|
|
43
|
+
...parsed,
|
|
68
44
|
},
|
|
69
|
-
}
|
|
70
|
-
)
|
|
45
|
+
},
|
|
46
|
+
})),
|
|
71
47
|
)
|
|
72
48
|
}
|
|
73
49
|
|
|
74
|
-
export function schemaCookies<
|
|
75
|
-
A,
|
|
76
|
-
I extends Readonly<Record<string, string | undefined>>,
|
|
77
|
-
R,
|
|
78
|
-
>(
|
|
50
|
+
export function schemaCookies<A, I extends Readonly<Record<string, string | undefined>>, R>(
|
|
79
51
|
fields: Schema.Schema<A, I, R>,
|
|
80
|
-
): <
|
|
81
|
-
D extends Route.RouteDescriptor.Any,
|
|
82
|
-
SB extends {},
|
|
83
|
-
P extends Route.Route.Tuple,
|
|
84
|
-
>(
|
|
52
|
+
): <D extends Route.RouteDescriptor.Any, SB extends {}, P extends Route.Route.Tuple>(
|
|
85
53
|
self: Route.RouteSet.RouteSet<D, SB, P>,
|
|
86
54
|
) => Route.RouteSet.RouteSet<
|
|
87
55
|
D,
|
|
88
56
|
SB,
|
|
89
|
-
[
|
|
90
|
-
...P,
|
|
91
|
-
Route.Route.Route<
|
|
92
|
-
{},
|
|
93
|
-
{ cookies: A },
|
|
94
|
-
unknown,
|
|
95
|
-
ParseResult.ParseError,
|
|
96
|
-
R
|
|
97
|
-
>,
|
|
98
|
-
]
|
|
57
|
+
[...P, Route.Route.Route<{}, { cookies: A }, unknown, ParseResult.ParseError, R>]
|
|
99
58
|
> {
|
|
100
59
|
const decode = Schema.decodeUnknown(fields)
|
|
101
60
|
return RouteHook.filter((ctx: { request: Request; cookies?: {} }) =>
|
|
102
|
-
Effect.map(
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
...ctx.cookies,
|
|
108
|
-
...parsed,
|
|
109
|
-
},
|
|
61
|
+
Effect.map(decode(Http.parseCookies(ctx.request.headers.get("cookie"))), (parsed) => ({
|
|
62
|
+
context: {
|
|
63
|
+
cookies: {
|
|
64
|
+
...ctx.cookies,
|
|
65
|
+
...parsed,
|
|
110
66
|
},
|
|
111
|
-
}
|
|
112
|
-
)
|
|
67
|
+
},
|
|
68
|
+
})),
|
|
113
69
|
)
|
|
114
70
|
}
|
|
115
71
|
|
|
116
72
|
export function schemaSearchParams<
|
|
117
73
|
A,
|
|
118
|
-
I extends Readonly<
|
|
119
|
-
Record<string, string | ReadonlyArray<string> | undefined>
|
|
120
|
-
>,
|
|
74
|
+
I extends Readonly<Record<string, string | ReadonlyArray<string> | undefined>>,
|
|
121
75
|
R,
|
|
122
76
|
>(
|
|
123
77
|
fields: Schema.Schema<A, I, R>,
|
|
124
|
-
): <
|
|
125
|
-
D extends Route.RouteDescriptor.Any,
|
|
126
|
-
SB extends {},
|
|
127
|
-
P extends Route.Route.Tuple,
|
|
128
|
-
>(
|
|
78
|
+
): <D extends Route.RouteDescriptor.Any, SB extends {}, P extends Route.Route.Tuple>(
|
|
129
79
|
self: Route.RouteSet.RouteSet<D, SB, P>,
|
|
130
80
|
) => Route.RouteSet.RouteSet<
|
|
131
81
|
D,
|
|
132
82
|
SB,
|
|
133
|
-
[
|
|
134
|
-
...P,
|
|
135
|
-
Route.Route.Route<
|
|
136
|
-
{},
|
|
137
|
-
{ searchParams: A },
|
|
138
|
-
unknown,
|
|
139
|
-
ParseResult.ParseError,
|
|
140
|
-
R
|
|
141
|
-
>,
|
|
142
|
-
]
|
|
83
|
+
[...P, Route.Route.Route<{}, { searchParams: A }, unknown, ParseResult.ParseError, R>]
|
|
143
84
|
> {
|
|
144
85
|
const decode = Schema.decodeUnknown(fields)
|
|
145
86
|
return RouteHook.filter((ctx: { request: Request; searchParams?: {} }) => {
|
|
146
87
|
const url = new URL(ctx.request.url)
|
|
147
|
-
return Effect.map(
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
...ctx.searchParams,
|
|
153
|
-
...parsed,
|
|
154
|
-
},
|
|
88
|
+
return Effect.map(decode(Http.mapUrlSearchParams(url.searchParams)), (parsed) => ({
|
|
89
|
+
context: {
|
|
90
|
+
searchParams: {
|
|
91
|
+
...ctx.searchParams,
|
|
92
|
+
...parsed,
|
|
155
93
|
},
|
|
156
|
-
}
|
|
157
|
-
)
|
|
94
|
+
},
|
|
95
|
+
}))
|
|
158
96
|
})
|
|
159
97
|
}
|
|
160
98
|
|
|
161
|
-
export function schemaPathParams<
|
|
162
|
-
A,
|
|
163
|
-
I extends Readonly<Record<string, string | undefined>>,
|
|
164
|
-
R,
|
|
165
|
-
>(
|
|
99
|
+
export function schemaPathParams<A, I extends Readonly<Record<string, string | undefined>>, R>(
|
|
166
100
|
fields: Schema.Schema<A, I, R>,
|
|
167
|
-
): <
|
|
168
|
-
D extends Route.RouteDescriptor.Any,
|
|
169
|
-
SB extends {},
|
|
170
|
-
P extends Route.Route.Tuple,
|
|
171
|
-
>(
|
|
101
|
+
): <D extends Route.RouteDescriptor.Any, SB extends {}, P extends Route.Route.Tuple>(
|
|
172
102
|
self: Route.RouteSet.RouteSet<D, SB, P>,
|
|
173
103
|
) => Route.RouteSet.RouteSet<
|
|
174
104
|
D,
|
|
175
105
|
SB,
|
|
176
|
-
[
|
|
177
|
-
...P,
|
|
178
|
-
Route.Route.Route<
|
|
179
|
-
{},
|
|
180
|
-
{ pathParams: A },
|
|
181
|
-
unknown,
|
|
182
|
-
ParseResult.ParseError,
|
|
183
|
-
R
|
|
184
|
-
>,
|
|
185
|
-
]
|
|
106
|
+
[...P, Route.Route.Route<{}, { pathParams: A }, unknown, ParseResult.ParseError, R>]
|
|
186
107
|
> {
|
|
187
108
|
const decode = Schema.decodeUnknown(fields)
|
|
188
|
-
return RouteHook.filter(
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
},
|
|
202
|
-
}),
|
|
203
|
-
)
|
|
204
|
-
},
|
|
205
|
-
)
|
|
109
|
+
return RouteHook.filter((ctx: { request: Request; path?: string; pathParams?: {} }) => {
|
|
110
|
+
const url = new URL(ctx.request.url)
|
|
111
|
+
const pattern = ctx.path ?? "/"
|
|
112
|
+
const params = PathPattern.match(pattern, url.pathname) ?? {}
|
|
113
|
+
return Effect.map(decode(params), (parsed) => ({
|
|
114
|
+
context: {
|
|
115
|
+
pathParams: {
|
|
116
|
+
...ctx.pathParams,
|
|
117
|
+
...parsed,
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
}))
|
|
121
|
+
})
|
|
206
122
|
}
|
|
207
123
|
|
|
208
|
-
export function schemaBodyJson<
|
|
209
|
-
A,
|
|
210
|
-
I,
|
|
211
|
-
R,
|
|
212
|
-
>(
|
|
124
|
+
export function schemaBodyJson<A, I, R>(
|
|
213
125
|
fields: Schema.Schema<A, I, R>,
|
|
214
|
-
): <
|
|
215
|
-
D extends Route.RouteDescriptor.Any,
|
|
216
|
-
SB extends {},
|
|
217
|
-
P extends Route.Route.Tuple,
|
|
218
|
-
>(
|
|
126
|
+
): <D extends Route.RouteDescriptor.Any, SB extends {}, P extends Route.Route.Tuple>(
|
|
219
127
|
self: Route.RouteSet.RouteSet<D, SB, P>,
|
|
220
128
|
) => Route.RouteSet.RouteSet<
|
|
221
129
|
D,
|
|
222
130
|
SB,
|
|
223
|
-
[
|
|
224
|
-
...P,
|
|
225
|
-
Route.Route.Route<
|
|
226
|
-
{},
|
|
227
|
-
{ body: A },
|
|
228
|
-
unknown,
|
|
229
|
-
RequestBodyError | ParseResult.ParseError,
|
|
230
|
-
R
|
|
231
|
-
>,
|
|
232
|
-
]
|
|
131
|
+
[...P, Route.Route.Route<{}, { body: A }, unknown, RequestBodyError | ParseResult.ParseError, R>]
|
|
233
132
|
> {
|
|
234
133
|
const decode = Schema.decodeUnknown(fields)
|
|
235
134
|
return RouteHook.filter((ctx: { request: Request; body?: {} }) =>
|
|
236
|
-
Effect.gen(function*() {
|
|
135
|
+
Effect.gen(function* () {
|
|
237
136
|
const json = yield* Effect.tryPromise({
|
|
238
137
|
try: () => ctx.request.json(),
|
|
239
138
|
catch: (error) => RequestBodyError("JsonError", error),
|
|
@@ -247,41 +146,26 @@ export function schemaBodyJson<
|
|
|
247
146
|
},
|
|
248
147
|
},
|
|
249
148
|
}
|
|
250
|
-
})
|
|
149
|
+
}),
|
|
251
150
|
)
|
|
252
151
|
}
|
|
253
152
|
|
|
254
153
|
export function schemaBodyUrlParams<
|
|
255
154
|
A,
|
|
256
|
-
I extends Readonly<
|
|
257
|
-
Record<string, string | ReadonlyArray<string> | undefined>
|
|
258
|
-
>,
|
|
155
|
+
I extends Readonly<Record<string, string | ReadonlyArray<string> | undefined>>,
|
|
259
156
|
R,
|
|
260
157
|
>(
|
|
261
158
|
fields: Schema.Schema<A, I, R>,
|
|
262
|
-
): <
|
|
263
|
-
D extends Route.RouteDescriptor.Any,
|
|
264
|
-
SB extends {},
|
|
265
|
-
P extends Route.Route.Tuple,
|
|
266
|
-
>(
|
|
159
|
+
): <D extends Route.RouteDescriptor.Any, SB extends {}, P extends Route.Route.Tuple>(
|
|
267
160
|
self: Route.RouteSet.RouteSet<D, SB, P>,
|
|
268
161
|
) => Route.RouteSet.RouteSet<
|
|
269
162
|
D,
|
|
270
163
|
SB,
|
|
271
|
-
[
|
|
272
|
-
...P,
|
|
273
|
-
Route.Route.Route<
|
|
274
|
-
{},
|
|
275
|
-
{ body: A },
|
|
276
|
-
unknown,
|
|
277
|
-
RequestBodyError | ParseResult.ParseError,
|
|
278
|
-
R
|
|
279
|
-
>,
|
|
280
|
-
]
|
|
164
|
+
[...P, Route.Route.Route<{}, { body: A }, unknown, RequestBodyError | ParseResult.ParseError, R>]
|
|
281
165
|
> {
|
|
282
166
|
const decode = Schema.decodeUnknown(fields)
|
|
283
167
|
return RouteHook.filter((ctx: { request: Request; body?: {} }) =>
|
|
284
|
-
Effect.gen(function*() {
|
|
168
|
+
Effect.gen(function* () {
|
|
285
169
|
const text = yield* Effect.tryPromise({
|
|
286
170
|
try: () => ctx.request.text(),
|
|
287
171
|
catch: (error) => RequestBodyError("UrlParamsError", error),
|
|
@@ -296,26 +180,17 @@ export function schemaBodyUrlParams<
|
|
|
296
180
|
},
|
|
297
181
|
},
|
|
298
182
|
}
|
|
299
|
-
})
|
|
183
|
+
}),
|
|
300
184
|
)
|
|
301
185
|
}
|
|
302
186
|
|
|
303
187
|
export function schemaBodyMultipart<
|
|
304
188
|
A,
|
|
305
|
-
I extends Partial<
|
|
306
|
-
Record<
|
|
307
|
-
string,
|
|
308
|
-
ReadonlyArray<Http.FilePart> | ReadonlyArray<string> | string
|
|
309
|
-
>
|
|
310
|
-
>,
|
|
189
|
+
I extends Partial<Record<string, ReadonlyArray<Http.FilePart> | ReadonlyArray<string> | string>>,
|
|
311
190
|
R,
|
|
312
191
|
>(
|
|
313
192
|
fields: Schema.Schema<A, I, R>,
|
|
314
|
-
): <
|
|
315
|
-
D extends Route.RouteDescriptor.Any,
|
|
316
|
-
SB extends {},
|
|
317
|
-
P extends Route.Route.Tuple,
|
|
318
|
-
>(
|
|
193
|
+
): <D extends Route.RouteDescriptor.Any, SB extends {}, P extends Route.Route.Tuple>(
|
|
319
194
|
self: Route.RouteSet.RouteSet<D, SB, P>,
|
|
320
195
|
) => Route.RouteSet.RouteSet<
|
|
321
196
|
D,
|
|
@@ -333,7 +208,7 @@ export function schemaBodyMultipart<
|
|
|
333
208
|
> {
|
|
334
209
|
const decode = Schema.decodeUnknown(fields)
|
|
335
210
|
return RouteHook.filter((ctx: { request: Request; body?: {} }) =>
|
|
336
|
-
Effect.gen(function*() {
|
|
211
|
+
Effect.gen(function* () {
|
|
337
212
|
const record = yield* Effect.tryPromise({
|
|
338
213
|
try: () => Http.parseFormData(ctx.request),
|
|
339
214
|
catch: (error) => RequestBodyError("MultipartError", error),
|
|
@@ -347,26 +222,17 @@ export function schemaBodyMultipart<
|
|
|
347
222
|
},
|
|
348
223
|
},
|
|
349
224
|
}
|
|
350
|
-
})
|
|
225
|
+
}),
|
|
351
226
|
)
|
|
352
227
|
}
|
|
353
228
|
|
|
354
229
|
export function schemaBodyForm<
|
|
355
230
|
A,
|
|
356
|
-
I extends Partial<
|
|
357
|
-
Record<
|
|
358
|
-
string,
|
|
359
|
-
ReadonlyArray<Http.FilePart> | ReadonlyArray<string> | string
|
|
360
|
-
>
|
|
361
|
-
>,
|
|
231
|
+
I extends Partial<Record<string, ReadonlyArray<Http.FilePart> | ReadonlyArray<string> | string>>,
|
|
362
232
|
R,
|
|
363
233
|
>(
|
|
364
234
|
fields: Schema.Schema<A, I, R>,
|
|
365
|
-
): <
|
|
366
|
-
D extends Route.RouteDescriptor.Any,
|
|
367
|
-
SB extends {},
|
|
368
|
-
P extends Route.Route.Tuple,
|
|
369
|
-
>(
|
|
235
|
+
): <D extends Route.RouteDescriptor.Any, SB extends {}, P extends Route.Route.Tuple>(
|
|
370
236
|
self: Route.RouteSet.RouteSet<D, SB, P>,
|
|
371
237
|
) => Route.RouteSet.RouteSet<
|
|
372
238
|
D,
|
|
@@ -384,7 +250,7 @@ export function schemaBodyForm<
|
|
|
384
250
|
> {
|
|
385
251
|
const decode = Schema.decodeUnknown(fields)
|
|
386
252
|
return RouteHook.filter((ctx: { request: Request; body?: {} }) =>
|
|
387
|
-
Effect.gen(function*() {
|
|
253
|
+
Effect.gen(function* () {
|
|
388
254
|
const contentType = ctx.request.headers.get("content-type") ?? ""
|
|
389
255
|
|
|
390
256
|
if (contentType.includes("application/x-www-form-urlencoded")) {
|
|
@@ -418,6 +284,6 @@ export function schemaBodyForm<
|
|
|
418
284
|
},
|
|
419
285
|
},
|
|
420
286
|
}
|
|
421
|
-
})
|
|
287
|
+
}),
|
|
422
288
|
)
|
|
423
289
|
}
|
package/src/RouteSse.ts
CHANGED
|
@@ -21,13 +21,10 @@ export type SseTaggedEvent = {
|
|
|
21
21
|
readonly _tag: string
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
export type SseEventInput =
|
|
25
|
-
| SseEvent
|
|
26
|
-
| SseTaggedEvent
|
|
24
|
+
export type SseEventInput = SseEvent | SseTaggedEvent
|
|
27
25
|
|
|
28
26
|
function isTaggedEvent(event: SseEventInput): event is SseTaggedEvent {
|
|
29
|
-
return Object.hasOwn(event, "_tag")
|
|
30
|
-
&& typeof event["_tag"] === "string"
|
|
27
|
+
return Object.hasOwn(event, "_tag") && typeof event["_tag"] === "string"
|
|
31
28
|
}
|
|
32
29
|
|
|
33
30
|
function formatSseEvent(event: SseEventInput): string {
|
|
@@ -59,18 +56,16 @@ export type SseHandlerInput<B, E, R> =
|
|
|
59
56
|
| Stream.Stream<SseEventInput, E, R>
|
|
60
57
|
| Effect.Effect<Stream.Stream<SseEventInput, E, R>, E, R>
|
|
61
58
|
| ((
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
unknown
|
|
73
|
-
>)
|
|
59
|
+
context: Values.Simplify<B>,
|
|
60
|
+
next: (context?: Partial<B> & Record<string, unknown>) => Entity.Entity<string>,
|
|
61
|
+
) =>
|
|
62
|
+
| Stream.Stream<SseEventInput, E, R>
|
|
63
|
+
| Effect.Effect<Stream.Stream<SseEventInput, E, R>, E, R>
|
|
64
|
+
| Generator<
|
|
65
|
+
Utils.YieldWrap<Effect.Effect<unknown, E, R>>,
|
|
66
|
+
Stream.Stream<SseEventInput, E, R>,
|
|
67
|
+
unknown
|
|
68
|
+
>)
|
|
74
69
|
|
|
75
70
|
export function sse<
|
|
76
71
|
D extends Route.RouteDescriptor.Any,
|
|
@@ -78,40 +73,24 @@ export function sse<
|
|
|
78
73
|
I extends Route.Route.Tuple,
|
|
79
74
|
E = never,
|
|
80
75
|
R = never,
|
|
81
|
-
>(
|
|
82
|
-
|
|
83
|
-
NoInfer<D & B & Route.ExtractBindings<I> & { format: "text" }>,
|
|
84
|
-
E,
|
|
85
|
-
R
|
|
86
|
-
>,
|
|
87
|
-
) {
|
|
88
|
-
return function(
|
|
89
|
-
self: Route.RouteSet.RouteSet<D, B, I>,
|
|
90
|
-
) {
|
|
76
|
+
>(handler: SseHandlerInput<NoInfer<D & B & Route.ExtractBindings<I> & { format: "text" }>, E, R>) {
|
|
77
|
+
return function (self: Route.RouteSet.RouteSet<D, B, I>) {
|
|
91
78
|
const sseHandler: Route.Route.Handler<
|
|
92
79
|
D & B & Route.ExtractBindings<I> & { format: "text" },
|
|
93
80
|
Stream.Stream<string, E, R>,
|
|
94
81
|
E,
|
|
95
82
|
R
|
|
96
83
|
> = (ctx, _next) => {
|
|
97
|
-
const getStream = (): Effect.Effect<
|
|
98
|
-
Stream.Stream<SseEventInput, E, R>,
|
|
99
|
-
E,
|
|
100
|
-
R
|
|
101
|
-
> => {
|
|
84
|
+
const getStream = (): Effect.Effect<Stream.Stream<SseEventInput, E, R>, E, R> => {
|
|
102
85
|
if (typeof handler === "function") {
|
|
103
86
|
const result = (handler as Function)(ctx, _next)
|
|
104
87
|
if (StreamExtra.isStream(result)) {
|
|
105
88
|
return Effect.succeed(result as Stream.Stream<SseEventInput, E, R>)
|
|
106
89
|
}
|
|
107
90
|
if (Effect.isEffect(result)) {
|
|
108
|
-
return result as Effect.Effect<
|
|
109
|
-
Stream.Stream<SseEventInput, E, R>,
|
|
110
|
-
E,
|
|
111
|
-
R
|
|
112
|
-
>
|
|
91
|
+
return result as Effect.Effect<Stream.Stream<SseEventInput, E, R>, E, R>
|
|
113
92
|
}
|
|
114
|
-
return Effect.gen(function*() {
|
|
93
|
+
return Effect.gen(function* () {
|
|
115
94
|
return yield* result
|
|
116
95
|
}) as Effect.Effect<Stream.Stream<SseEventInput, E, R>, E, R>
|
|
117
96
|
}
|
|
@@ -119,23 +98,17 @@ export function sse<
|
|
|
119
98
|
return Effect.succeed(handler as Stream.Stream<SseEventInput, E, R>)
|
|
120
99
|
}
|
|
121
100
|
if (Effect.isEffect(handler)) {
|
|
122
|
-
return handler as Effect.Effect<
|
|
123
|
-
Stream.Stream<SseEventInput, E, R>,
|
|
124
|
-
E,
|
|
125
|
-
R
|
|
126
|
-
>
|
|
101
|
+
return handler as Effect.Effect<Stream.Stream<SseEventInput, E, R>, E, R>
|
|
127
102
|
}
|
|
128
103
|
return Effect.succeed(Stream.empty)
|
|
129
104
|
}
|
|
130
105
|
|
|
131
106
|
return Effect.map(getStream(), (eventStream) => {
|
|
132
107
|
const formattedStream = Stream.map(eventStream, formatSseEvent)
|
|
133
|
-
const heartbeat = Stream
|
|
134
|
-
.
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
)
|
|
138
|
-
.pipe(Stream.drop(1))
|
|
108
|
+
const heartbeat = Stream.repeat(
|
|
109
|
+
Stream.succeed(HEARTBEAT),
|
|
110
|
+
Schedule.spaced(HEARTBEAT_INTERVAL),
|
|
111
|
+
).pipe(Stream.drop(1))
|
|
139
112
|
const merged = Stream.merge(formattedStream, heartbeat, {
|
|
140
113
|
haltStrategy: "left",
|
|
141
114
|
})
|
|
@@ -143,53 +116,26 @@ export function sse<
|
|
|
143
116
|
headers: {
|
|
144
117
|
"content-type": "text/event-stream",
|
|
145
118
|
"cache-control": "no-cache",
|
|
146
|
-
|
|
119
|
+
connection: "keep-alive",
|
|
147
120
|
},
|
|
148
121
|
})
|
|
149
122
|
})
|
|
150
123
|
}
|
|
151
124
|
|
|
152
|
-
const route = Route.make<
|
|
153
|
-
{ format: "text" },
|
|
154
|
-
{},
|
|
155
|
-
Stream.Stream<string, E, R>,
|
|
156
|
-
E,
|
|
157
|
-
R
|
|
158
|
-
>(
|
|
125
|
+
const route = Route.make<{ format: "text" }, {}, Stream.Stream<string, E, R>, E, R>(
|
|
159
126
|
sseHandler as any,
|
|
160
127
|
{ format: "text" },
|
|
161
128
|
)
|
|
162
129
|
|
|
163
130
|
const items: [
|
|
164
131
|
...I,
|
|
165
|
-
Route.Route.Route<
|
|
166
|
-
|
|
167
|
-
{},
|
|
168
|
-
Stream.Stream<string, E, R>,
|
|
169
|
-
E,
|
|
170
|
-
R
|
|
171
|
-
>,
|
|
172
|
-
] = [
|
|
173
|
-
...Route.items(self),
|
|
174
|
-
route,
|
|
175
|
-
]
|
|
132
|
+
Route.Route.Route<{ format: "text" }, {}, Stream.Stream<string, E, R>, E, R>,
|
|
133
|
+
] = [...Route.items(self), route]
|
|
176
134
|
|
|
177
135
|
return Route.set<
|
|
178
136
|
D,
|
|
179
137
|
B,
|
|
180
|
-
[
|
|
181
|
-
|
|
182
|
-
Route.Route.Route<
|
|
183
|
-
{ format: "text" },
|
|
184
|
-
{},
|
|
185
|
-
Stream.Stream<string, E, R>,
|
|
186
|
-
E,
|
|
187
|
-
R
|
|
188
|
-
>,
|
|
189
|
-
]
|
|
190
|
-
>(
|
|
191
|
-
items,
|
|
192
|
-
Route.descriptor(self),
|
|
193
|
-
)
|
|
138
|
+
[...I, Route.Route.Route<{ format: "text" }, {}, Stream.Stream<string, E, R>, E, R>]
|
|
139
|
+
>(items, Route.descriptor(self))
|
|
194
140
|
}
|
|
195
141
|
}
|