effect-start 0.9.0 → 0.10.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/package.json +12 -13
- package/src/BundleHttp.test.ts +1 -1
- package/src/Commander.test.ts +15 -15
- package/src/Commander.ts +58 -88
- package/src/EncryptedCookies.test.ts +4 -4
- package/src/FileHttpRouter.test.ts +81 -12
- package/src/FileHttpRouter.ts +115 -26
- package/src/FileRouter.ts +60 -162
- package/src/FileRouterCodegen.test.ts +250 -64
- package/src/FileRouterCodegen.ts +13 -56
- package/src/FileRouterPattern.test.ts +116 -0
- package/src/FileRouterPattern.ts +59 -0
- package/src/FileRouter_path.test.ts +63 -102
- package/src/FileSystemExtra.test.ts +226 -0
- package/src/FileSystemExtra.ts +24 -60
- package/src/HttpUtils.test.ts +68 -0
- package/src/HttpUtils.ts +15 -0
- package/src/HyperHtml.ts +24 -5
- package/src/JsModule.test.ts +1 -1
- package/src/NodeFileSystem.ts +764 -0
- package/src/Random.ts +59 -0
- package/src/Route.test.ts +471 -0
- package/src/Route.ts +298 -153
- package/src/RouteRender.ts +38 -0
- package/src/Router.ts +11 -33
- package/src/RouterPattern.test.ts +629 -0
- package/src/RouterPattern.ts +391 -0
- package/src/Start.ts +14 -52
- package/src/bun/BunBundle.test.ts +0 -3
- package/src/bun/BunHttpServer.ts +246 -0
- package/src/bun/BunHttpServer_web.ts +384 -0
- package/src/bun/BunRoute.test.ts +341 -0
- package/src/bun/BunRoute.ts +326 -0
- package/src/bun/BunRoute_bundles.test.ts +218 -0
- package/src/bun/BunRuntime.ts +33 -0
- package/src/bun/BunTailwindPlugin.test.ts +1 -1
- package/src/bun/_empty.html +1 -0
- package/src/bun/index.ts +2 -1
- package/src/testing.ts +12 -3
- package/src/Datastar.test.ts +0 -267
- package/src/Datastar.ts +0 -68
- package/src/bun/BunFullstackServer.ts +0 -45
- package/src/bun/BunFullstackServer_httpServer.ts +0 -541
- package/src/jsx-datastar.d.ts +0 -63
package/package.json
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "effect-start",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": "./src/index.ts",
|
|
8
8
|
"./Router": "./src/Router.ts",
|
|
9
9
|
"./Route": "./src/Route.ts",
|
|
10
|
-
"./Datastar": "./src/Datastar.ts",
|
|
11
10
|
"./EncryptedCookies": "./src/EncryptedCookies.ts",
|
|
12
11
|
"./bun": "./src/bun/index.ts",
|
|
13
12
|
"./client": "./src/client/index.ts",
|
|
@@ -20,14 +19,14 @@
|
|
|
20
19
|
},
|
|
21
20
|
"scripts": {
|
|
22
21
|
"format": "bunx dprint fmt",
|
|
22
|
+
"test": "bun test src/",
|
|
23
23
|
"deploy": "bunx npm publish --access public"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@effect/platform": "
|
|
27
|
-
"@effect/platform-bun": ">=0.65"
|
|
26
|
+
"@effect/platform": "^0.93.3"
|
|
28
27
|
},
|
|
29
28
|
"peerDependencies": {
|
|
30
|
-
"typescript": "^5.
|
|
29
|
+
"typescript": "^5.9.3",
|
|
31
30
|
"effect": ">=3.16.4"
|
|
32
31
|
},
|
|
33
32
|
"peerDependenciesMeta": {
|
|
@@ -39,15 +38,15 @@
|
|
|
39
38
|
"@dprint/json": "^0.21.0",
|
|
40
39
|
"@dprint/markdown": "^0.20.0",
|
|
41
40
|
"@dprint/typescript": "^0.95.12",
|
|
42
|
-
"@effect/language-service": "^0.
|
|
43
|
-
"@tailwindcss/node": "
|
|
44
|
-
"@types/bun": "^1.
|
|
45
|
-
"@types/react": "^19.
|
|
46
|
-
"@types/react-dom": "^19.
|
|
47
|
-
"dprint-cli": "^0.4.
|
|
41
|
+
"@effect/language-service": "^0.56.0",
|
|
42
|
+
"@tailwindcss/node": "^4.1.17",
|
|
43
|
+
"@types/bun": "^1.3.3",
|
|
44
|
+
"@types/react": "^19.2.7",
|
|
45
|
+
"@types/react-dom": "^19.2.3",
|
|
46
|
+
"dprint-cli": "^0.4.1",
|
|
48
47
|
"dprint-markup": "nounder/dprint-markup",
|
|
49
|
-
"effect": "^3.19.
|
|
50
|
-
"effect-memfs": "
|
|
48
|
+
"effect": "^3.19.6",
|
|
49
|
+
"effect-memfs": "^0.8.0",
|
|
51
50
|
"ts-namespace-import": "nounder/ts-namespace-import#140c405"
|
|
52
51
|
},
|
|
53
52
|
"files": [
|
package/src/BundleHttp.test.ts
CHANGED
package/src/Commander.test.ts
CHANGED
|
@@ -3,7 +3,7 @@ import * as Effect from "effect/Effect"
|
|
|
3
3
|
import * as Schema from "effect/Schema"
|
|
4
4
|
import * as Commander from "./Commander.ts"
|
|
5
5
|
|
|
6
|
-
t.describe(
|
|
6
|
+
t.describe(`${Commander.make.name}`, () => {
|
|
7
7
|
t.it("should create a basic command", () => {
|
|
8
8
|
const cmd = Commander.make({
|
|
9
9
|
name: "test-app",
|
|
@@ -14,7 +14,7 @@ t.describe("make", () => {
|
|
|
14
14
|
})
|
|
15
15
|
})
|
|
16
16
|
|
|
17
|
-
t.describe(
|
|
17
|
+
t.describe(`${Commander.option.name} - nested builder API`, () => {
|
|
18
18
|
t.it("should add an option with schema", () => {
|
|
19
19
|
const cmd = Commander
|
|
20
20
|
.make({ name: "app" })
|
|
@@ -76,7 +76,7 @@ t.describe("option - nested builder API", () => {
|
|
|
76
76
|
})
|
|
77
77
|
})
|
|
78
78
|
|
|
79
|
-
t.describe(
|
|
79
|
+
t.describe(`${Commander.parse.name} - kebab-to-camel conversion`, () => {
|
|
80
80
|
t.it("should convert kebab-case to camelCase", async () => {
|
|
81
81
|
const cmd = Commander
|
|
82
82
|
.make({ name: "app" })
|
|
@@ -198,7 +198,7 @@ t.describe("parse - kebab-to-camel conversion", () => {
|
|
|
198
198
|
})
|
|
199
199
|
})
|
|
200
200
|
|
|
201
|
-
t.describe(
|
|
201
|
+
t.describe(`${Commander.optionHelp.name}`, () => {
|
|
202
202
|
t.it("should add help option", () => {
|
|
203
203
|
const cmd = Commander
|
|
204
204
|
.make({ name: "app" })
|
|
@@ -210,7 +210,7 @@ t.describe("optionHelp", () => {
|
|
|
210
210
|
})
|
|
211
211
|
})
|
|
212
212
|
|
|
213
|
-
t.describe(
|
|
213
|
+
t.describe(`${Commander.optionVersion.name}`, () => {
|
|
214
214
|
t.it("should add version option", () => {
|
|
215
215
|
const cmd = Commander
|
|
216
216
|
.make({ name: "app", version: "1.0.0" })
|
|
@@ -222,7 +222,7 @@ t.describe("optionVersion", () => {
|
|
|
222
222
|
})
|
|
223
223
|
})
|
|
224
224
|
|
|
225
|
-
t.describe(
|
|
225
|
+
t.describe(`${Commander.handle.name}`, () => {
|
|
226
226
|
t.it("should mark command as handled", () => {
|
|
227
227
|
const handled = Commander
|
|
228
228
|
.make({ name: "app" })
|
|
@@ -246,7 +246,7 @@ t.describe("handle", () => {
|
|
|
246
246
|
})
|
|
247
247
|
})
|
|
248
248
|
|
|
249
|
-
t.describe(
|
|
249
|
+
t.describe(`${Commander.subcommand.name}`, () => {
|
|
250
250
|
t.it("should add subcommand", () => {
|
|
251
251
|
const subCmd = Commander
|
|
252
252
|
.make({ name: "format" })
|
|
@@ -266,7 +266,7 @@ t.describe("subcommand", () => {
|
|
|
266
266
|
})
|
|
267
267
|
})
|
|
268
268
|
|
|
269
|
-
t.describe(
|
|
269
|
+
t.describe(`${Commander.help.name}`, () => {
|
|
270
270
|
t.it("should generate help text", () => {
|
|
271
271
|
const cmd = Commander
|
|
272
272
|
.make({
|
|
@@ -309,7 +309,7 @@ t.describe("BooleanFromString", () => {
|
|
|
309
309
|
})
|
|
310
310
|
})
|
|
311
311
|
|
|
312
|
-
t.describe(
|
|
312
|
+
t.describe(`${Commander.choice.name}`, () => {
|
|
313
313
|
t.it("should accept valid choice", async () => {
|
|
314
314
|
const ColorSchema = Schema.compose(
|
|
315
315
|
Schema.String,
|
|
@@ -337,7 +337,7 @@ t.describe("choice", () => {
|
|
|
337
337
|
})
|
|
338
338
|
})
|
|
339
339
|
|
|
340
|
-
t.describe(
|
|
340
|
+
t.describe(`${Commander.repeatable.name}`, () => {
|
|
341
341
|
t.it("should parse comma-separated values", async () => {
|
|
342
342
|
const schema = Commander.repeatable(Schema.String)
|
|
343
343
|
|
|
@@ -452,7 +452,7 @@ t.describe("integration", () => {
|
|
|
452
452
|
})
|
|
453
453
|
})
|
|
454
454
|
|
|
455
|
-
t.describe(
|
|
455
|
+
t.describe(`${Commander.parse.name} - comprehensive`, () => {
|
|
456
456
|
t.it("should parse with explicit args", async () => {
|
|
457
457
|
const cmd = Commander
|
|
458
458
|
.make({ name: "app" })
|
|
@@ -845,7 +845,7 @@ t.describe("action/handler", () => {
|
|
|
845
845
|
})
|
|
846
846
|
})
|
|
847
847
|
|
|
848
|
-
t.describe(
|
|
848
|
+
t.describe(`${Commander.optionVersion.name} - version behavior`, () => {
|
|
849
849
|
t.it("should include version in command definition", () => {
|
|
850
850
|
const cmd = Commander
|
|
851
851
|
.make({ name: "app", version: "1.0.0" })
|
|
@@ -860,7 +860,7 @@ t.describe("version", () => {
|
|
|
860
860
|
.make({ name: "app", version: "2.0.0" })
|
|
861
861
|
|
|
862
862
|
t.expect(cmd.version).toBe("2.0.0")
|
|
863
|
-
t.expect(
|
|
863
|
+
t.expect(cmd.options["version"]).toBeUndefined()
|
|
864
864
|
})
|
|
865
865
|
|
|
866
866
|
t.it("should include version option in help", () => {
|
|
@@ -875,7 +875,7 @@ t.describe("version", () => {
|
|
|
875
875
|
})
|
|
876
876
|
})
|
|
877
877
|
|
|
878
|
-
t.describe(
|
|
878
|
+
t.describe(`${Commander.help.name} - comprehensive`, () => {
|
|
879
879
|
t.it("should generate help with description", () => {
|
|
880
880
|
const cmd = Commander
|
|
881
881
|
.make({
|
|
@@ -951,7 +951,7 @@ t.describe("help - comprehensive", () => {
|
|
|
951
951
|
})
|
|
952
952
|
})
|
|
953
953
|
|
|
954
|
-
t.describe(
|
|
954
|
+
t.describe(`${Commander.subcommand.name} - comprehensive`, () => {
|
|
955
955
|
t.it("should add subcommand", () => {
|
|
956
956
|
const subCmd = Commander
|
|
957
957
|
.make({ name: "build" })
|
package/src/Commander.ts
CHANGED
|
@@ -172,6 +172,19 @@ export interface SubcommandDef<Handled extends boolean = boolean> {
|
|
|
172
172
|
readonly command: CommanderSet<any, any, Handled>
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
+
type Extend<
|
|
176
|
+
S,
|
|
177
|
+
NewOpts extends OptionsMap,
|
|
178
|
+
NewSubs extends ReadonlyArray<SubcommandDef> = [],
|
|
179
|
+
Handled extends boolean = false,
|
|
180
|
+
> = S extends CommanderSet<infer Opts, infer Subs, infer _H> ? CommanderSet<
|
|
181
|
+
& Opts
|
|
182
|
+
& NewOpts,
|
|
183
|
+
[...Subs, ...NewSubs],
|
|
184
|
+
Handled
|
|
185
|
+
>
|
|
186
|
+
: CommanderSet<NewOpts, NewSubs, Handled>
|
|
187
|
+
|
|
175
188
|
type CommanderBuilder = {
|
|
176
189
|
option: typeof optionMethod
|
|
177
190
|
optionHelp: typeof optionHelp
|
|
@@ -222,26 +235,13 @@ const optionMethod = function<
|
|
|
222
235
|
>(
|
|
223
236
|
this: S,
|
|
224
237
|
opt: Opt,
|
|
225
|
-
): S
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
[K in Opt["name"] as OptionNameToCamelCase<K>]: Opt
|
|
229
|
-
},
|
|
230
|
-
Subs,
|
|
231
|
-
false
|
|
232
|
-
>
|
|
233
|
-
: CommanderSet<
|
|
234
|
-
{
|
|
235
|
-
[K in Opt["name"] as OptionNameToCamelCase<K>]: Opt
|
|
236
|
-
},
|
|
237
|
-
[],
|
|
238
|
-
false
|
|
238
|
+
): Extend<S, { [K in Opt["name"] as OptionNameToCamelCase<K>]: Opt }> {
|
|
239
|
+
const base = (this && typeof this === "object" ? this : {}) as Partial<
|
|
240
|
+
CommanderSet.Instance
|
|
239
241
|
>
|
|
240
|
-
|
|
241
|
-
const
|
|
242
|
-
const
|
|
243
|
-
const baseOptions: OptionsMap = base.options || {}
|
|
244
|
-
const baseSubcommands = base.subcommands || []
|
|
242
|
+
const baseName = base.name ?? ""
|
|
243
|
+
const baseOptions: OptionsMap = base.options ?? {}
|
|
244
|
+
const baseSubcommands = base.subcommands ?? []
|
|
245
245
|
const baseDescription = base.description
|
|
246
246
|
const baseVersion = base.version
|
|
247
247
|
|
|
@@ -253,31 +253,18 @@ const optionMethod = function<
|
|
|
253
253
|
version: baseVersion,
|
|
254
254
|
options: { ...baseOptions, [camelKey]: opt },
|
|
255
255
|
subcommands: baseSubcommands,
|
|
256
|
-
}) as
|
|
256
|
+
}) as Extend<S, { [K in Opt["name"] as OptionNameToCamelCase<K>]: Opt }>
|
|
257
257
|
}
|
|
258
258
|
|
|
259
259
|
export const optionHelp = function<S>(
|
|
260
260
|
this: S,
|
|
261
|
-
): S
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
"help": OptionBuilder<boolean, "--help">
|
|
265
|
-
},
|
|
266
|
-
Subs,
|
|
267
|
-
false
|
|
268
|
-
>
|
|
269
|
-
: CommanderSet<
|
|
270
|
-
{
|
|
271
|
-
"help": OptionBuilder<boolean, "--help">
|
|
272
|
-
},
|
|
273
|
-
[],
|
|
274
|
-
false
|
|
261
|
+
): Extend<S, { "help": OptionBuilder<boolean, "--help"> }> {
|
|
262
|
+
const base = (this && typeof this === "object" ? this : {}) as Partial<
|
|
263
|
+
CommanderSet.Instance
|
|
275
264
|
>
|
|
276
|
-
|
|
277
|
-
const
|
|
278
|
-
const
|
|
279
|
-
const baseOptions: OptionsMap = base.options || {}
|
|
280
|
-
const baseSubcommands = base.subcommands || []
|
|
265
|
+
const baseName = base.name ?? ""
|
|
266
|
+
const baseOptions: OptionsMap = base.options ?? {}
|
|
267
|
+
const baseSubcommands = base.subcommands ?? []
|
|
281
268
|
const baseDescription = base.description
|
|
282
269
|
const baseVersion = base.version
|
|
283
270
|
|
|
@@ -296,31 +283,18 @@ export const optionHelp = function<S>(
|
|
|
296
283
|
version: baseVersion,
|
|
297
284
|
options: { ...baseOptions, help: helpOption },
|
|
298
285
|
subcommands: baseSubcommands,
|
|
299
|
-
}) as
|
|
286
|
+
}) as Extend<S, { "help": OptionBuilder<boolean, "--help"> }>
|
|
300
287
|
}
|
|
301
288
|
|
|
302
289
|
export const optionVersion = function<S>(
|
|
303
290
|
this: S,
|
|
304
|
-
): S
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
"version": OptionBuilder<boolean, "--version">
|
|
308
|
-
},
|
|
309
|
-
Subs,
|
|
310
|
-
false
|
|
311
|
-
>
|
|
312
|
-
: CommanderSet<
|
|
313
|
-
{
|
|
314
|
-
"version": OptionBuilder<boolean, "--version">
|
|
315
|
-
},
|
|
316
|
-
[],
|
|
317
|
-
false
|
|
291
|
+
): Extend<S, { "version": OptionBuilder<boolean, "--version"> }> {
|
|
292
|
+
const base = (this && typeof this === "object" ? this : {}) as Partial<
|
|
293
|
+
CommanderSet.Instance
|
|
318
294
|
>
|
|
319
|
-
|
|
320
|
-
const
|
|
321
|
-
const
|
|
322
|
-
const baseOptions: OptionsMap = base.options || {}
|
|
323
|
-
const baseSubcommands = base.subcommands || []
|
|
295
|
+
const baseName = base.name ?? ""
|
|
296
|
+
const baseOptions: OptionsMap = base.options ?? {}
|
|
297
|
+
const baseSubcommands = base.subcommands ?? []
|
|
324
298
|
const baseDescription = base.description
|
|
325
299
|
const baseVersion = base.version
|
|
326
300
|
|
|
@@ -339,7 +313,7 @@ export const optionVersion = function<S>(
|
|
|
339
313
|
version: baseVersion,
|
|
340
314
|
options: { ...baseOptions, version: versionOption },
|
|
341
315
|
subcommands: baseSubcommands,
|
|
342
|
-
}) as
|
|
316
|
+
}) as Extend<S, { "version": OptionBuilder<boolean, "--version"> }>
|
|
343
317
|
}
|
|
344
318
|
|
|
345
319
|
export const subcommand = function<
|
|
@@ -350,27 +324,19 @@ export const subcommand = function<
|
|
|
350
324
|
>(
|
|
351
325
|
this: S,
|
|
352
326
|
cmd: CommanderSet<SubOpts, SubSubs, SubHandled>,
|
|
353
|
-
): S
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
false
|
|
327
|
+
): Extend<S, {}, [SubcommandDef<SubHandled>]> {
|
|
328
|
+
const base = (this && typeof this === "object" ? this : {}) as Partial<
|
|
329
|
+
CommanderSet.Instance
|
|
357
330
|
>
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
false
|
|
362
|
-
>
|
|
363
|
-
{
|
|
364
|
-
const base = this && typeof this === "object" ? this as any : {}
|
|
365
|
-
const baseName = base.name || ""
|
|
366
|
-
const baseOptions = base.options || {}
|
|
367
|
-
const baseSubcommands = base.subcommands || []
|
|
331
|
+
const baseName = base.name ?? ""
|
|
332
|
+
const baseOptions = base.options ?? {}
|
|
333
|
+
const baseSubcommands = base.subcommands ?? []
|
|
368
334
|
const baseDescription = base.description
|
|
369
335
|
const baseVersion = base.version
|
|
370
336
|
|
|
371
|
-
const subDef: SubcommandDef = {
|
|
337
|
+
const subDef: SubcommandDef<SubHandled> = {
|
|
372
338
|
_tag: "SubcommandDef",
|
|
373
|
-
command: cmd
|
|
339
|
+
command: cmd,
|
|
374
340
|
}
|
|
375
341
|
|
|
376
342
|
return makeSet({
|
|
@@ -378,8 +344,8 @@ export const subcommand = function<
|
|
|
378
344
|
description: baseDescription,
|
|
379
345
|
version: baseVersion,
|
|
380
346
|
options: baseOptions,
|
|
381
|
-
subcommands: [...baseSubcommands, subDef]
|
|
382
|
-
}) as
|
|
347
|
+
subcommands: [...baseSubcommands, subDef],
|
|
348
|
+
}) as Extend<S, {}, [SubcommandDef<SubHandled>]>
|
|
383
349
|
}
|
|
384
350
|
|
|
385
351
|
export const handle = function<
|
|
@@ -389,16 +355,16 @@ export const handle = function<
|
|
|
389
355
|
this: CommanderSet<Opts, Subs, false>,
|
|
390
356
|
handler: (args: ExtractOptionValues<Opts>) => Effect.Effect<void>,
|
|
391
357
|
): CommanderSet<Opts, Subs, true> {
|
|
392
|
-
const base = this
|
|
358
|
+
const base = this as CommanderSet.Instance<Opts, Subs, false>
|
|
393
359
|
|
|
394
|
-
return makeSet({
|
|
395
|
-
name: base.name
|
|
360
|
+
return makeSet<Opts, Subs, true>({
|
|
361
|
+
name: base.name,
|
|
396
362
|
description: base.description,
|
|
397
363
|
version: base.version,
|
|
398
|
-
options: base.options
|
|
399
|
-
subcommands: base.subcommands
|
|
400
|
-
handler
|
|
401
|
-
})
|
|
364
|
+
options: base.options,
|
|
365
|
+
subcommands: base.subcommands,
|
|
366
|
+
handler,
|
|
367
|
+
})
|
|
402
368
|
}
|
|
403
369
|
|
|
404
370
|
export const make = <const Name extends string>(config: {
|
|
@@ -589,12 +555,16 @@ export const runMain = <
|
|
|
589
555
|
|
|
590
556
|
const parsedOptions = yield* parse(cmd, args)
|
|
591
557
|
|
|
592
|
-
if ((parsedOptions
|
|
558
|
+
if (Predicate.hasProperty(parsedOptions, "help") && parsedOptions.help) {
|
|
593
559
|
console.log(generateHelp(cmd))
|
|
594
560
|
return
|
|
595
561
|
}
|
|
596
562
|
|
|
597
|
-
if (
|
|
563
|
+
if (
|
|
564
|
+
Predicate.hasProperty(parsedOptions, "version")
|
|
565
|
+
&& parsedOptions.version
|
|
566
|
+
&& cmd.version
|
|
567
|
+
) {
|
|
598
568
|
console.log(`${cmd.name} v${cmd.version}`)
|
|
599
569
|
return
|
|
600
570
|
}
|
|
@@ -669,4 +639,4 @@ export const repeatable = <A>(
|
|
|
669
639
|
})
|
|
670
640
|
.pipe(
|
|
671
641
|
Schema.compose(Schema.Array(schema)),
|
|
672
|
-
)
|
|
642
|
+
)
|
|
@@ -4,7 +4,7 @@ import * as ConfigProvider from "effect/ConfigProvider"
|
|
|
4
4
|
import * as Effect from "effect/Effect"
|
|
5
5
|
import * as EncryptedCookies from "./EncryptedCookies.ts"
|
|
6
6
|
|
|
7
|
-
t.describe(
|
|
7
|
+
t.describe(`${EncryptedCookies.encrypt.name}`, () => {
|
|
8
8
|
t.test("return encrypted string in correct format", async () => {
|
|
9
9
|
const value = "hello world"
|
|
10
10
|
|
|
@@ -79,7 +79,7 @@ t.describe("encrypt", () => {
|
|
|
79
79
|
})
|
|
80
80
|
})
|
|
81
81
|
|
|
82
|
-
t.describe(
|
|
82
|
+
t.describe(`${EncryptedCookies.decrypt.name}`, () => {
|
|
83
83
|
t.test("decrypt encrypted string successfully", async () => {
|
|
84
84
|
const originalValue = "hello world"
|
|
85
85
|
|
|
@@ -192,7 +192,7 @@ t.describe("decrypt", () => {
|
|
|
192
192
|
})
|
|
193
193
|
})
|
|
194
194
|
|
|
195
|
-
t.describe(
|
|
195
|
+
t.describe(`${EncryptedCookies.encryptCookie.name}`, () => {
|
|
196
196
|
t.test("preserve cookie properties and encrypt value", async () => {
|
|
197
197
|
const cookie = Cookies.unsafeMakeCookie("test", "hello world")
|
|
198
198
|
|
|
@@ -211,7 +211,7 @@ t.describe("encryptCookie", () => {
|
|
|
211
211
|
})
|
|
212
212
|
})
|
|
213
213
|
|
|
214
|
-
t.describe(
|
|
214
|
+
t.describe(`${EncryptedCookies.decryptCookie.name}`, () => {
|
|
215
215
|
t.test("preserve cookie properties and decrypt value", async () => {
|
|
216
216
|
const originalCookie = Cookies.unsafeMakeCookie("test", "hello world")
|
|
217
217
|
|
|
@@ -17,7 +17,6 @@ class CustomError extends Data.TaggedError("CustomError") {}
|
|
|
17
17
|
const SampleRoutes = [
|
|
18
18
|
{
|
|
19
19
|
path: "/users",
|
|
20
|
-
segments: [{ literal: "users" }],
|
|
21
20
|
load: async () => ({
|
|
22
21
|
default: Route
|
|
23
22
|
.html(Effect.succeed("Users list"))
|
|
@@ -26,15 +25,14 @@ const SampleRoutes = [
|
|
|
26
25
|
},
|
|
27
26
|
{
|
|
28
27
|
path: "/articles",
|
|
29
|
-
segments: [{ literal: "articles" }],
|
|
30
28
|
load: async () => ({
|
|
31
29
|
default: Route.html(Effect.succeed("Articles list")),
|
|
32
30
|
}),
|
|
33
31
|
},
|
|
34
32
|
] as const
|
|
35
33
|
|
|
36
|
-
const SampleRouteManifest: Router.
|
|
37
|
-
|
|
34
|
+
const SampleRouteManifest: Router.RouterManifest = {
|
|
35
|
+
routes: SampleRoutes,
|
|
38
36
|
}
|
|
39
37
|
|
|
40
38
|
const routerLayer = Router.layerPromise(async () => SampleRouteManifest)
|
|
@@ -55,9 +53,8 @@ t.it("HttpRouter Requirement and Error types infers", () =>
|
|
|
55
53
|
|
|
56
54
|
t.it("HTTP methods", () =>
|
|
57
55
|
effect(function*() {
|
|
58
|
-
const allMethodsRoute: Router.
|
|
56
|
+
const allMethodsRoute: Router.LazyRoute = {
|
|
59
57
|
path: "/",
|
|
60
|
-
segments: [],
|
|
61
58
|
load: async () => ({
|
|
62
59
|
default: Route
|
|
63
60
|
.html(Effect.succeed("GET"))
|
|
@@ -90,8 +87,8 @@ t.it("HTTP methods", () =>
|
|
|
90
87
|
|
|
91
88
|
t.it("router handles requests correctly", () =>
|
|
92
89
|
effect(function*() {
|
|
93
|
-
const
|
|
94
|
-
const client = TestHttpClient.make(
|
|
90
|
+
const router = yield* FileHttpRouter.make(SampleRoutes)
|
|
91
|
+
const client = TestHttpClient.make(router)
|
|
95
92
|
|
|
96
93
|
const getUsersResponse = yield* client.get("/users")
|
|
97
94
|
|
|
@@ -147,24 +144,21 @@ t.it(
|
|
|
147
144
|
"handles routes with special characters (tilde and hyphen)",
|
|
148
145
|
() =>
|
|
149
146
|
effect(function*() {
|
|
150
|
-
const specialCharRoutes: Router.
|
|
147
|
+
const specialCharRoutes: Router.LazyRoute[] = [
|
|
151
148
|
{
|
|
152
149
|
path: "/api-v1",
|
|
153
|
-
segments: [{ literal: "api-v1" }],
|
|
154
150
|
load: async () => ({
|
|
155
151
|
default: Route.text(Effect.succeed("API v1")),
|
|
156
152
|
}),
|
|
157
153
|
},
|
|
158
154
|
{
|
|
159
155
|
path: "/files~backup",
|
|
160
|
-
segments: [{ literal: "files~backup" }],
|
|
161
156
|
load: async () => ({
|
|
162
157
|
default: Route.text(Effect.succeed("Backup files")),
|
|
163
158
|
}),
|
|
164
159
|
},
|
|
165
160
|
{
|
|
166
161
|
path: "/test-route~temp",
|
|
167
|
-
segments: [{ literal: "test-route~temp" }],
|
|
168
162
|
load: async () => ({
|
|
169
163
|
default: Route.post(Route.text(Effect.succeed("Test route"))),
|
|
170
164
|
}),
|
|
@@ -205,3 +199,78 @@ t.it(
|
|
|
205
199
|
.toBe("Test route")
|
|
206
200
|
}),
|
|
207
201
|
)
|
|
202
|
+
|
|
203
|
+
t.it(
|
|
204
|
+
"layer routes can wrap inner routes using next()",
|
|
205
|
+
() =>
|
|
206
|
+
effect(function*() {
|
|
207
|
+
const routeWithLayer: Router.LazyRoute = {
|
|
208
|
+
path: "/page",
|
|
209
|
+
load: async () => ({
|
|
210
|
+
default: Route.html(Effect.succeed("<h1>Page Content</h1>")),
|
|
211
|
+
}),
|
|
212
|
+
layers: [
|
|
213
|
+
async () => ({
|
|
214
|
+
default: Route.layer(
|
|
215
|
+
Route.html(function*(context) {
|
|
216
|
+
const innerContent = yield* context.next()
|
|
217
|
+
return `<html><body>${innerContent}</body></html>`
|
|
218
|
+
}),
|
|
219
|
+
),
|
|
220
|
+
}),
|
|
221
|
+
],
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const router = yield* FileHttpRouter.make([routeWithLayer])
|
|
225
|
+
const client = TestHttpClient.make(router)
|
|
226
|
+
|
|
227
|
+
const response = yield* client.get("/page")
|
|
228
|
+
|
|
229
|
+
t.expect(response.status).toBe(200)
|
|
230
|
+
|
|
231
|
+
const html = yield* response.text
|
|
232
|
+
|
|
233
|
+
t.expect(html).toBe("<html><body><h1>Page Content</h1></body></html>")
|
|
234
|
+
}),
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
t.it("nested layers compose correctly with next()", () =>
|
|
238
|
+
effect(function*() {
|
|
239
|
+
const routeWithNestedLayers: Router.LazyRoute = {
|
|
240
|
+
path: "/nested",
|
|
241
|
+
load: async () => ({
|
|
242
|
+
default: Route.html(Effect.succeed("content")),
|
|
243
|
+
}),
|
|
244
|
+
layers: [
|
|
245
|
+
async () => ({
|
|
246
|
+
default: Route.layer(
|
|
247
|
+
Route.html(function*(context) {
|
|
248
|
+
const inner = yield* context.next()
|
|
249
|
+
return `<div class="outer">${inner}</div>`
|
|
250
|
+
}),
|
|
251
|
+
),
|
|
252
|
+
}),
|
|
253
|
+
async () => ({
|
|
254
|
+
default: Route.layer(
|
|
255
|
+
Route.html(function*(context) {
|
|
256
|
+
const inner = yield* context.next()
|
|
257
|
+
return `<div class="inner">${inner}</div>`
|
|
258
|
+
}),
|
|
259
|
+
),
|
|
260
|
+
}),
|
|
261
|
+
],
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const router = yield* FileHttpRouter.make([routeWithNestedLayers])
|
|
265
|
+
const client = TestHttpClient.make(router)
|
|
266
|
+
|
|
267
|
+
const response = yield* client.get("/nested")
|
|
268
|
+
|
|
269
|
+
t.expect(response.status).toBe(200)
|
|
270
|
+
|
|
271
|
+
const html = yield* response.text
|
|
272
|
+
|
|
273
|
+
t.expect(html).toBe(
|
|
274
|
+
"<div class=\"outer\"><div class=\"inner\">content</div></div>",
|
|
275
|
+
)
|
|
276
|
+
}))
|