effect-start 0.18.0 → 0.20.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.
Files changed (203) hide show
  1. package/README.md +3 -3
  2. package/dist/Development.d.ts +8 -3
  3. package/dist/Development.js +14 -7
  4. package/dist/Effectify.d.ts +212 -0
  5. package/dist/Effectify.js +19 -0
  6. package/dist/FilePathPattern.d.ts +29 -0
  7. package/dist/FilePathPattern.js +86 -0
  8. package/dist/FileRouter.d.ts +39 -41
  9. package/dist/FileRouter.js +104 -158
  10. package/dist/FileRouterCodegen.d.ts +7 -8
  11. package/dist/FileRouterCodegen.js +97 -66
  12. package/dist/PlatformError.d.ts +46 -0
  13. package/dist/PlatformError.js +43 -0
  14. package/dist/PlatformRuntime.d.ts +27 -0
  15. package/dist/PlatformRuntime.js +51 -0
  16. package/dist/Route.d.ts +6 -2
  17. package/dist/Route.js +22 -0
  18. package/dist/RouteBody.d.ts +1 -1
  19. package/dist/RouteHttp.d.ts +1 -1
  20. package/dist/RouteHttp.js +12 -19
  21. package/dist/RouteMount.d.ts +2 -1
  22. package/dist/Start.d.ts +33 -6
  23. package/dist/Start.js +31 -13
  24. package/dist/Unique.d.ts +50 -0
  25. package/dist/Unique.js +187 -0
  26. package/dist/bun/BunHttpServer.js +5 -6
  27. package/dist/bun/BunPlatformHttpServer.d.ts +10 -0
  28. package/dist/bun/BunPlatformHttpServer.js +53 -0
  29. package/dist/bun/BunRoute.d.ts +4 -6
  30. package/dist/bun/BunRoute.js +10 -18
  31. package/dist/bun/BunRuntime.d.ts +2 -1
  32. package/dist/bun/BunRuntime.js +10 -5
  33. package/dist/bun/BunServer.d.ts +33 -0
  34. package/dist/bun/BunServer.js +133 -0
  35. package/dist/bun/BunServerRequest.d.ts +60 -0
  36. package/dist/bun/BunServerRequest.js +252 -0
  37. package/dist/bun/index.d.ts +1 -1
  38. package/dist/bun/index.js +1 -1
  39. package/dist/datastar/actions/fetch.d.ts +30 -0
  40. package/dist/datastar/actions/fetch.js +411 -0
  41. package/dist/datastar/actions/peek.d.ts +1 -0
  42. package/dist/datastar/actions/peek.js +14 -0
  43. package/dist/datastar/actions/setAll.d.ts +1 -0
  44. package/dist/datastar/actions/setAll.js +13 -0
  45. package/dist/datastar/actions/toggleAll.d.ts +1 -0
  46. package/dist/datastar/actions/toggleAll.js +13 -0
  47. package/dist/datastar/attributes/attr.d.ts +1 -0
  48. package/dist/datastar/attributes/attr.js +49 -0
  49. package/dist/datastar/attributes/bind.d.ts +1 -0
  50. package/dist/datastar/attributes/bind.js +183 -0
  51. package/dist/datastar/attributes/class.d.ts +1 -0
  52. package/dist/datastar/attributes/class.js +50 -0
  53. package/dist/datastar/attributes/computed.d.ts +1 -0
  54. package/dist/datastar/attributes/computed.js +27 -0
  55. package/dist/datastar/attributes/effect.d.ts +1 -0
  56. package/dist/datastar/attributes/effect.js +10 -0
  57. package/dist/datastar/attributes/indicator.d.ts +1 -0
  58. package/dist/datastar/attributes/indicator.js +32 -0
  59. package/dist/datastar/attributes/init.d.ts +1 -0
  60. package/dist/datastar/attributes/init.js +27 -0
  61. package/dist/datastar/attributes/jsonSignals.d.ts +1 -0
  62. package/dist/datastar/attributes/jsonSignals.js +31 -0
  63. package/dist/datastar/attributes/on.d.ts +1 -0
  64. package/dist/datastar/attributes/on.js +59 -0
  65. package/dist/datastar/attributes/onIntersect.d.ts +1 -0
  66. package/dist/datastar/attributes/onIntersect.js +54 -0
  67. package/dist/datastar/attributes/onInterval.d.ts +1 -0
  68. package/dist/datastar/attributes/onInterval.js +31 -0
  69. package/dist/datastar/attributes/onSignalPatch.d.ts +1 -0
  70. package/dist/datastar/attributes/onSignalPatch.js +44 -0
  71. package/dist/datastar/attributes/ref.d.ts +1 -0
  72. package/dist/datastar/attributes/ref.js +11 -0
  73. package/dist/datastar/attributes/show.d.ts +1 -0
  74. package/dist/datastar/attributes/show.js +32 -0
  75. package/dist/datastar/attributes/signals.d.ts +1 -0
  76. package/dist/datastar/attributes/signals.js +18 -0
  77. package/dist/datastar/attributes/style.d.ts +1 -0
  78. package/dist/datastar/attributes/style.js +56 -0
  79. package/dist/datastar/attributes/text.d.ts +1 -0
  80. package/dist/datastar/attributes/text.js +27 -0
  81. package/dist/datastar/engine.d.ts +156 -0
  82. package/dist/datastar/engine.js +971 -0
  83. package/dist/datastar/index.d.ts +24 -0
  84. package/dist/datastar/index.js +24 -0
  85. package/dist/datastar/load.d.ts +24 -0
  86. package/dist/datastar/load.js +24 -0
  87. package/dist/datastar/utils.d.ts +51 -0
  88. package/dist/datastar/utils.js +205 -0
  89. package/dist/datastar/watchers/patchElements.d.ts +1 -0
  90. package/dist/datastar/watchers/patchElements.js +420 -0
  91. package/dist/datastar/watchers/patchSignals.d.ts +1 -0
  92. package/dist/datastar/watchers/patchSignals.js +15 -0
  93. package/dist/index.d.ts +1 -0
  94. package/dist/index.js +1 -0
  95. package/dist/node/Effectify.d.ts +209 -0
  96. package/dist/node/Effectify.js +19 -0
  97. package/dist/node/FileSystem.d.ts +3 -5
  98. package/dist/node/FileSystem.js +42 -62
  99. package/dist/node/NodeFileSystem.d.ts +7 -0
  100. package/dist/node/NodeFileSystem.js +420 -0
  101. package/dist/node/NodeUtils.d.ts +2 -0
  102. package/dist/node/NodeUtils.js +20 -0
  103. package/dist/node/PlatformError.d.ts +46 -0
  104. package/dist/node/PlatformError.js +43 -0
  105. package/dist/testing/TestLogger.js +1 -1
  106. package/dist/x/tailwind/plugin.js +1 -1
  107. package/package.json +18 -7
  108. package/src/Development.ts +36 -40
  109. package/src/Effectify.ts +269 -0
  110. package/src/FilePathPattern.ts +115 -0
  111. package/src/FileRouter.ts +178 -255
  112. package/src/FileRouterCodegen.ts +135 -92
  113. package/src/PlatformError.ts +117 -0
  114. package/src/PlatformRuntime.ts +108 -0
  115. package/src/Route.ts +31 -2
  116. package/src/RouteBody.ts +1 -1
  117. package/src/RouteHttp.ts +15 -29
  118. package/src/RouteMount.ts +1 -1
  119. package/src/Start.ts +61 -27
  120. package/src/Unique.ts +232 -0
  121. package/src/bun/BunPlatformHttpServer.ts +88 -0
  122. package/src/bun/BunRoute.ts +14 -24
  123. package/src/bun/BunRuntime.ts +21 -5
  124. package/src/bun/BunServer.ts +228 -0
  125. package/src/bun/index.ts +1 -1
  126. package/src/datastar/README.md +18 -0
  127. package/src/datastar/actions/fetch.ts +609 -0
  128. package/src/datastar/actions/peek.ts +17 -0
  129. package/src/datastar/actions/setAll.ts +20 -0
  130. package/src/datastar/actions/toggleAll.ts +20 -0
  131. package/src/datastar/attributes/attr.ts +50 -0
  132. package/src/datastar/attributes/bind.ts +220 -0
  133. package/src/datastar/attributes/class.ts +57 -0
  134. package/src/datastar/attributes/computed.ts +33 -0
  135. package/src/datastar/attributes/effect.ts +11 -0
  136. package/src/datastar/attributes/indicator.ts +39 -0
  137. package/src/datastar/attributes/init.ts +35 -0
  138. package/src/datastar/attributes/jsonSignals.ts +38 -0
  139. package/src/datastar/attributes/on.ts +71 -0
  140. package/src/datastar/attributes/onIntersect.ts +65 -0
  141. package/src/datastar/attributes/onInterval.ts +39 -0
  142. package/src/datastar/attributes/onSignalPatch.ts +63 -0
  143. package/src/datastar/attributes/ref.ts +12 -0
  144. package/src/datastar/attributes/show.ts +33 -0
  145. package/src/datastar/attributes/signals.ts +22 -0
  146. package/src/datastar/attributes/style.ts +63 -0
  147. package/src/datastar/attributes/text.ts +30 -0
  148. package/src/datastar/engine.ts +1341 -0
  149. package/src/datastar/index.ts +25 -0
  150. package/src/datastar/utils.ts +286 -0
  151. package/src/datastar/watchers/patchElements.ts +554 -0
  152. package/src/datastar/watchers/patchSignals.ts +15 -0
  153. package/src/index.ts +1 -0
  154. package/src/node/{FileSystem.ts → NodeFileSystem.ts} +59 -97
  155. package/src/node/{Utils.ts → NodeUtils.ts} +2 -0
  156. package/src/testing/TestLogger.ts +1 -1
  157. package/src/x/tailwind/plugin.ts +1 -1
  158. package/dist/Random.d.ts +0 -5
  159. package/dist/Random.js +0 -49
  160. package/src/Commander.test.ts +0 -1639
  161. package/src/ContentNegotiation.test.ts +0 -603
  162. package/src/Development.test.ts +0 -119
  163. package/src/Entity.test.ts +0 -592
  164. package/src/FileRouterCodegen.todo.ts +0 -1133
  165. package/src/FileRouterPattern.test.ts +0 -147
  166. package/src/FileRouterPattern.ts +0 -59
  167. package/src/FileRouter_files.test.ts +0 -64
  168. package/src/FileRouter_path.test.ts +0 -145
  169. package/src/FileRouter_tree.test.ts +0 -132
  170. package/src/Http.test.ts +0 -319
  171. package/src/HttpAppExtra.test.ts +0 -103
  172. package/src/HttpUtils.test.ts +0 -85
  173. package/src/PathPattern.test.ts +0 -648
  174. package/src/Random.ts +0 -59
  175. package/src/RouteBody.test.ts +0 -232
  176. package/src/RouteHook.test.ts +0 -40
  177. package/src/RouteHttp.test.ts +0 -2909
  178. package/src/RouteMount.test.ts +0 -481
  179. package/src/RouteSchema.test.ts +0 -427
  180. package/src/RouteSse.test.ts +0 -249
  181. package/src/RouteTree.test.ts +0 -494
  182. package/src/RouteTrie.test.ts +0 -322
  183. package/src/RouterPattern.test.ts +0 -676
  184. package/src/RouterPattern.ts +0 -416
  185. package/src/StartApp.ts +0 -47
  186. package/src/Values.test.ts +0 -263
  187. package/src/bun/BunBundle.test.ts +0 -268
  188. package/src/bun/BunBundle_imports.test.ts +0 -48
  189. package/src/bun/BunHttpServer.test.ts +0 -251
  190. package/src/bun/BunHttpServer.ts +0 -306
  191. package/src/bun/BunImportTrackerPlugin.test.ts +0 -77
  192. package/src/bun/BunRoute.test.ts +0 -162
  193. package/src/bundler/BundleHttp.test.ts +0 -132
  194. package/src/effect/HttpRouter.test.ts +0 -548
  195. package/src/experimental/EncryptedCookies.test.ts +0 -488
  196. package/src/hyper/HyperHtml.test.ts +0 -209
  197. package/src/hyper/HyperRoute.test.tsx +0 -197
  198. package/src/middlewares/BasicAuthMiddleware.test.ts +0 -84
  199. package/src/testing/TestHttpClient.test.ts +0 -83
  200. package/src/testing/TestLogger.test.ts +0 -51
  201. package/src/x/datastar/Datastar.test.ts +0 -266
  202. package/src/x/tailwind/TailwindPlugin.test.ts +0 -333
  203. /package/src/bun/{BunHttpServer_web.ts → BunServerRequest.ts} +0 -0
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
- })
@@ -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
- })
@@ -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
- })