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
@@ -1,488 +0,0 @@
1
- import * as Cookies from "@effect/platform/Cookies"
2
- import * as test from "bun:test"
3
- import * as ConfigProvider from "effect/ConfigProvider"
4
- import * as Effect from "effect/Effect"
5
- import * as EncryptedCookies from "./EncryptedCookies.ts"
6
-
7
- test.describe(`${EncryptedCookies.encrypt.name}`, () => {
8
- test.test("return encrypted string in correct format", async () => {
9
- const value = "hello world"
10
-
11
- const result = await Effect.runPromise(
12
- EncryptedCookies.encrypt(value, { secret: "test-secret" }),
13
- )
14
-
15
- // Check format: three base64url segments separated by .
16
- const segments = result.split(".")
17
- test
18
- .expect(segments)
19
- .toHaveLength(3)
20
-
21
- // Each segment should be base64url (no +, /, or = characters
22
- // so cookie values are not escaped)
23
- segments.forEach((segment: string) => {
24
- test
25
- .expect(segment)
26
- .not
27
- .toMatch(/[+/=]/)
28
- // Should be valid base64url that can be decoded
29
- const base64 = segment.replace(/-/g, "+").replace(/_/g, "/")
30
- const paddedBase64 = base64 + "=".repeat((4 - base64.length % 4) % 4)
31
- test
32
- .expect(() => atob(paddedBase64))
33
- .not
34
- .toThrow()
35
- })
36
- })
37
-
38
- test.test("produce different results for same input due to random IV", async () => {
39
- const value = "same value"
40
-
41
- const result1 = await Effect.runPromise(
42
- EncryptedCookies.encrypt(value, { secret: "test-secret" }),
43
- )
44
- const result2 = await Effect.runPromise(
45
- EncryptedCookies.encrypt(value, { secret: "test-secret" }),
46
- )
47
-
48
- test
49
- .expect(result1)
50
- .not
51
- .toBe(result2)
52
-
53
- // But both should have correct format
54
- test
55
- .expect(result1.split("."))
56
- .toHaveLength(3)
57
- test
58
- .expect(result2.split("."))
59
- .toHaveLength(3)
60
- })
61
-
62
- test.test("handle empty string", async () => {
63
- const value = ""
64
-
65
- const result = await Effect.runPromise(
66
- EncryptedCookies.encrypt(value, { secret: "test-secret" }),
67
- )
68
-
69
- test
70
- .expect(result.split("."))
71
- .toHaveLength(3)
72
- })
73
-
74
- test.test("handle special characters", async () => {
75
- const value = "hello 世界! @#$%^&*()"
76
-
77
- const result = await Effect.runPromise(
78
- EncryptedCookies.encrypt(value, { secret: "test-secret" }),
79
- )
80
-
81
- test
82
- .expect(result.split("."))
83
- .toHaveLength(3)
84
- })
85
-
86
- test.test("handle object with undefined properties", async () => {
87
- const value = { id: "some", optional: undefined }
88
-
89
- const encrypted = await Effect.runPromise(
90
- EncryptedCookies.encrypt(value, { secret: "test-secret" }),
91
- )
92
- const decrypted = await Effect.runPromise(
93
- EncryptedCookies.decrypt(encrypted, { secret: "test-secret" }),
94
- )
95
-
96
- // JSON.stringify removes undefined properties
97
- test
98
- .expect(decrypted)
99
- .toEqual({ id: "some" })
100
- })
101
- })
102
-
103
- test.describe(`${EncryptedCookies.decrypt.name}`, () => {
104
- test.test("decrypt encrypted string successfully", async () => {
105
- const originalValue = "hello world"
106
-
107
- const encrypted = await Effect.runPromise(
108
- EncryptedCookies.encrypt(originalValue, { secret: "test-secret" }),
109
- )
110
- const decrypted = await Effect.runPromise(
111
- EncryptedCookies.decrypt(encrypted, { secret: "test-secret" }),
112
- )
113
-
114
- test
115
- .expect(decrypted)
116
- .toBe(originalValue)
117
- })
118
-
119
- test.test("handle empty string round-trip", async () => {
120
- const originalValue = ""
121
-
122
- const encrypted = await Effect.runPromise(
123
- EncryptedCookies.encrypt(originalValue, { secret: "test-secret" }),
124
- )
125
- const decrypted = await Effect.runPromise(
126
- EncryptedCookies.decrypt(encrypted, { secret: "test-secret" }),
127
- )
128
-
129
- test
130
- .expect(decrypted)
131
- .toBe(originalValue)
132
- })
133
-
134
- test.test("handle special characters round-trip", async () => {
135
- const originalValue = "hello 世界! @#$%^&*()"
136
-
137
- const encrypted = await Effect.runPromise(
138
- EncryptedCookies.encrypt(originalValue, { secret: "test-secret" }),
139
- )
140
- const decrypted = await Effect.runPromise(
141
- EncryptedCookies.decrypt(encrypted, { secret: "test-secret" }),
142
- )
143
-
144
- test
145
- .expect(decrypted)
146
- .toBe(originalValue)
147
- })
148
-
149
- test.test("fail with invalid format", () => {
150
- const invalidValue = "not-encrypted"
151
-
152
- test
153
- .expect(
154
- Effect.runPromise(
155
- EncryptedCookies.decrypt(invalidValue, { secret: "test-secret" }),
156
- ),
157
- )
158
- .rejects
159
- .toThrow()
160
- })
161
-
162
- test.test("fail with wrong number of segments", () => {
163
- const invalidValue = "one.two"
164
-
165
- test
166
- .expect(
167
- Effect.runPromise(
168
- EncryptedCookies.decrypt(invalidValue, { secret: "test-secret" }),
169
- ),
170
- )
171
- .rejects
172
- .toThrow()
173
- })
174
-
175
- test.test("fail with invalid base64", () => {
176
- const invalidValue = "invalid.base64.data"
177
-
178
- test
179
- .expect(
180
- Effect.runPromise(
181
- EncryptedCookies.decrypt(invalidValue, { secret: "test-secret" }),
182
- ),
183
- )
184
- .rejects
185
- .toThrow()
186
- })
187
-
188
- test.test("fail with null value", () => {
189
- test
190
- .expect(
191
- Effect.runPromise(
192
- EncryptedCookies.encrypt(null, { secret: "test-secret" }),
193
- ),
194
- )
195
- .rejects
196
- .toThrow()
197
- })
198
-
199
- test.test("fail with undefined value", () => {
200
- test
201
- .expect(
202
- Effect.runPromise(
203
- EncryptedCookies.encrypt(undefined, { secret: "test-secret" }),
204
- ),
205
- )
206
- .rejects
207
- .toThrow()
208
- })
209
-
210
- test.test("fail with empty encrypted value", () => {
211
- test
212
- .expect(
213
- Effect.runPromise(
214
- EncryptedCookies.decrypt("", { secret: "test-secret" }),
215
- ),
216
- )
217
- .rejects
218
- .toThrow()
219
- })
220
- })
221
-
222
- test.describe(`${EncryptedCookies.encryptCookie.name}`, () => {
223
- test.test("preserve cookie properties and encrypt value", async () => {
224
- const cookie = Cookies.unsafeMakeCookie("test", "hello world")
225
-
226
- const result = await Effect.runPromise(
227
- EncryptedCookies.encryptCookie(cookie, { secret: "test-secret" }),
228
- )
229
-
230
- // Cookie properties should be preserved
231
- test
232
- .expect(result.name)
233
- .toBe("test")
234
-
235
- // Value should be encrypted (different from original)
236
- test
237
- .expect(result.value)
238
- .not
239
- .toBe("hello world")
240
-
241
- // Should be in encrypted format
242
- test
243
- .expect(result.value.split("."))
244
- .toHaveLength(3)
245
- })
246
- })
247
-
248
- test.describe(`${EncryptedCookies.decryptCookie.name}`, () => {
249
- test.test("preserve cookie properties and decrypt value", async () => {
250
- const originalCookie = Cookies.unsafeMakeCookie("test", "hello world")
251
-
252
- const encrypted = await Effect.runPromise(
253
- EncryptedCookies.encryptCookie(originalCookie, { secret: "test-secret" }),
254
- )
255
- const decrypted = await Effect.runPromise(
256
- EncryptedCookies.decryptCookie(encrypted, { secret: "test-secret" }),
257
- )
258
-
259
- // Cookie properties should be preserved
260
- test
261
- .expect(decrypted.name)
262
- .toBe("test")
263
-
264
- // Value should be JSON stringified (string values are now always serialized)
265
- test
266
- .expect(decrypted.value)
267
- .toBe("\"hello world\"")
268
- })
269
- })
270
-
271
- test.describe("service", () => {
272
- test.test("service uses pre-calculated key material", async () => {
273
- const testSecret = "test-secret-key"
274
- const testValue = "hello world"
275
-
276
- const program = Effect.gen(function*() {
277
- const service = yield* EncryptedCookies.EncryptedCookies
278
-
279
- const encrypted = yield* service.encrypt(testValue)
280
- const decrypted = yield* service.decrypt(encrypted)
281
-
282
- return { encrypted, decrypted }
283
- })
284
-
285
- const result = await Effect.runPromise(
286
- program.pipe(
287
- Effect.provide(EncryptedCookies.layer({ secret: testSecret })),
288
- ),
289
- )
290
-
291
- test
292
- .expect(result.decrypted)
293
- .toBe(testValue)
294
- test
295
- .expect(result.encrypted)
296
- .not
297
- .toBe(testValue)
298
- test
299
- .expect(result.encrypted.split("."))
300
- .toHaveLength(3)
301
- })
302
-
303
- test.test("service cookie functions work with pre-calculated key", async () => {
304
- const testSecret = "test-secret-key"
305
- const originalCookie = Cookies.unsafeMakeCookie("test", "hello world")
306
-
307
- const program = Effect.gen(function*() {
308
- const service = yield* EncryptedCookies.EncryptedCookies
309
-
310
- const encrypted = yield* service.encryptCookie(originalCookie)
311
- const decrypted = yield* service.decryptCookie(encrypted)
312
-
313
- return { encrypted, decrypted }
314
- })
315
-
316
- const result = await Effect.runPromise(
317
- program.pipe(
318
- Effect.provide(EncryptedCookies.layer({ secret: testSecret })),
319
- ),
320
- )
321
-
322
- test
323
- .expect(result.decrypted.name)
324
- .toBe("test")
325
- test
326
- .expect(result.decrypted.value)
327
- .toBe("\"hello world\"")
328
- test
329
- .expect(result.encrypted.value)
330
- .not
331
- .toBe("hello world")
332
- })
333
-
334
- test.test("functions work with pre-derived keys passed as options", async () => {
335
- const testSecret = "test-secret-key"
336
- const testValue = "hello world"
337
-
338
- // Pre-derive keys manually
339
- const program = Effect.gen(function*() {
340
- const keyMaterial = yield* Effect.tryPromise({
341
- try: () =>
342
- crypto.subtle.importKey(
343
- "raw",
344
- new TextEncoder().encode(testSecret),
345
- { name: "HKDF" },
346
- false,
347
- ["deriveKey"],
348
- ),
349
- catch: (error) => error,
350
- })
351
-
352
- const encryptKey = yield* Effect.tryPromise({
353
- try: () =>
354
- crypto.subtle.deriveKey(
355
- {
356
- name: "HKDF",
357
- salt: new TextEncoder().encode("cookie-encryption"),
358
- info: new TextEncoder().encode("aes-256-gcm"),
359
- hash: "SHA-256",
360
- },
361
- keyMaterial,
362
- { name: "AES-GCM", length: 256 },
363
- false,
364
- ["encrypt"],
365
- ),
366
- catch: (error) => error,
367
- })
368
-
369
- const decryptKey = yield* Effect.tryPromise({
370
- try: () =>
371
- crypto.subtle.deriveKey(
372
- {
373
- name: "HKDF",
374
- salt: new TextEncoder().encode("cookie-encryption"),
375
- info: new TextEncoder().encode("aes-256-gcm"),
376
- hash: "SHA-256",
377
- },
378
- keyMaterial,
379
- { name: "AES-GCM", length: 256 },
380
- false,
381
- ["decrypt"],
382
- ),
383
- catch: (error) => error,
384
- })
385
-
386
- // Use functions with pre-derived keys
387
- const encrypted = yield* EncryptedCookies.encrypt(testValue, {
388
- key: encryptKey,
389
- })
390
- const decrypted = yield* EncryptedCookies.decrypt(encrypted, {
391
- key: decryptKey,
392
- })
393
-
394
- return { encrypted, decrypted }
395
- })
396
-
397
- const result = await Effect.runPromise(program)
398
-
399
- test
400
- .expect(result.decrypted)
401
- .toBe(testValue)
402
- test
403
- .expect(result.encrypted)
404
- .not
405
- .toBe(testValue)
406
- test
407
- .expect(result.encrypted.split("."))
408
- .toHaveLength(3)
409
- })
410
- })
411
-
412
- test.describe("layerConfig", () => {
413
- test.test("succeed with valid SECRET_KEY_BASE", async () => {
414
- const validSecret = "a".repeat(40)
415
-
416
- const program = Effect.gen(function*() {
417
- const service = yield* EncryptedCookies.EncryptedCookies
418
- const encrypted = yield* service.encrypt("test")
419
- const decrypted = yield* service.decrypt(encrypted)
420
- return decrypted
421
- })
422
-
423
- const result = await Effect.runPromise(
424
- program.pipe(
425
- Effect.provide(
426
- EncryptedCookies.layerConfig("SECRET_KEY_BASE"),
427
- ),
428
- Effect.withConfigProvider(
429
- ConfigProvider.fromMap(
430
- new Map([["SECRET_KEY_BASE", validSecret]]),
431
- ),
432
- ),
433
- ),
434
- )
435
-
436
- test
437
- .expect(result)
438
- .toBe("test")
439
- })
440
-
441
- test.test("fail with short SECRET_KEY_BASE", async () => {
442
- const shortSecret = "short"
443
-
444
- const program = Effect.gen(function*() {
445
- const service = yield* EncryptedCookies.EncryptedCookies
446
- return yield* service.encrypt("test")
447
- })
448
-
449
- test
450
- .expect(
451
- Effect.runPromise(
452
- program.pipe(
453
- Effect.provide(
454
- EncryptedCookies.layerConfig("SECRET_KEY_BASE"),
455
- ),
456
- Effect.withConfigProvider(
457
- ConfigProvider.fromMap(
458
- new Map([["SECRET_KEY_BASE", shortSecret]]),
459
- ),
460
- ),
461
- ),
462
- ),
463
- )
464
- .rejects
465
- .toThrow("SECRET_KEY_BASE must be at least 40 characters")
466
- })
467
-
468
- test.test("fail with missing SECRET_KEY_BASE", async () => {
469
- const program = Effect.gen(function*() {
470
- const service = yield* EncryptedCookies.EncryptedCookies
471
- return yield* service.encrypt("test")
472
- })
473
-
474
- test
475
- .expect(
476
- Effect.runPromise(
477
- program.pipe(
478
- Effect.provide(
479
- EncryptedCookies.layerConfig("SECRET_KEY_BASE"),
480
- ),
481
- Effect.withConfigProvider(ConfigProvider.fromMap(new Map())),
482
- ),
483
- ),
484
- )
485
- .rejects
486
- .toThrow("SECRET_KEY_BASE must be at least 40 characters")
487
- })
488
- })
@@ -1,209 +0,0 @@
1
- import * as test from "bun:test"
2
- import * as HyperHtml from "./HyperHtml.ts"
3
- import * as HyperNode from "./HyperNode.ts"
4
-
5
- test.it("boolean true attributes render without value (React-like)", () => {
6
- const node = HyperNode.make("div", {
7
- hidden: true,
8
- disabled: true,
9
- "data-active": true,
10
- })
11
-
12
- const html = HyperHtml.renderToString(node)
13
-
14
- test
15
- .expect(html)
16
- .toBe("<div hidden disabled data-active></div>")
17
- })
18
-
19
- test.it("boolean false attributes are omitted", () => {
20
- const node = HyperNode.make("div", {
21
- hidden: false,
22
- disabled: false,
23
- "data-active": false,
24
- })
25
-
26
- const html = HyperHtml.renderToString(node)
27
-
28
- test
29
- .expect(html)
30
- .toBe("<div></div>")
31
- })
32
-
33
- test.it("string attributes render with values", () => {
34
- const node = HyperNode.make("div", {
35
- id: "test",
36
- class: "my-class",
37
- "data-value": "hello",
38
- })
39
-
40
- const html = HyperHtml.renderToString(node)
41
-
42
- test
43
- .expect(html)
44
- .toBe("<div id=\"test\" class=\"my-class\" data-value=\"hello\"></div>")
45
- })
46
-
47
- test.it("number attributes render with values", () => {
48
- const node = HyperNode.make("input", {
49
- type: "number",
50
- min: 0,
51
- max: 100,
52
- value: 50,
53
- })
54
-
55
- const html = HyperHtml.renderToString(node)
56
-
57
- test
58
- .expect(html)
59
- .toBe("<input type=\"number\" min=\"0\" max=\"100\" value=\"50\">")
60
- })
61
-
62
- test.it("null and undefined attributes are omitted", () => {
63
- const node = HyperNode.make("div", {
64
- id: null,
65
- class: undefined,
66
- "data-test": "value",
67
- })
68
-
69
- const html = HyperHtml.renderToString(node)
70
-
71
- test
72
- .expect(html)
73
- .toBe("<div data-test=\"value\"></div>")
74
- })
75
-
76
- test.it("mixed boolean and string attributes", () => {
77
- const node = HyperNode.make("input", {
78
- type: "checkbox",
79
- checked: true,
80
- disabled: false,
81
- name: "test",
82
- value: "on",
83
- })
84
-
85
- const html = HyperHtml.renderToString(node)
86
-
87
- test
88
- .expect(html)
89
- .toBe("<input type=\"checkbox\" checked name=\"test\" value=\"on\">")
90
- })
91
-
92
- test.it("data-* attributes with object values are JSON stringified", () => {
93
- const node = HyperNode.make("div", {
94
- "data-signals": {
95
- draft: "",
96
- pendingDraft: "",
97
- username: "User123",
98
- },
99
- })
100
-
101
- const html = HyperHtml.renderToString(node)
102
-
103
- test
104
- .expect(html)
105
- .toBe(
106
- "<div data-signals=\"{&quot;draft&quot;:&quot;&quot;,&quot;pendingDraft&quot;:&quot;&quot;,&quot;username&quot;:&quot;User123&quot;}\"></div>",
107
- )
108
- })
109
-
110
- test.it("data-* attributes with array values are JSON stringified", () => {
111
- const node = HyperNode.make("div", {
112
- "data-items": [1, 2, 3],
113
- })
114
-
115
- const html = HyperHtml.renderToString(node)
116
-
117
- test
118
- .expect(html)
119
- .toBe("<div data-items=\"[1,2,3]\"></div>")
120
- })
121
-
122
- test.it("data-* attributes with nested object values", () => {
123
- const node = HyperNode.make("div", {
124
- "data-config": {
125
- user: { name: "John", active: true },
126
- settings: { theme: "dark" },
127
- },
128
- })
129
-
130
- const html = HyperHtml.renderToString(node)
131
-
132
- test
133
- .expect(html)
134
- .toBe(
135
- "<div data-config=\"{&quot;user&quot;:{&quot;name&quot;:&quot;John&quot;,&quot;active&quot;:true},&quot;settings&quot;:{&quot;theme&quot;:&quot;dark&quot;}}\"></div>",
136
- )
137
- })
138
-
139
- test.it("data-* string values are not JSON stringified", () => {
140
- const node = HyperNode.make("div", {
141
- "data-value": "hello world",
142
- })
143
-
144
- const html = HyperHtml.renderToString(node)
145
-
146
- test
147
- .expect(html)
148
- .toBe("<div data-value=\"hello world\"></div>")
149
- })
150
-
151
- test.it("non-data attributes with object values are not JSON stringified", () => {
152
- const node = HyperNode.make("div", {
153
- style: "color: red",
154
- })
155
-
156
- const html = HyperHtml.renderToString(node)
157
-
158
- test
159
- .expect(html)
160
- .toBe("<div style=\"color: red\"></div>")
161
- })
162
-
163
- test.it("script with function child renders as IIFE", () => {
164
- const handler = (window: Window) => {
165
- console.log("Hello from", window.document.title)
166
- }
167
-
168
- const node = HyperNode.make("script", {
169
- children: handler,
170
- })
171
-
172
- const html = HyperHtml.renderToString(node)
173
-
174
- test
175
- .expect(html)
176
- .toBe(`<script>(${handler.toString()})(window)</script>`)
177
- })
178
-
179
- test.it("script with arrow function child renders as IIFE", () => {
180
- const node = HyperNode.make("script", {
181
- children: (window: Window) => {
182
- window.alert("test")
183
- },
184
- })
185
-
186
- const html = HyperHtml.renderToString(node)
187
-
188
- test
189
- .expect(html)
190
- .toContain("<script>(")
191
- test
192
- .expect(html)
193
- .toContain(")(window)</script>")
194
- test
195
- .expect(html)
196
- .toContain("window.alert")
197
- })
198
-
199
- test.it("script with string child renders normally", () => {
200
- const node = HyperNode.make("script", {
201
- children: "console.log('hello')",
202
- })
203
-
204
- const html = HyperHtml.renderToString(node)
205
-
206
- test
207
- .expect(html)
208
- .toBe("<script>console.log(&apos;hello&apos;)</script>")
209
- })