effect-start 0.17.2 → 0.19.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/dist/Development.d.ts +7 -2
- package/dist/Development.js +12 -6
- package/dist/PlatformRuntime.d.ts +4 -0
- package/dist/PlatformRuntime.js +9 -0
- package/dist/Route.d.ts +6 -2
- package/dist/Route.js +22 -0
- package/dist/RouteHttp.d.ts +1 -1
- package/dist/RouteHttp.js +12 -19
- package/dist/RouteMount.d.ts +2 -1
- package/dist/Start.d.ts +1 -5
- package/dist/Start.js +1 -8
- package/dist/Unique.d.ts +50 -0
- package/dist/Unique.js +187 -0
- package/dist/bun/BunHttpServer.js +5 -6
- package/dist/bun/BunRoute.d.ts +1 -1
- package/dist/bun/BunRoute.js +2 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/node/Effectify.d.ts +209 -0
- package/dist/node/Effectify.js +19 -0
- package/dist/node/FileSystem.d.ts +3 -5
- package/dist/node/FileSystem.js +42 -62
- package/dist/node/PlatformError.d.ts +46 -0
- package/dist/node/PlatformError.js +43 -0
- package/dist/testing/TestLogger.js +1 -1
- package/package.json +10 -5
- package/src/Development.ts +13 -18
- package/src/PlatformRuntime.ts +11 -0
- package/src/Route.ts +31 -2
- package/src/RouteHttp.ts +15 -31
- package/src/RouteMount.ts +1 -1
- package/src/Start.ts +1 -15
- package/src/Unique.ts +232 -0
- package/src/bun/BunHttpServer.ts +6 -9
- package/src/bun/BunRoute.ts +3 -3
- package/src/index.ts +1 -0
- package/src/node/Effectify.ts +262 -0
- package/src/node/FileSystem.ts +59 -97
- package/src/node/PlatformError.ts +102 -0
- package/src/testing/TestLogger.ts +1 -1
- package/dist/Random.d.ts +0 -5
- package/dist/Random.js +0 -49
- package/src/Commander.test.ts +0 -1639
- package/src/ContentNegotiation.test.ts +0 -603
- package/src/Development.test.ts +0 -119
- package/src/Entity.test.ts +0 -592
- package/src/FileRouterPattern.test.ts +0 -147
- package/src/FileRouter_files.test.ts +0 -64
- package/src/FileRouter_path.test.ts +0 -145
- package/src/FileRouter_tree.test.ts +0 -132
- package/src/Http.test.ts +0 -319
- package/src/HttpAppExtra.test.ts +0 -103
- package/src/HttpUtils.test.ts +0 -85
- package/src/PathPattern.test.ts +0 -648
- package/src/Random.ts +0 -59
- package/src/RouteBody.test.ts +0 -232
- package/src/RouteHook.test.ts +0 -40
- package/src/RouteHttp.test.ts +0 -2909
- package/src/RouteMount.test.ts +0 -481
- package/src/RouteSchema.test.ts +0 -427
- package/src/RouteSse.test.ts +0 -249
- package/src/RouteTree.test.ts +0 -494
- package/src/RouteTrie.test.ts +0 -322
- package/src/RouterPattern.test.ts +0 -676
- package/src/Values.test.ts +0 -263
- package/src/bun/BunBundle.test.ts +0 -268
- package/src/bun/BunBundle_imports.test.ts +0 -48
- package/src/bun/BunHttpServer.test.ts +0 -251
- package/src/bun/BunImportTrackerPlugin.test.ts +0 -77
- package/src/bun/BunRoute.test.ts +0 -162
- package/src/bundler/BundleHttp.test.ts +0 -132
- package/src/effect/HttpRouter.test.ts +0 -548
- package/src/experimental/EncryptedCookies.test.ts +0 -488
- package/src/hyper/HyperHtml.test.ts +0 -209
- package/src/hyper/HyperRoute.test.tsx +0 -197
- package/src/middlewares/BasicAuthMiddleware.test.ts +0 -84
- package/src/testing/TestHttpClient.test.ts +0 -83
- package/src/testing/TestLogger.test.ts +0 -51
- package/src/x/datastar/Datastar.test.ts +0 -266
- package/src/x/tailwind/TailwindPlugin.test.ts +0 -333
package/src/Http.test.ts
DELETED
|
@@ -1,319 +0,0 @@
|
|
|
1
|
-
import * as test from "bun:test"
|
|
2
|
-
import * as Http from "./Http.ts"
|
|
3
|
-
|
|
4
|
-
test.describe("mapHeaders", () => {
|
|
5
|
-
test.it("converts Headers to record with lowercase keys", () => {
|
|
6
|
-
const headers = new Headers({
|
|
7
|
-
"Content-Type": "application/json",
|
|
8
|
-
"X-Custom-Header": "value",
|
|
9
|
-
})
|
|
10
|
-
|
|
11
|
-
const record = Http.mapHeaders(headers)
|
|
12
|
-
|
|
13
|
-
test
|
|
14
|
-
.expect(record)
|
|
15
|
-
.toEqual({
|
|
16
|
-
"content-type": "application/json",
|
|
17
|
-
"x-custom-header": "value",
|
|
18
|
-
})
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
test.it("returns empty record for empty headers", () => {
|
|
22
|
-
const headers = new Headers()
|
|
23
|
-
const record = Http.mapHeaders(headers)
|
|
24
|
-
|
|
25
|
-
test
|
|
26
|
-
.expect(record)
|
|
27
|
-
.toEqual({})
|
|
28
|
-
})
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
test.describe("parseCookies", () => {
|
|
32
|
-
test.it("parses cookie header string", () => {
|
|
33
|
-
const cookieHeader = "session=abc123; token=xyz789"
|
|
34
|
-
const cookies = Http.parseCookies(cookieHeader)
|
|
35
|
-
|
|
36
|
-
test
|
|
37
|
-
.expect(cookies)
|
|
38
|
-
.toEqual({
|
|
39
|
-
session: "abc123",
|
|
40
|
-
token: "xyz789",
|
|
41
|
-
})
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
test.it("handles cookies with = in value", () => {
|
|
45
|
-
const cookieHeader = "data=key=value"
|
|
46
|
-
const cookies = Http.parseCookies(cookieHeader)
|
|
47
|
-
|
|
48
|
-
test
|
|
49
|
-
.expect(cookies)
|
|
50
|
-
.toEqual({
|
|
51
|
-
data: "key=value",
|
|
52
|
-
})
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
test.it("trims whitespace from cookie names and values", () => {
|
|
56
|
-
const cookieHeader = " session = abc123 ; token = xyz789 "
|
|
57
|
-
const cookies = Http.parseCookies(cookieHeader)
|
|
58
|
-
|
|
59
|
-
test
|
|
60
|
-
.expect(cookies)
|
|
61
|
-
.toEqual({
|
|
62
|
-
session: "abc123",
|
|
63
|
-
token: "xyz789",
|
|
64
|
-
})
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
test.it("handles empty cookie values", () => {
|
|
68
|
-
const cookieHeader = "session=; token=xyz789"
|
|
69
|
-
const cookies = Http.parseCookies(cookieHeader)
|
|
70
|
-
|
|
71
|
-
test
|
|
72
|
-
.expect(cookies)
|
|
73
|
-
.toEqual({
|
|
74
|
-
session: "",
|
|
75
|
-
token: "xyz789",
|
|
76
|
-
})
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
test.it("handles cookies without values", () => {
|
|
80
|
-
const cookieHeader = "flag; session=abc123"
|
|
81
|
-
const cookies = Http.parseCookies(cookieHeader)
|
|
82
|
-
|
|
83
|
-
test
|
|
84
|
-
.expect(cookies)
|
|
85
|
-
.toEqual({
|
|
86
|
-
flag: undefined,
|
|
87
|
-
session: "abc123",
|
|
88
|
-
})
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
test.it("ignores empty parts", () => {
|
|
92
|
-
const cookieHeader = "session=abc123;; ; token=xyz789"
|
|
93
|
-
const cookies = Http.parseCookies(cookieHeader)
|
|
94
|
-
|
|
95
|
-
test
|
|
96
|
-
.expect(cookies)
|
|
97
|
-
.toEqual({
|
|
98
|
-
session: "abc123",
|
|
99
|
-
token: "xyz789",
|
|
100
|
-
})
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
test.it("returns empty record for null cookie header", () => {
|
|
104
|
-
const cookies = Http.parseCookies(null)
|
|
105
|
-
|
|
106
|
-
test
|
|
107
|
-
.expect(cookies)
|
|
108
|
-
.toEqual({})
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
test.it("returns empty record for empty cookie header", () => {
|
|
112
|
-
const cookies = Http.parseCookies("")
|
|
113
|
-
|
|
114
|
-
test
|
|
115
|
-
.expect(cookies)
|
|
116
|
-
.toEqual({})
|
|
117
|
-
})
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
test.describe("mapUrlSearchParams", () => {
|
|
121
|
-
test.it("converts single values to strings", () => {
|
|
122
|
-
const params = new URLSearchParams("page=1&limit=10")
|
|
123
|
-
const record = Http.mapUrlSearchParams(params)
|
|
124
|
-
|
|
125
|
-
test
|
|
126
|
-
.expect(record)
|
|
127
|
-
.toEqual({
|
|
128
|
-
page: "1",
|
|
129
|
-
limit: "10",
|
|
130
|
-
})
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
test.it("converts multiple values to arrays", () => {
|
|
134
|
-
const params = new URLSearchParams("tags=red&tags=blue&tags=green")
|
|
135
|
-
const record = Http.mapUrlSearchParams(params)
|
|
136
|
-
|
|
137
|
-
test
|
|
138
|
-
.expect(record)
|
|
139
|
-
.toEqual({
|
|
140
|
-
tags: ["red", "blue", "green"],
|
|
141
|
-
})
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
test.it("handles mixed single and multiple values", () => {
|
|
145
|
-
const params = new URLSearchParams("page=1&tags=red&tags=blue")
|
|
146
|
-
const record = Http.mapUrlSearchParams(params)
|
|
147
|
-
|
|
148
|
-
test
|
|
149
|
-
.expect(record)
|
|
150
|
-
.toEqual({
|
|
151
|
-
page: "1",
|
|
152
|
-
tags: ["red", "blue"],
|
|
153
|
-
})
|
|
154
|
-
})
|
|
155
|
-
|
|
156
|
-
test.it("returns empty record for empty params", () => {
|
|
157
|
-
const params = new URLSearchParams()
|
|
158
|
-
const record = Http.mapUrlSearchParams(params)
|
|
159
|
-
|
|
160
|
-
test
|
|
161
|
-
.expect(record)
|
|
162
|
-
.toEqual({})
|
|
163
|
-
})
|
|
164
|
-
})
|
|
165
|
-
|
|
166
|
-
test.describe("parseFormData", () => {
|
|
167
|
-
function createFormDataRequest(formData: FormData): Request {
|
|
168
|
-
return new Request("http://localhost/", {
|
|
169
|
-
method: "POST",
|
|
170
|
-
body: formData,
|
|
171
|
-
})
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
test.it("parses single string field", async () => {
|
|
175
|
-
const formData = new FormData()
|
|
176
|
-
formData.append("name", "John")
|
|
177
|
-
|
|
178
|
-
const request = createFormDataRequest(formData)
|
|
179
|
-
const result = await Http.parseFormData(request)
|
|
180
|
-
|
|
181
|
-
test
|
|
182
|
-
.expect(result)
|
|
183
|
-
.toEqual({
|
|
184
|
-
name: "John",
|
|
185
|
-
})
|
|
186
|
-
})
|
|
187
|
-
|
|
188
|
-
test.it("parses multiple string fields", async () => {
|
|
189
|
-
const formData = new FormData()
|
|
190
|
-
formData.append("name", "John")
|
|
191
|
-
formData.append("email", "john@example.com")
|
|
192
|
-
|
|
193
|
-
const request = createFormDataRequest(formData)
|
|
194
|
-
const result = await Http.parseFormData(request)
|
|
195
|
-
|
|
196
|
-
test
|
|
197
|
-
.expect(result)
|
|
198
|
-
.toEqual({
|
|
199
|
-
name: "John",
|
|
200
|
-
email: "john@example.com",
|
|
201
|
-
})
|
|
202
|
-
})
|
|
203
|
-
|
|
204
|
-
test.it("parses multiple values for same key as array", async () => {
|
|
205
|
-
const formData = new FormData()
|
|
206
|
-
formData.append("tags", "red")
|
|
207
|
-
formData.append("tags", "blue")
|
|
208
|
-
formData.append("tags", "green")
|
|
209
|
-
|
|
210
|
-
const request = createFormDataRequest(formData)
|
|
211
|
-
const result = await Http.parseFormData(request)
|
|
212
|
-
|
|
213
|
-
test
|
|
214
|
-
.expect(result)
|
|
215
|
-
.toEqual({
|
|
216
|
-
tags: ["red", "blue", "green"],
|
|
217
|
-
})
|
|
218
|
-
})
|
|
219
|
-
|
|
220
|
-
test.it("parses single file upload", async () => {
|
|
221
|
-
const formData = new FormData()
|
|
222
|
-
const fileContent = new Uint8Array([72, 101, 108, 108, 111]) // "Hello"
|
|
223
|
-
const file = new File([fileContent], "test.txt", { type: "text/plain" })
|
|
224
|
-
formData.append("document", file)
|
|
225
|
-
|
|
226
|
-
const request = createFormDataRequest(formData)
|
|
227
|
-
const result = await Http.parseFormData(request)
|
|
228
|
-
|
|
229
|
-
test.expect(result.document).toBeDefined()
|
|
230
|
-
const files = result.document as ReadonlyArray<Http.FilePart>
|
|
231
|
-
test.expect(files).toHaveLength(1)
|
|
232
|
-
test.expect(files[0]._tag).toBe("File")
|
|
233
|
-
test.expect(files[0].key).toBe("document")
|
|
234
|
-
test.expect(files[0].name).toBe("test.txt")
|
|
235
|
-
test.expect(files[0].contentType.startsWith("text/plain")).toBe(true)
|
|
236
|
-
test.expect(files[0].content).toEqual(fileContent)
|
|
237
|
-
})
|
|
238
|
-
|
|
239
|
-
test.it("parses multiple file uploads for same key", async () => {
|
|
240
|
-
const formData = new FormData()
|
|
241
|
-
const file1 = new File([new Uint8Array([1, 2, 3])], "file1.bin", {
|
|
242
|
-
type: "application/octet-stream",
|
|
243
|
-
})
|
|
244
|
-
const file2 = new File([new Uint8Array([4, 5, 6])], "file2.bin", {
|
|
245
|
-
type: "application/octet-stream",
|
|
246
|
-
})
|
|
247
|
-
formData.append("files", file1)
|
|
248
|
-
formData.append("files", file2)
|
|
249
|
-
|
|
250
|
-
const request = createFormDataRequest(formData)
|
|
251
|
-
const result = await Http.parseFormData(request)
|
|
252
|
-
|
|
253
|
-
const files = result.files as ReadonlyArray<Http.FilePart>
|
|
254
|
-
test.expect(files).toHaveLength(2)
|
|
255
|
-
test.expect(files[0].name).toBe("file1.bin")
|
|
256
|
-
test.expect(files[0].content).toEqual(new Uint8Array([1, 2, 3]))
|
|
257
|
-
test.expect(files[1].name).toBe("file2.bin")
|
|
258
|
-
test.expect(files[1].content).toEqual(new Uint8Array([4, 5, 6]))
|
|
259
|
-
})
|
|
260
|
-
|
|
261
|
-
test.it("uses default content type for files without type", async () => {
|
|
262
|
-
const formData = new FormData()
|
|
263
|
-
const file = new File([new Uint8Array([1, 2, 3])], "unknown.dat", {
|
|
264
|
-
type: "",
|
|
265
|
-
})
|
|
266
|
-
formData.append("upload", file)
|
|
267
|
-
|
|
268
|
-
const request = createFormDataRequest(formData)
|
|
269
|
-
const result = await Http.parseFormData(request)
|
|
270
|
-
|
|
271
|
-
const files = result.upload as ReadonlyArray<Http.FilePart>
|
|
272
|
-
test.expect(files[0].contentType).toBe("application/octet-stream")
|
|
273
|
-
})
|
|
274
|
-
|
|
275
|
-
test.it("parses mixed string fields and file uploads", async () => {
|
|
276
|
-
const formData = new FormData()
|
|
277
|
-
formData.append("title", "My Document")
|
|
278
|
-
const file = new File([new Uint8Array([1, 2, 3])], "doc.pdf", {
|
|
279
|
-
type: "application/pdf",
|
|
280
|
-
})
|
|
281
|
-
formData.append("attachment", file)
|
|
282
|
-
formData.append("description", "A test document")
|
|
283
|
-
|
|
284
|
-
const request = createFormDataRequest(formData)
|
|
285
|
-
const result = await Http.parseFormData(request)
|
|
286
|
-
|
|
287
|
-
test.expect(result.title).toBe("My Document")
|
|
288
|
-
test.expect(result.description).toBe("A test document")
|
|
289
|
-
const files = result.attachment as ReadonlyArray<Http.FilePart>
|
|
290
|
-
test.expect(files).toHaveLength(1)
|
|
291
|
-
test.expect(files[0].name).toBe("doc.pdf")
|
|
292
|
-
})
|
|
293
|
-
|
|
294
|
-
test.it("returns empty record for empty form data", async () => {
|
|
295
|
-
const formData = new FormData()
|
|
296
|
-
|
|
297
|
-
const request = createFormDataRequest(formData)
|
|
298
|
-
const result = await Http.parseFormData(request)
|
|
299
|
-
|
|
300
|
-
test
|
|
301
|
-
.expect(result)
|
|
302
|
-
.toEqual({})
|
|
303
|
-
})
|
|
304
|
-
|
|
305
|
-
test.it("parses Blob as file", async () => {
|
|
306
|
-
const formData = new FormData()
|
|
307
|
-
const blob = new Blob([new Uint8Array([10, 20, 30])], { type: "image/png" })
|
|
308
|
-
formData.append("image", blob, "image.png")
|
|
309
|
-
|
|
310
|
-
const request = createFormDataRequest(formData)
|
|
311
|
-
const result = await Http.parseFormData(request)
|
|
312
|
-
|
|
313
|
-
const files = result.image as ReadonlyArray<Http.FilePart>
|
|
314
|
-
test.expect(files).toHaveLength(1)
|
|
315
|
-
test.expect(files[0].name).toBe("image.png")
|
|
316
|
-
test.expect(files[0].contentType).toBe("image/png")
|
|
317
|
-
test.expect(files[0].content).toEqual(new Uint8Array([10, 20, 30]))
|
|
318
|
-
})
|
|
319
|
-
})
|
package/src/HttpAppExtra.test.ts
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import { HttpServerRequest } from "@effect/platform"
|
|
2
|
-
import { RouteNotFound } from "@effect/platform/HttpServerError"
|
|
3
|
-
import * as test from "bun:test"
|
|
4
|
-
import {
|
|
5
|
-
Layer,
|
|
6
|
-
Logger,
|
|
7
|
-
} from "effect"
|
|
8
|
-
import * as Cause from "effect/Cause"
|
|
9
|
-
import * as LogLevel from "effect/LogLevel"
|
|
10
|
-
import * as HttpAppExtra from "./HttpAppExtra.ts"
|
|
11
|
-
import { effectFn } from "./testing"
|
|
12
|
-
|
|
13
|
-
const mockRequest = HttpServerRequest.HttpServerRequest.of({
|
|
14
|
-
url: "http://localhost:3000/test",
|
|
15
|
-
method: "GET",
|
|
16
|
-
headers: {
|
|
17
|
-
"accept": "application/json",
|
|
18
|
-
"user-agent": "test",
|
|
19
|
-
},
|
|
20
|
-
} as any)
|
|
21
|
-
|
|
22
|
-
const mockRequestLayer = Layer.mergeAll(
|
|
23
|
-
Layer.succeed(HttpServerRequest.HttpServerRequest, mockRequest),
|
|
24
|
-
Logger.minimumLogLevel(LogLevel.None),
|
|
25
|
-
)
|
|
26
|
-
|
|
27
|
-
const effect = effectFn(mockRequestLayer)
|
|
28
|
-
|
|
29
|
-
test.describe("renderError", () => {
|
|
30
|
-
const routeNotFoundCause = Cause.fail(
|
|
31
|
-
new RouteNotFound({ request: {} as any }),
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
test.it("returns JSON for Accept: application/json", () =>
|
|
35
|
-
effect(function*() {
|
|
36
|
-
const response = yield* HttpAppExtra.renderError(
|
|
37
|
-
routeNotFoundCause,
|
|
38
|
-
"application/json",
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
test
|
|
42
|
-
.expect(response.status)
|
|
43
|
-
.toEqual(404)
|
|
44
|
-
test
|
|
45
|
-
.expect(response.headers["content-type"])
|
|
46
|
-
.toContain("application/json")
|
|
47
|
-
}))
|
|
48
|
-
|
|
49
|
-
test.it("returns HTML for Accept: text/html", () =>
|
|
50
|
-
effect(function*() {
|
|
51
|
-
const response = yield* HttpAppExtra.renderError(
|
|
52
|
-
routeNotFoundCause,
|
|
53
|
-
"text/html",
|
|
54
|
-
)
|
|
55
|
-
|
|
56
|
-
test
|
|
57
|
-
.expect(response.status)
|
|
58
|
-
.toEqual(404)
|
|
59
|
-
test
|
|
60
|
-
.expect(response.headers["content-type"])
|
|
61
|
-
.toContain("text/html")
|
|
62
|
-
}))
|
|
63
|
-
|
|
64
|
-
test.it("returns plain text for Accept: text/plain", () =>
|
|
65
|
-
effect(function*() {
|
|
66
|
-
const response = yield* HttpAppExtra.renderError(
|
|
67
|
-
routeNotFoundCause,
|
|
68
|
-
"text/plain",
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
test
|
|
72
|
-
.expect(response.status)
|
|
73
|
-
.toEqual(404)
|
|
74
|
-
test
|
|
75
|
-
.expect(response.headers["content-type"])
|
|
76
|
-
.toContain("text/plain")
|
|
77
|
-
}))
|
|
78
|
-
|
|
79
|
-
test.it("returns JSON by default (no Accept header)", () =>
|
|
80
|
-
effect(function*() {
|
|
81
|
-
const response = yield* HttpAppExtra.renderError(routeNotFoundCause, "")
|
|
82
|
-
|
|
83
|
-
test
|
|
84
|
-
.expect(response.status)
|
|
85
|
-
.toEqual(404)
|
|
86
|
-
test
|
|
87
|
-
.expect(response.headers["content-type"])
|
|
88
|
-
.toContain("application/json")
|
|
89
|
-
}))
|
|
90
|
-
|
|
91
|
-
test.it("returns 500 for unexpected errors", () =>
|
|
92
|
-
effect(function*() {
|
|
93
|
-
const unexpectedCause = Cause.fail({ message: "Something went wrong" })
|
|
94
|
-
const response = yield* HttpAppExtra.renderError(
|
|
95
|
-
unexpectedCause,
|
|
96
|
-
"application/json",
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
test
|
|
100
|
-
.expect(response.status)
|
|
101
|
-
.toEqual(500)
|
|
102
|
-
}))
|
|
103
|
-
})
|
package/src/HttpUtils.test.ts
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import * as HttpServerRequest from "@effect/platform/HttpServerRequest"
|
|
2
|
-
import * as test from "bun:test"
|
|
3
|
-
import * as HttpUtils from "./HttpUtils.ts"
|
|
4
|
-
|
|
5
|
-
const makeRequest = (url: string, headers: Record<string, string> = {}) =>
|
|
6
|
-
HttpServerRequest.fromWeb(
|
|
7
|
-
new Request(`http://test${url}`, { headers }),
|
|
8
|
-
)
|
|
9
|
-
|
|
10
|
-
test.describe("makeUrlFromRequest", () => {
|
|
11
|
-
test.it("uses Host header for relative URL", () => {
|
|
12
|
-
const request = makeRequest("/api/users", {
|
|
13
|
-
host: "example.com",
|
|
14
|
-
})
|
|
15
|
-
const url = HttpUtils.makeUrlFromRequest(request)
|
|
16
|
-
|
|
17
|
-
test
|
|
18
|
-
.expect(url.href)
|
|
19
|
-
.toBe("http://example.com/api/users")
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
test.it("uses Origin header when present (takes precedence over Host)", () => {
|
|
23
|
-
const request = makeRequest("/api/users", {
|
|
24
|
-
origin: "https://app.example.com",
|
|
25
|
-
host: "example.com",
|
|
26
|
-
})
|
|
27
|
-
const url = HttpUtils.makeUrlFromRequest(request)
|
|
28
|
-
|
|
29
|
-
test
|
|
30
|
-
.expect(url.href)
|
|
31
|
-
.toBe("https://app.example.com/api/users")
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
test.it("uses X-Forwarded-Proto for protocol behind reverse proxy", () => {
|
|
35
|
-
const request = makeRequest("/api/users", {
|
|
36
|
-
host: "example.com",
|
|
37
|
-
"x-forwarded-proto": "https",
|
|
38
|
-
})
|
|
39
|
-
const url = HttpUtils.makeUrlFromRequest(request)
|
|
40
|
-
|
|
41
|
-
test
|
|
42
|
-
.expect(url.href)
|
|
43
|
-
.toBe("https://example.com/api/users")
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
test.it("falls back to http://localhost when no headers", () => {
|
|
47
|
-
const request = makeRequest("/api/users", {})
|
|
48
|
-
const url = HttpUtils.makeUrlFromRequest(request)
|
|
49
|
-
|
|
50
|
-
test
|
|
51
|
-
.expect(url.href)
|
|
52
|
-
.toBe("http://localhost/api/users")
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
test.it("handles URL with query parameters", () => {
|
|
56
|
-
const request = makeRequest("/search?q=test&page=1", {
|
|
57
|
-
host: "example.com",
|
|
58
|
-
})
|
|
59
|
-
const url = HttpUtils.makeUrlFromRequest(request)
|
|
60
|
-
|
|
61
|
-
test
|
|
62
|
-
.expect(url.href)
|
|
63
|
-
.toBe("http://example.com/search?q=test&page=1")
|
|
64
|
-
test
|
|
65
|
-
.expect(url.searchParams.get("q"))
|
|
66
|
-
.toBe("test")
|
|
67
|
-
test
|
|
68
|
-
.expect(url.searchParams.get("page"))
|
|
69
|
-
.toBe("1")
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
test.it("handles root path", () => {
|
|
73
|
-
const request = makeRequest("/", {
|
|
74
|
-
host: "example.com",
|
|
75
|
-
})
|
|
76
|
-
const url = HttpUtils.makeUrlFromRequest(request)
|
|
77
|
-
|
|
78
|
-
test
|
|
79
|
-
.expect(url.href)
|
|
80
|
-
.toBe("http://example.com/")
|
|
81
|
-
test
|
|
82
|
-
.expect(url.pathname)
|
|
83
|
-
.toBe("/")
|
|
84
|
-
})
|
|
85
|
-
})
|