@effect/platform 0.11.5 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/FileSystem.d.ts +43 -11
- package/FileSystem.d.ts.map +1 -1
- package/FileSystem.js +33 -3
- package/FileSystem.js.map +1 -1
- package/Http/App.d.ts +18 -0
- package/Http/App.d.ts.map +1 -0
- package/Http/App.js +6 -0
- package/Http/App.js.map +1 -0
- package/Http/Body.d.ts +37 -14
- package/Http/Body.d.ts.map +1 -1
- package/Http/Body.js +17 -5
- package/Http/Body.js.map +1 -1
- package/Http/Client.d.ts +2 -2
- package/Http/Client.d.ts.map +1 -1
- package/Http/Client.js +3 -3
- package/Http/Client.js.map +1 -1
- package/Http/ClientRequest.d.ts +44 -1
- package/Http/ClientRequest.d.ts.map +1 -1
- package/Http/ClientRequest.js +21 -3
- package/Http/ClientRequest.js.map +1 -1
- package/Http/ClientResponse.d.ts +13 -1
- package/Http/ClientResponse.d.ts.map +1 -1
- package/Http/ClientResponse.js +14 -2
- package/Http/ClientResponse.js.map +1 -1
- package/Http/FormData.d.ts +97 -4
- package/Http/FormData.d.ts.map +1 -1
- package/Http/FormData.js +77 -2
- package/Http/FormData.js.map +1 -1
- package/Http/Headers.d.ts +29 -3
- package/Http/Headers.d.ts.map +1 -1
- package/Http/Headers.js +13 -1
- package/Http/Headers.js.map +1 -1
- package/Http/IncomingMessage.d.ts +26 -5
- package/Http/IncomingMessage.d.ts.map +1 -1
- package/Http/IncomingMessage.js +38 -3
- package/Http/IncomingMessage.js.map +1 -1
- package/Http/Middleware.d.ts +56 -0
- package/Http/Middleware.d.ts.map +1 -0
- package/Http/Middleware.js +46 -0
- package/Http/Middleware.js.map +1 -0
- package/Http/Router.d.ts +221 -0
- package/Http/Router.d.ts.map +1 -0
- package/Http/Router.js +148 -0
- package/Http/Router.js.map +1 -0
- package/Http/Server.d.ts +85 -0
- package/Http/Server.d.ts.map +1 -0
- package/Http/Server.js +34 -0
- package/Http/Server.js.map +1 -0
- package/Http/ServerError.d.ts +96 -0
- package/Http/ServerError.d.ts.map +1 -0
- package/Http/ServerError.js +40 -0
- package/Http/ServerError.js.map +1 -0
- package/Http/ServerRequest.d.ts +82 -0
- package/Http/ServerRequest.d.ts.map +1 -0
- package/Http/ServerRequest.js +66 -0
- package/Http/ServerRequest.js.map +1 -0
- package/Http/ServerResponse.d.ts +168 -0
- package/Http/ServerResponse.d.ts.map +1 -0
- package/Http/ServerResponse.js +116 -0
- package/Http/ServerResponse.js.map +1 -0
- package/Http/UrlParams.d.ts +20 -5
- package/Http/UrlParams.d.ts.map +1 -1
- package/Http/UrlParams.js.map +1 -1
- package/HttpServer.d.ts +44 -0
- package/HttpServer.d.ts.map +1 -0
- package/HttpServer.js +29 -0
- package/HttpServer.js.map +1 -0
- package/internal/fileSystem.js +33 -12
- package/internal/fileSystem.js.map +1 -1
- package/internal/http/body.js +28 -28
- package/internal/http/body.js.map +1 -1
- package/internal/http/client.d.ts.map +1 -1
- package/internal/http/client.js +32 -26
- package/internal/http/client.js.map +1 -1
- package/internal/http/clientRequest.js +22 -6
- package/internal/http/clientRequest.js.map +1 -1
- package/internal/http/clientResponse.js +15 -12
- package/internal/http/clientResponse.js.map +1 -1
- package/internal/http/formData.d.ts +8 -0
- package/internal/http/formData.d.ts.map +1 -0
- package/internal/http/formData.js +88 -0
- package/internal/http/formData.js.map +1 -0
- package/internal/http/middleware.d.ts +2 -0
- package/internal/http/middleware.d.ts.map +1 -0
- package/internal/http/middleware.js +43 -0
- package/internal/http/middleware.js.map +1 -0
- package/internal/http/router.d.ts +2 -0
- package/internal/http/router.d.ts.map +1 -0
- package/internal/http/router.js +187 -0
- package/internal/http/router.js.map +1 -0
- package/internal/http/server.d.ts +2 -0
- package/internal/http/server.d.ts.map +1 -0
- package/internal/http/server.js +30 -0
- package/internal/http/server.js.map +1 -0
- package/internal/http/serverError.d.ts +2 -0
- package/internal/http/serverError.d.ts.map +1 -0
- package/internal/http/serverError.js +30 -0
- package/internal/http/serverError.js.map +1 -0
- package/internal/http/serverRequest.d.ts +2 -0
- package/internal/http/serverRequest.d.ts.map +1 -0
- package/internal/http/serverRequest.js +57 -0
- package/internal/http/serverRequest.js.map +1 -0
- package/internal/http/serverResponse.d.ts +2 -0
- package/internal/http/serverResponse.d.ts.map +1 -0
- package/internal/http/serverResponse.js +109 -0
- package/internal/http/serverResponse.js.map +1 -0
- package/mjs/FileSystem.mjs +26 -1
- package/mjs/FileSystem.mjs.map +1 -1
- package/mjs/Http/App.mjs +2 -0
- package/mjs/Http/App.mjs.map +1 -0
- package/mjs/Http/Body.mjs +12 -2
- package/mjs/Http/Body.mjs.map +1 -1
- package/mjs/Http/Client.mjs +1 -1
- package/mjs/Http/Client.mjs.map +1 -1
- package/mjs/Http/ClientRequest.mjs +16 -1
- package/mjs/Http/ClientRequest.mjs.map +1 -1
- package/mjs/Http/ClientResponse.mjs +11 -1
- package/mjs/Http/ClientResponse.mjs.map +1 -1
- package/mjs/Http/FormData.mjs +62 -1
- package/mjs/Http/FormData.mjs.map +1 -1
- package/mjs/Http/Headers.mjs +10 -0
- package/mjs/Http/Headers.mjs.map +1 -1
- package/mjs/Http/IncomingMessage.mjs +32 -1
- package/mjs/Http/IncomingMessage.mjs.map +1 -1
- package/mjs/Http/Middleware.mjs +32 -0
- package/mjs/Http/Middleware.mjs.map +1 -0
- package/mjs/Http/Router.mjs +117 -0
- package/mjs/Http/Router.mjs.map +1 -0
- package/mjs/Http/Server.mjs +22 -0
- package/mjs/Http/Server.mjs.map +1 -0
- package/mjs/Http/ServerError.mjs +27 -0
- package/mjs/Http/ServerError.mjs.map +1 -0
- package/mjs/Http/ServerRequest.mjs +48 -0
- package/mjs/Http/ServerRequest.mjs.map +1 -0
- package/mjs/Http/ServerResponse.mjs +90 -0
- package/mjs/Http/ServerResponse.mjs.map +1 -0
- package/mjs/Http/UrlParams.mjs.map +1 -1
- package/mjs/HttpServer.mjs +24 -0
- package/mjs/HttpServer.mjs.map +1 -0
- package/mjs/internal/fileSystem.mjs +27 -11
- package/mjs/internal/fileSystem.mjs.map +1 -1
- package/mjs/internal/http/body.mjs +23 -25
- package/mjs/internal/http/body.mjs.map +1 -1
- package/mjs/internal/http/client.mjs +30 -24
- package/mjs/internal/http/client.mjs.map +1 -1
- package/mjs/internal/http/clientRequest.mjs +16 -4
- package/mjs/internal/http/clientRequest.mjs.map +1 -1
- package/mjs/internal/http/clientResponse.mjs +15 -12
- package/mjs/internal/http/clientResponse.mjs.map +1 -1
- package/mjs/internal/http/formData.mjs +67 -0
- package/mjs/internal/http/formData.mjs.map +1 -0
- package/mjs/internal/http/middleware.mjs +29 -0
- package/mjs/internal/http/middleware.mjs.map +1 -0
- package/mjs/internal/http/router.mjs +155 -0
- package/mjs/internal/http/router.mjs.map +1 -0
- package/mjs/internal/http/server.mjs +17 -0
- package/mjs/internal/http/server.mjs.map +1 -0
- package/mjs/internal/http/serverError.mjs +17 -0
- package/mjs/internal/http/serverError.mjs.map +1 -0
- package/mjs/internal/http/serverRequest.mjs +41 -0
- package/mjs/internal/http/serverRequest.mjs.map +1 -0
- package/mjs/internal/http/serverResponse.mjs +82 -0
- package/mjs/internal/http/serverResponse.mjs.map +1 -0
- package/package.json +2 -1
- package/src/FileSystem.ts +52 -27
- package/src/Http/App.ts +19 -0
- package/src/Http/Body.ts +41 -14
- package/src/Http/Client.ts +6 -3
- package/src/Http/ClientRequest.ts +52 -2
- package/src/Http/ClientResponse.ts +13 -1
- package/src/Http/FormData.ts +121 -5
- package/src/Http/Headers.ts +37 -3
- package/src/Http/IncomingMessage.ts +46 -3
- package/src/Http/Middleware.ts +69 -0
- package/src/Http/Router.ts +342 -0
- package/src/Http/Server.ts +134 -0
- package/src/Http/ServerError.ts +111 -0
- package/src/Http/ServerRequest.ts +120 -0
- package/src/Http/ServerResponse.ts +202 -0
- package/src/Http/UrlParams.ts +20 -5
- package/src/HttpServer.ts +44 -0
- package/src/internal/fileSystem.ts +28 -7
- package/src/internal/http/body.ts +65 -39
- package/src/internal/http/client.ts +45 -36
- package/src/internal/http/clientRequest.ts +64 -4
- package/src/internal/http/clientResponse.ts +21 -13
- package/src/internal/http/formData.ts +140 -0
- package/src/internal/http/middleware.ts +72 -0
- package/src/internal/http/router.ts +298 -0
- package/src/internal/http/server.ts +80 -0
- package/src/internal/http/serverError.ts +26 -0
- package/src/internal/http/serverRequest.ts +71 -0
- package/src/internal/http/serverResponse.ts +255 -0
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
import * as Chunk from "@effect/data/Chunk"
|
|
2
|
+
import * as Context from "@effect/data/Context"
|
|
3
|
+
import * as Equal from "@effect/data/Equal"
|
|
4
|
+
import { dual } from "@effect/data/Function"
|
|
5
|
+
import * as Hash from "@effect/data/Hash"
|
|
6
|
+
import * as Option from "@effect/data/Option"
|
|
7
|
+
import { pipeArguments } from "@effect/data/Pipeable"
|
|
8
|
+
import * as Effect from "@effect/io/Effect"
|
|
9
|
+
import type * as App from "@effect/platform/Http/App"
|
|
10
|
+
import type * as Method from "@effect/platform/Http/Method"
|
|
11
|
+
import type * as Router from "@effect/platform/Http/Router"
|
|
12
|
+
import * as Error from "@effect/platform/Http/ServerError"
|
|
13
|
+
import * as ServerRequest from "@effect/platform/Http/ServerRequest"
|
|
14
|
+
import * as Schema from "@effect/schema/Schema"
|
|
15
|
+
import * as Channel from "@effect/stream/Channel"
|
|
16
|
+
import * as Sink from "@effect/stream/Sink"
|
|
17
|
+
import * as Stream from "@effect/stream/Stream"
|
|
18
|
+
import type { HTTPMethod } from "find-my-way"
|
|
19
|
+
import FindMyWay from "find-my-way"
|
|
20
|
+
|
|
21
|
+
/** @internal */
|
|
22
|
+
export const TypeId: Router.TypeId = Symbol.for("@effect/platform/Http/Router") as Router.TypeId
|
|
23
|
+
|
|
24
|
+
/** @internal */
|
|
25
|
+
export const RouteTypeId: Router.RouteTypeId = Symbol.for("@effect/platform/Http/Router/Route") as Router.RouteTypeId
|
|
26
|
+
|
|
27
|
+
/** @internal */
|
|
28
|
+
export const RouteContextTypeId: Router.RouteContextTypeId = Symbol.for(
|
|
29
|
+
"@effect/platform/Http/Router/RouteContext"
|
|
30
|
+
) as Router.RouteContextTypeId
|
|
31
|
+
|
|
32
|
+
/** @internal */
|
|
33
|
+
export const RouteContext = Context.Tag<Router.RouteContext>("@effect/platform/Http/Router/RouteContext")
|
|
34
|
+
|
|
35
|
+
/** @internal */
|
|
36
|
+
export const params = Effect.map(RouteContext, (_) => _.params)
|
|
37
|
+
|
|
38
|
+
/** @internal */
|
|
39
|
+
export const searchParams = Effect.map(RouteContext, (_) => _.searchParams)
|
|
40
|
+
|
|
41
|
+
/** @internal */
|
|
42
|
+
export const schemaParams = <I extends Readonly<Record<string, string>>, A>(schema: Schema.Schema<I, A>) => {
|
|
43
|
+
const parse = Schema.parse(schema)
|
|
44
|
+
return Effect.flatMap(
|
|
45
|
+
RouteContext,
|
|
46
|
+
(_) =>
|
|
47
|
+
parse({
|
|
48
|
+
..._.searchParams,
|
|
49
|
+
..._.params
|
|
50
|
+
})
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
class RouterImpl<R, E> implements Router.Router<R, E> {
|
|
55
|
+
readonly [TypeId]: Router.TypeId
|
|
56
|
+
constructor(
|
|
57
|
+
readonly routes: Chunk.Chunk<Router.Route<R, E>>,
|
|
58
|
+
readonly mounts: Chunk.Chunk<readonly [string, App.Default<R, E>]>
|
|
59
|
+
) {
|
|
60
|
+
this[TypeId] = TypeId
|
|
61
|
+
this[Effect.EffectTypeId] = undefined
|
|
62
|
+
this[Stream.StreamTypeId] = undefined
|
|
63
|
+
this[Sink.SinkTypeId] = undefined
|
|
64
|
+
this[Channel.ChannelTypeId] = undefined
|
|
65
|
+
}
|
|
66
|
+
pipe() {
|
|
67
|
+
return pipeArguments(this, arguments)
|
|
68
|
+
}
|
|
69
|
+
private httpApp: App.Default<Exclude<R, Router.RouteContext>, E | Error.RouteNotFound> | undefined
|
|
70
|
+
commit() {
|
|
71
|
+
if (this.httpApp === undefined) {
|
|
72
|
+
this.httpApp = toHttpApp(this)
|
|
73
|
+
}
|
|
74
|
+
return this.httpApp
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// implements HttpApp/Effect
|
|
78
|
+
public _tag = "Commit" // OP_COMMIT
|
|
79
|
+
readonly [Effect.EffectTypeId]: any
|
|
80
|
+
readonly [Stream.StreamTypeId]: any
|
|
81
|
+
readonly [Sink.SinkTypeId]: any
|
|
82
|
+
readonly [Channel.ChannelTypeId]: any;
|
|
83
|
+
[Equal.symbol](
|
|
84
|
+
this: RouterImpl<R, E>,
|
|
85
|
+
that: RouterImpl<R, E>
|
|
86
|
+
): boolean {
|
|
87
|
+
return this === that
|
|
88
|
+
}
|
|
89
|
+
[Hash.symbol](this: RouterImpl<R, E>): number {
|
|
90
|
+
return Hash.random(this)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const toHttpApp = <R, E>(
|
|
95
|
+
self: Router.Router<R, E>
|
|
96
|
+
): App.Default<Exclude<R, Router.RouteContext>, E | Error.RouteNotFound> => {
|
|
97
|
+
const router = FindMyWay()
|
|
98
|
+
Chunk.forEach(self.mounts, ([path, app]) => {
|
|
99
|
+
const fn = () => {}
|
|
100
|
+
fn.handler = Effect.updateService(app, ServerRequest.ServerRequest, (request) => sliceRequestUrl(request, path))
|
|
101
|
+
router.all(path, fn)
|
|
102
|
+
router.all(path + "/*", fn)
|
|
103
|
+
})
|
|
104
|
+
Chunk.forEach(self.routes, (route) => {
|
|
105
|
+
const fn = () => {}
|
|
106
|
+
fn.handler = route
|
|
107
|
+
if (route.method === "*") {
|
|
108
|
+
router.all(route.path, fn)
|
|
109
|
+
} else {
|
|
110
|
+
router.on(route.method, route.path, fn)
|
|
111
|
+
}
|
|
112
|
+
})
|
|
113
|
+
return Effect.flatMap(
|
|
114
|
+
ServerRequest.ServerRequest,
|
|
115
|
+
(request): App.Default<Exclude<R, Router.RouteContext>, E | Error.RouteNotFound> => {
|
|
116
|
+
const result = router.find(request.method as HTTPMethod, request.url)
|
|
117
|
+
if (result === null) {
|
|
118
|
+
return Effect.fail(Error.RouteNotFound({ request }))
|
|
119
|
+
}
|
|
120
|
+
const handler = (result.handler as any).handler
|
|
121
|
+
if (RouteTypeId in handler) {
|
|
122
|
+
const route = handler as Router.Route<R, E>
|
|
123
|
+
if (route.prefix._tag === "Some") {
|
|
124
|
+
request = sliceRequestUrl(request, route.prefix.value)
|
|
125
|
+
}
|
|
126
|
+
return Effect.mapInputContext(
|
|
127
|
+
route.handler,
|
|
128
|
+
(context) =>
|
|
129
|
+
Context.add(
|
|
130
|
+
Context.add(context, ServerRequest.ServerRequest, request),
|
|
131
|
+
RouteContext,
|
|
132
|
+
new RouteContextImpl(result.params, result.searchParams)
|
|
133
|
+
) as Context.Context<R>
|
|
134
|
+
)
|
|
135
|
+
}
|
|
136
|
+
return (handler as App.Default<Exclude<R, Router.RouteContext>, E>)
|
|
137
|
+
}
|
|
138
|
+
)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function sliceRequestUrl(request: ServerRequest.ServerRequest, prefix: string) {
|
|
142
|
+
const prefexLen = prefix.length
|
|
143
|
+
return request.setUrl(request.url.length <= prefexLen ? "/" : request.url.slice(prefexLen))
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
class RouteImpl<R, E> implements Router.Route<R, E> {
|
|
147
|
+
readonly [RouteTypeId]: Router.RouteTypeId
|
|
148
|
+
constructor(
|
|
149
|
+
readonly method: Method.Method | "*",
|
|
150
|
+
readonly path: string,
|
|
151
|
+
readonly handler: Router.Route.Handler<R, E>,
|
|
152
|
+
readonly prefix = Option.none<string>()
|
|
153
|
+
) {
|
|
154
|
+
this[RouteTypeId] = RouteTypeId
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
class RouteContextImpl implements Router.RouteContext {
|
|
159
|
+
readonly [RouteContextTypeId]: Router.RouteContextTypeId
|
|
160
|
+
constructor(
|
|
161
|
+
readonly params: Readonly<Record<string, string | undefined>>,
|
|
162
|
+
readonly searchParams: Readonly<Record<string, string>>
|
|
163
|
+
) {
|
|
164
|
+
this[RouteContextTypeId] = RouteContextTypeId
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/** @internal */
|
|
169
|
+
export const empty: Router.Router<never, never> = new RouterImpl(Chunk.empty(), Chunk.empty())
|
|
170
|
+
|
|
171
|
+
/** @internal */
|
|
172
|
+
export const fromIterable = <R, E>(
|
|
173
|
+
routes: Iterable<Router.Route<R, E>>
|
|
174
|
+
): Router.Router<R, E> => new RouterImpl(Chunk.fromIterable(routes), Chunk.empty())
|
|
175
|
+
|
|
176
|
+
/** @internal */
|
|
177
|
+
export const makeRoute = <R, E>(
|
|
178
|
+
method: Method.Method,
|
|
179
|
+
path: string,
|
|
180
|
+
handler: Router.Route.Handler<R, E>,
|
|
181
|
+
prefix: Option.Option<string> = Option.none()
|
|
182
|
+
): Router.Route<R, E> => new RouteImpl(method, path, handler, prefix)
|
|
183
|
+
|
|
184
|
+
/** @internal */
|
|
185
|
+
export const concat = dual<
|
|
186
|
+
<R1, E1>(that: Router.Router<R1, E1>) => <R, E>(self: Router.Router<R, E>) => Router.Router<R | R1, E | E1>,
|
|
187
|
+
<R, E, R1, E1>(self: Router.Router<R, E>, that: Router.Router<R1, E1>) => Router.Router<R | R1, E | E1>
|
|
188
|
+
>(2, (self, that) => new RouterImpl(Chunk.appendAll(self.routes, that.routes) as any, self.mounts))
|
|
189
|
+
|
|
190
|
+
const removeTrailingSlash = (path: string) => (path.endsWith("/") ? path.slice(0, -1) : path)
|
|
191
|
+
|
|
192
|
+
/** @internal */
|
|
193
|
+
export const prefixAll = dual<
|
|
194
|
+
(prefix: string) => <R, E>(self: Router.Router<R, E>) => Router.Router<R, E>,
|
|
195
|
+
<R, E>(self: Router.Router<R, E>, prefix: string) => Router.Router<R, E>
|
|
196
|
+
>(
|
|
197
|
+
2,
|
|
198
|
+
(self, prefix) => {
|
|
199
|
+
prefix = removeTrailingSlash(prefix)
|
|
200
|
+
return new RouterImpl(
|
|
201
|
+
Chunk.map(self.routes, (route) =>
|
|
202
|
+
new RouteImpl(
|
|
203
|
+
route.method,
|
|
204
|
+
route.path === "/" ? prefix : prefix + route.path,
|
|
205
|
+
route.handler,
|
|
206
|
+
Option.orElse(
|
|
207
|
+
Option.map(route.prefix, (_) => prefix + _),
|
|
208
|
+
() => Option.some(prefix)
|
|
209
|
+
)
|
|
210
|
+
)),
|
|
211
|
+
Chunk.map(self.mounts, ([path, app]) => [path === "/" ? prefix : prefix + path, app])
|
|
212
|
+
)
|
|
213
|
+
}
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
/** @internal */
|
|
217
|
+
export const mount = dual<
|
|
218
|
+
<R1, E1>(
|
|
219
|
+
path: string,
|
|
220
|
+
that: Router.Router<R1, E1>
|
|
221
|
+
) => <R, E>(self: Router.Router<R, E>) => Router.Router<R | R1, E | E1>,
|
|
222
|
+
<R, E, R1, E1>(
|
|
223
|
+
self: Router.Router<R, E>,
|
|
224
|
+
path: string,
|
|
225
|
+
that: Router.Router<R1, E1>
|
|
226
|
+
) => Router.Router<R | R1, E | E1>
|
|
227
|
+
>(
|
|
228
|
+
3,
|
|
229
|
+
(self, path, that) => concat(self, prefixAll(that, path))
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
/** @internal */
|
|
233
|
+
export const mountApp = dual<
|
|
234
|
+
<R1, E1>(
|
|
235
|
+
path: string,
|
|
236
|
+
that: App.Default<R1, E1>
|
|
237
|
+
) => <R, E>(self: Router.Router<R, E>) => Router.Router<R | R1, E | E1>,
|
|
238
|
+
<R, E, R1, E1>(
|
|
239
|
+
self: Router.Router<R, E>,
|
|
240
|
+
path: string,
|
|
241
|
+
that: App.Default<R1, E1>
|
|
242
|
+
) => Router.Router<R | R1, E | E1>
|
|
243
|
+
>(
|
|
244
|
+
3,
|
|
245
|
+
(self, path, that) => new RouterImpl(self.routes, Chunk.append(self.mounts, [removeTrailingSlash(path), that]) as any)
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
/** @internal */
|
|
249
|
+
export const route = (method: Method.Method | "*"): {
|
|
250
|
+
<R1, E1>(
|
|
251
|
+
path: string,
|
|
252
|
+
handler: Router.Route.Handler<R1, E1>
|
|
253
|
+
): <R, E>(self: Router.Router<R, E>) => Router.Router<R | Exclude<R1, Router.RouteContext>, E1 | E>
|
|
254
|
+
<R, E, R1, E1>(
|
|
255
|
+
self: Router.Router<R, E>,
|
|
256
|
+
path: string,
|
|
257
|
+
handler: Router.Route.Handler<R1, E1>
|
|
258
|
+
): Router.Router<R | Exclude<R1, Router.RouteContext>, E | E1>
|
|
259
|
+
} =>
|
|
260
|
+
dual<
|
|
261
|
+
<R1, E1>(
|
|
262
|
+
path: string,
|
|
263
|
+
handler: Router.Route.Handler<R1, E1>
|
|
264
|
+
) => <R, E>(self: Router.Router<R, E>) => Router.Router<R | Exclude<R1, Router.RouteContext>, E | E1>,
|
|
265
|
+
<R, E, R1, E1>(
|
|
266
|
+
self: Router.Router<R, E>,
|
|
267
|
+
path: string,
|
|
268
|
+
handler: Router.Route.Handler<R1, E1>
|
|
269
|
+
) => Router.Router<R | Exclude<R1, Router.RouteContext>, E | E1>
|
|
270
|
+
>(3, (self, path, handler) =>
|
|
271
|
+
new RouterImpl(
|
|
272
|
+
Chunk.append(self.routes, new RouteImpl(method, path, handler)) as any,
|
|
273
|
+
self.mounts
|
|
274
|
+
))
|
|
275
|
+
|
|
276
|
+
/** @internal */
|
|
277
|
+
export const all = route("*")
|
|
278
|
+
|
|
279
|
+
/** @internal */
|
|
280
|
+
export const get = route("GET")
|
|
281
|
+
|
|
282
|
+
/** @internal */
|
|
283
|
+
export const post = route("POST")
|
|
284
|
+
|
|
285
|
+
/** @internal */
|
|
286
|
+
export const put = route("PUT")
|
|
287
|
+
|
|
288
|
+
/** @internal */
|
|
289
|
+
export const patch = route("PATCH")
|
|
290
|
+
|
|
291
|
+
/** @internal */
|
|
292
|
+
export const del = route("DELETE")
|
|
293
|
+
|
|
294
|
+
/** @internal */
|
|
295
|
+
export const head = route("HEAD")
|
|
296
|
+
|
|
297
|
+
/** @internal */
|
|
298
|
+
export const options = route("OPTIONS")
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import * as Context from "@effect/data/Context"
|
|
2
|
+
import { dual } from "@effect/data/Function"
|
|
3
|
+
import * as Effect from "@effect/io/Effect"
|
|
4
|
+
import type * as Scope from "@effect/io/Scope"
|
|
5
|
+
import type * as App from "@effect/platform/Http/App"
|
|
6
|
+
import type * as Middleware from "@effect/platform/Http/Middleware"
|
|
7
|
+
import type * as Server from "@effect/platform/Http/Server"
|
|
8
|
+
import type * as Error from "@effect/platform/Http/ServerError"
|
|
9
|
+
import type * as ServerRequest from "@effect/platform/Http/ServerRequest"
|
|
10
|
+
|
|
11
|
+
/** @internal */
|
|
12
|
+
export const TypeId: Server.TypeId = Symbol.for("@effect/platform/Http/Server") as Server.TypeId
|
|
13
|
+
|
|
14
|
+
/** @internal */
|
|
15
|
+
export const serverTag = Context.Tag<Server.Server>("@effect/platform/Http/Server")
|
|
16
|
+
|
|
17
|
+
const serverProto = {
|
|
18
|
+
[TypeId]: TypeId
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** @internal */
|
|
22
|
+
export const isServer = (u: unknown): u is Server.Server => typeof u === "object" && u !== null && TypeId in u
|
|
23
|
+
|
|
24
|
+
/** @internal */
|
|
25
|
+
export const make = (
|
|
26
|
+
options: {
|
|
27
|
+
readonly serve: (
|
|
28
|
+
httpApp: App.Default<never, unknown>,
|
|
29
|
+
middleware?: Middleware.Middleware
|
|
30
|
+
) => Effect.Effect<Scope.Scope, Error.ServeError, never>
|
|
31
|
+
readonly address: Server.Address
|
|
32
|
+
}
|
|
33
|
+
): Server.Server => Object.assign(Object.create(serverProto), options)
|
|
34
|
+
|
|
35
|
+
/** @internal */
|
|
36
|
+
export const serve = dual<
|
|
37
|
+
{
|
|
38
|
+
(): <R, E>(
|
|
39
|
+
httpApp: App.Default<R, E>
|
|
40
|
+
) => Effect.Effect<
|
|
41
|
+
Server.Server | Scope.Scope | Exclude<R, ServerRequest.ServerRequest>,
|
|
42
|
+
Error.ServeError,
|
|
43
|
+
never
|
|
44
|
+
>
|
|
45
|
+
<R, E, App extends App.Default<any, any>>(middleware: Middleware.Middleware.Applied<R, E, App>): (
|
|
46
|
+
httpApp: App.Default<R, E>
|
|
47
|
+
) => Effect.Effect<
|
|
48
|
+
Server.Server | Scope.Scope | Exclude<Effect.Effect.Context<App>, ServerRequest.ServerRequest>,
|
|
49
|
+
Error.ServeError,
|
|
50
|
+
never
|
|
51
|
+
>
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
<R, E>(
|
|
55
|
+
httpApp: App.Default<R, E>
|
|
56
|
+
): Effect.Effect<Server.Server | Scope.Scope | Exclude<R, ServerRequest.ServerRequest>, Error.ServeError, never>
|
|
57
|
+
<R, E, App extends App.Default<any, any>>(
|
|
58
|
+
httpApp: App.Default<R, E>,
|
|
59
|
+
middleware: Middleware.Middleware.Applied<R, E, App>
|
|
60
|
+
): Effect.Effect<
|
|
61
|
+
Server.Server | Exclude<Effect.Effect.Context<App>, ServerRequest.ServerRequest> | Scope.Scope,
|
|
62
|
+
Error.ServeError,
|
|
63
|
+
never
|
|
64
|
+
>
|
|
65
|
+
}
|
|
66
|
+
>(
|
|
67
|
+
(args) => Effect.isEffect(args[0]),
|
|
68
|
+
(<R, E, App extends App.Default<any, any>>(
|
|
69
|
+
httpApp: App.Default<R, E>,
|
|
70
|
+
middleware: Middleware.Middleware.Applied<R, E, App>
|
|
71
|
+
): Effect.Effect<
|
|
72
|
+
Server.Server | Exclude<Effect.Effect.Context<App>, ServerRequest.ServerRequest> | Scope.Scope,
|
|
73
|
+
Error.ServeError,
|
|
74
|
+
never
|
|
75
|
+
> =>
|
|
76
|
+
Effect.flatMap(
|
|
77
|
+
serverTag,
|
|
78
|
+
(server) => server.serve(httpApp, middleware)
|
|
79
|
+
)) as any
|
|
80
|
+
)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import * as Data from "@effect/data/Data"
|
|
2
|
+
import type * as Error from "@effect/platform/Http/ServerError"
|
|
3
|
+
|
|
4
|
+
/** @internal */
|
|
5
|
+
export const TypeId: Error.TypeId = Symbol.for(
|
|
6
|
+
"@effect/platform/Http/Error"
|
|
7
|
+
) as Error.TypeId
|
|
8
|
+
|
|
9
|
+
const make = <A extends Error.HttpServerError>(tag: A["_tag"]) => (props: Omit<A, Error.HttpError.ProvidedFields>): A =>
|
|
10
|
+
Data.struct({
|
|
11
|
+
[TypeId]: TypeId,
|
|
12
|
+
_tag: tag,
|
|
13
|
+
...props
|
|
14
|
+
} as A)
|
|
15
|
+
|
|
16
|
+
/** @internal */
|
|
17
|
+
export const requestError = make<Error.RequestError>("RequestError")
|
|
18
|
+
|
|
19
|
+
/** @internal */
|
|
20
|
+
export const responseError = make<Error.ResponseError>("ResponseError")
|
|
21
|
+
|
|
22
|
+
/** @internal */
|
|
23
|
+
export const routeNotFound = make<Error.RouteNotFound>("RouteNotFound")
|
|
24
|
+
|
|
25
|
+
/** @internal */
|
|
26
|
+
export const serveError = make<Error.ServeError>("ServeError")
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import * as Context from "@effect/data/Context"
|
|
2
|
+
import * as Effect from "@effect/io/Effect"
|
|
3
|
+
import * as FormData from "@effect/platform/Http/FormData"
|
|
4
|
+
import * as IncomingMessage from "@effect/platform/Http/IncomingMessage"
|
|
5
|
+
import * as Error from "@effect/platform/Http/ServerError"
|
|
6
|
+
import type * as ServerRequest from "@effect/platform/Http/ServerRequest"
|
|
7
|
+
import type * as Schema from "@effect/schema/Schema"
|
|
8
|
+
|
|
9
|
+
/** @internal */
|
|
10
|
+
export const TypeId: ServerRequest.TypeId = Symbol.for("@effect/platform/Http/ServerRequest") as ServerRequest.TypeId
|
|
11
|
+
|
|
12
|
+
/** @internal */
|
|
13
|
+
export const serverRequestTag = Context.Tag<ServerRequest.ServerRequest>(TypeId)
|
|
14
|
+
|
|
15
|
+
/** @internal */
|
|
16
|
+
export const formDataRecord = Effect.map(
|
|
17
|
+
Effect.flatMap(serverRequestTag, (request) => request.formData),
|
|
18
|
+
FormData.toRecord
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
/** @internal */
|
|
22
|
+
export const schemaHeaders = <I extends Readonly<Record<string, string>>, A>(schema: Schema.Schema<I, A>) => {
|
|
23
|
+
const parse = IncomingMessage.schemaHeaders(schema)
|
|
24
|
+
return Effect.flatMap(serverRequestTag, parse)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** @internal */
|
|
28
|
+
export const schemaBodyJson = <I, A>(schema: Schema.Schema<I, A>) => {
|
|
29
|
+
const parse = IncomingMessage.schemaBodyJson(schema)
|
|
30
|
+
return Effect.flatMap(serverRequestTag, parse)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** @internal */
|
|
34
|
+
export const schemaBodyUrlParams = <I extends Readonly<Record<string, string>>, A>(schema: Schema.Schema<I, A>) => {
|
|
35
|
+
const parse = IncomingMessage.schemaBodyUrlParams(schema)
|
|
36
|
+
return Effect.flatMap(serverRequestTag, parse)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** @internal */
|
|
40
|
+
export const schemaFormData = <I extends Readonly<Record<string, string | ReadonlyArray<globalThis.File>>>, A>(
|
|
41
|
+
schema: Schema.Schema<I, A>
|
|
42
|
+
) => {
|
|
43
|
+
const parse = FormData.schemaRecord(schema)
|
|
44
|
+
return Effect.flatMap(
|
|
45
|
+
Effect.flatMap(serverRequestTag, (request) => request.formData),
|
|
46
|
+
parse
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** @internal */
|
|
51
|
+
export const schemaFormDataJson = <I, A>(schema: Schema.Schema<I, A>) => {
|
|
52
|
+
const parse = FormData.schemaJson(schema)
|
|
53
|
+
return (field: string) =>
|
|
54
|
+
Effect.flatMap(serverRequestTag, (request) =>
|
|
55
|
+
Effect.flatMap(
|
|
56
|
+
request.formData,
|
|
57
|
+
(formData) =>
|
|
58
|
+
Effect.catchTag(
|
|
59
|
+
parse(formData, field),
|
|
60
|
+
"FormDataError",
|
|
61
|
+
(error) =>
|
|
62
|
+
Effect.fail(
|
|
63
|
+
Error.RequestError({
|
|
64
|
+
reason: "Decode",
|
|
65
|
+
request,
|
|
66
|
+
error: error.error
|
|
67
|
+
})
|
|
68
|
+
)
|
|
69
|
+
)
|
|
70
|
+
))
|
|
71
|
+
}
|