@effect/platform 0.48.15 → 0.48.17

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 (134) hide show
  1. package/Http/Cookies/package.json +6 -0
  2. package/README.md +235 -46
  3. package/dist/cjs/Http/Client.js +6 -1
  4. package/dist/cjs/Http/Client.js.map +1 -1
  5. package/dist/cjs/Http/ClientRequest.js.map +1 -1
  6. package/dist/cjs/Http/ClientResponse.js.map +1 -1
  7. package/dist/cjs/Http/Cookies.js +566 -0
  8. package/dist/cjs/Http/Cookies.js.map +1 -0
  9. package/dist/cjs/Http/Headers.js +2 -2
  10. package/dist/cjs/Http/Headers.js.map +1 -1
  11. package/dist/cjs/Http/IncomingMessage.js +12 -16
  12. package/dist/cjs/Http/IncomingMessage.js.map +1 -1
  13. package/dist/cjs/Http/Multipart.js.map +1 -1
  14. package/dist/cjs/Http/Router.js +11 -1
  15. package/dist/cjs/Http/Router.js.map +1 -1
  16. package/dist/cjs/Http/ServerRequest.js +6 -1
  17. package/dist/cjs/Http/ServerRequest.js.map +1 -1
  18. package/dist/cjs/Http/ServerResponse.js +36 -1
  19. package/dist/cjs/Http/ServerResponse.js.map +1 -1
  20. package/dist/cjs/Http/UrlParams.js +2 -2
  21. package/dist/cjs/Http/UrlParams.js.map +1 -1
  22. package/dist/cjs/HttpClient.js +3 -1
  23. package/dist/cjs/HttpClient.js.map +1 -1
  24. package/dist/cjs/HttpServer.js +3 -1
  25. package/dist/cjs/HttpServer.js.map +1 -1
  26. package/dist/cjs/internal/http/body.js +2 -2
  27. package/dist/cjs/internal/http/body.js.map +1 -1
  28. package/dist/cjs/internal/http/client.js +9 -3
  29. package/dist/cjs/internal/http/client.js.map +1 -1
  30. package/dist/cjs/internal/http/clientRequest.js +2 -2
  31. package/dist/cjs/internal/http/clientRequest.js.map +1 -1
  32. package/dist/cjs/internal/http/clientResponse.js +16 -8
  33. package/dist/cjs/internal/http/clientResponse.js.map +1 -1
  34. package/dist/cjs/internal/http/multipart.js +4 -4
  35. package/dist/cjs/internal/http/multipart.js.map +1 -1
  36. package/dist/cjs/internal/http/router.js +34 -7
  37. package/dist/cjs/internal/http/router.js.map +1 -1
  38. package/dist/cjs/internal/http/serverRequest.js +30 -15
  39. package/dist/cjs/internal/http/serverRequest.js.map +1 -1
  40. package/dist/cjs/internal/http/serverResponse.js +48 -23
  41. package/dist/cjs/internal/http/serverResponse.js.map +1 -1
  42. package/dist/dts/Error.d.ts.map +1 -1
  43. package/dist/dts/Http/App.d.ts +1 -1
  44. package/dist/dts/Http/App.d.ts.map +1 -1
  45. package/dist/dts/Http/Client.d.ts +13 -2
  46. package/dist/dts/Http/Client.d.ts.map +1 -1
  47. package/dist/dts/Http/ClientRequest.d.ts +2 -1
  48. package/dist/dts/Http/ClientRequest.d.ts.map +1 -1
  49. package/dist/dts/Http/ClientResponse.d.ts +7 -4
  50. package/dist/dts/Http/ClientResponse.d.ts.map +1 -1
  51. package/dist/dts/Http/Cookies.d.ts +253 -0
  52. package/dist/dts/Http/Cookies.d.ts.map +1 -0
  53. package/dist/dts/Http/Headers.d.ts +2 -2
  54. package/dist/dts/Http/Headers.d.ts.map +1 -1
  55. package/dist/dts/Http/IncomingMessage.d.ts +7 -6
  56. package/dist/dts/Http/IncomingMessage.d.ts.map +1 -1
  57. package/dist/dts/Http/Multipart.d.ts +3 -2
  58. package/dist/dts/Http/Multipart.d.ts.map +1 -1
  59. package/dist/dts/Http/Router.d.ts +29 -3
  60. package/dist/dts/Http/Router.d.ts.map +1 -1
  61. package/dist/dts/Http/ServerRequest.d.ts +14 -6
  62. package/dist/dts/Http/ServerRequest.d.ts.map +1 -1
  63. package/dist/dts/Http/ServerResponse.d.ts +89 -13
  64. package/dist/dts/Http/ServerResponse.d.ts.map +1 -1
  65. package/dist/dts/Http/UrlParams.d.ts +3 -2
  66. package/dist/dts/Http/UrlParams.d.ts.map +1 -1
  67. package/dist/dts/HttpClient.d.ts +8 -0
  68. package/dist/dts/HttpClient.d.ts.map +1 -1
  69. package/dist/dts/HttpServer.d.ts +8 -0
  70. package/dist/dts/HttpServer.d.ts.map +1 -1
  71. package/dist/dts/Socket.d.ts +3 -3
  72. package/dist/dts/Socket.d.ts.map +1 -1
  73. package/dist/dts/internal/http/router.d.ts.map +1 -1
  74. package/dist/esm/Http/Client.js +5 -0
  75. package/dist/esm/Http/Client.js.map +1 -1
  76. package/dist/esm/Http/ClientRequest.js.map +1 -1
  77. package/dist/esm/Http/ClientResponse.js.map +1 -1
  78. package/dist/esm/Http/Cookies.js +518 -0
  79. package/dist/esm/Http/Cookies.js.map +1 -0
  80. package/dist/esm/Http/Headers.js +2 -2
  81. package/dist/esm/Http/Headers.js.map +1 -1
  82. package/dist/esm/Http/IncomingMessage.js +12 -15
  83. package/dist/esm/Http/IncomingMessage.js.map +1 -1
  84. package/dist/esm/Http/Multipart.js.map +1 -1
  85. package/dist/esm/Http/Router.js +10 -0
  86. package/dist/esm/Http/Router.js.map +1 -1
  87. package/dist/esm/Http/ServerRequest.js +5 -0
  88. package/dist/esm/Http/ServerRequest.js.map +1 -1
  89. package/dist/esm/Http/ServerResponse.js +35 -0
  90. package/dist/esm/Http/ServerResponse.js.map +1 -1
  91. package/dist/esm/Http/UrlParams.js +2 -2
  92. package/dist/esm/Http/UrlParams.js.map +1 -1
  93. package/dist/esm/HttpClient.js +8 -0
  94. package/dist/esm/HttpClient.js.map +1 -1
  95. package/dist/esm/HttpServer.js +8 -0
  96. package/dist/esm/HttpServer.js.map +1 -1
  97. package/dist/esm/internal/http/body.js +2 -2
  98. package/dist/esm/internal/http/body.js.map +1 -1
  99. package/dist/esm/internal/http/client.js +8 -2
  100. package/dist/esm/internal/http/client.js.map +1 -1
  101. package/dist/esm/internal/http/clientRequest.js +2 -2
  102. package/dist/esm/internal/http/clientRequest.js.map +1 -1
  103. package/dist/esm/internal/http/clientResponse.js +16 -8
  104. package/dist/esm/internal/http/clientResponse.js.map +1 -1
  105. package/dist/esm/internal/http/multipart.js +4 -4
  106. package/dist/esm/internal/http/multipart.js.map +1 -1
  107. package/dist/esm/internal/http/router.js +31 -6
  108. package/dist/esm/internal/http/router.js.map +1 -1
  109. package/dist/esm/internal/http/serverRequest.js +28 -14
  110. package/dist/esm/internal/http/serverRequest.js.map +1 -1
  111. package/dist/esm/internal/http/serverResponse.js +47 -22
  112. package/dist/esm/internal/http/serverResponse.js.map +1 -1
  113. package/package.json +12 -4
  114. package/src/Http/Client.ts +16 -2
  115. package/src/Http/ClientRequest.ts +3 -1
  116. package/src/Http/ClientResponse.ts +18 -7
  117. package/src/Http/Cookies.ts +718 -0
  118. package/src/Http/Headers.ts +16 -8
  119. package/src/Http/IncomingMessage.ts +17 -12
  120. package/src/Http/Multipart.ts +5 -2
  121. package/src/Http/Router.ts +50 -3
  122. package/src/Http/ServerRequest.ts +25 -7
  123. package/src/Http/ServerResponse.ts +145 -13
  124. package/src/Http/UrlParams.ts +3 -2
  125. package/src/HttpClient.ts +8 -0
  126. package/src/HttpServer.ts +8 -0
  127. package/src/internal/http/body.ts +3 -2
  128. package/src/internal/http/client.ts +45 -5
  129. package/src/internal/http/clientRequest.ts +3 -2
  130. package/src/internal/http/clientResponse.ts +18 -8
  131. package/src/internal/http/multipart.ts +7 -4
  132. package/src/internal/http/router.ts +80 -6
  133. package/src/internal/http/serverRequest.ts +41 -15
  134. package/src/internal/http/serverResponse.ts +190 -18
@@ -1,3 +1,4 @@
1
+ import type { ParseOptions } from "@effect/schema/AST"
1
2
  import type * as ParseResult from "@effect/schema/ParseResult"
2
3
  import * as Schema from "@effect/schema/Schema"
3
4
  import * as Context from "effect/Context"
@@ -5,7 +6,8 @@ import * as Effect from "effect/Effect"
5
6
  import { dual, pipe } from "effect/Function"
6
7
  import * as Layer from "effect/Layer"
7
8
  import { pipeArguments } from "effect/Pipeable"
8
- import type * as Predicate from "effect/Predicate"
9
+ import * as Predicate from "effect/Predicate"
10
+ import * as Ref from "effect/Ref"
9
11
  import type * as Schedule from "effect/Schedule"
10
12
  import type * as Scope from "effect/Scope"
11
13
  import * as Stream from "effect/Stream"
@@ -14,6 +16,7 @@ import type * as Client from "../../Http/Client.js"
14
16
  import * as Error from "../../Http/ClientError.js"
15
17
  import type * as ClientRequest from "../../Http/ClientRequest.js"
16
18
  import type * as ClientResponse from "../../Http/ClientResponse.js"
19
+ import * as Cookies from "../../Http/Cookies.js"
17
20
  import * as Method from "../../Http/Method.js"
18
21
  import * as UrlParams from "../../Http/UrlParams.js"
19
22
  import * as internalBody from "./body.js"
@@ -35,6 +38,8 @@ const clientProto = {
35
38
  }
36
39
  }
37
40
 
41
+ const isClient = (u: unknown): u is Client.Client<unknown, unknown, unknown> => Predicate.hasProperty(u, TypeId)
42
+
38
43
  /** @internal */
39
44
  export const make = <R, E, A, R2, E2>(
40
45
  execute: (
@@ -547,7 +552,8 @@ export const retry: {
547
552
  /** @internal */
548
553
  export const schemaFunction = dual<
549
554
  <SA, SI, SR>(
550
- schema: Schema.Schema<SA, SI, SR>
555
+ schema: Schema.Schema<SA, SI, SR>,
556
+ options?: ParseOptions | undefined
551
557
  ) => <R, E, A>(
552
558
  self: Client.Client<R, E, A>
553
559
  ) => (
@@ -557,14 +563,15 @@ export const schemaFunction = dual<
557
563
  ) => Effect.Effect<A, E | ParseResult.ParseError | Error.RequestError, SR | R>,
558
564
  <R, E, A, SA, SI, SR>(
559
565
  self: Client.Client<R, E, A>,
560
- schema: Schema.Schema<SA, SI, SR>
566
+ schema: Schema.Schema<SA, SI, SR>,
567
+ options?: ParseOptions | undefined
561
568
  ) => (
562
569
  request: ClientRequest.ClientRequest
563
570
  ) => (
564
571
  a: SA
565
572
  ) => Effect.Effect<A, E | ParseResult.ParseError | Error.RequestError, SR | R>
566
- >(2, (self, schema) => {
567
- const encode = Schema.encode(schema)
573
+ >((args) => isClient(args[0]), (self, schema, options) => {
574
+ const encode = Schema.encode(schema, options)
568
575
  return (request) => (a) =>
569
576
  Effect.flatMap(
570
577
  Effect.tryMap(encode(a), {
@@ -609,3 +616,36 @@ export const tapRequest = dual<
609
616
  f: (a: ClientRequest.ClientRequest) => Effect.Effect<_, E2, R2>
610
617
  ) => Client.Client<R | R2, E | E2, A>
611
618
  >(2, (self, f) => make(self.execute as any, (request) => Effect.tap(self.preprocess(request), f)))
619
+
620
+ /** @internal */
621
+ export const withCookiesRef = dual<
622
+ (
623
+ ref: Ref.Ref<Cookies.Cookies>
624
+ ) => <R, E>(self: Client.Client.WithResponse<R, E>) => Client.Client.WithResponse<R, E>,
625
+ <R, E>(
626
+ self: Client.Client.WithResponse<R, E>,
627
+ ref: Ref.Ref<Cookies.Cookies>
628
+ ) => Client.Client.WithResponse<R, E>
629
+ >(
630
+ 2,
631
+ <R, E>(
632
+ self: Client.Client.WithResponse<R, E>,
633
+ ref: Ref.Ref<Cookies.Cookies>
634
+ ): Client.Client.WithResponse<R, E> =>
635
+ make(
636
+ (request: Effect.Effect<ClientRequest.ClientRequest, E, R>) =>
637
+ Effect.tap(
638
+ self.execute(request),
639
+ (response) => Ref.update(ref, (cookies) => Cookies.merge(cookies, response.cookies))
640
+ ),
641
+ (request) =>
642
+ Effect.flatMap(self.preprocess(request), (request) =>
643
+ Effect.map(
644
+ Ref.get(ref),
645
+ (cookies) =>
646
+ Cookies.isEmpty(cookies)
647
+ ? request
648
+ : internalRequest.setHeader(request, "cookie", Cookies.toCookieHeader(cookies))
649
+ ))
650
+ )
651
+ )
@@ -1,3 +1,4 @@
1
+ import type { ParseOptions } from "@effect/schema/AST"
1
2
  import type * as Schema from "@effect/schema/Schema"
2
3
  import * as Effect from "effect/Effect"
3
4
  import { dual } from "effect/Function"
@@ -373,11 +374,11 @@ export const fileWebBody = dual<
373
374
  >(2, (self, file) => setBody(self, internalBody.fileWeb(file)))
374
375
 
375
376
  /** @internal */
376
- export const schemaBody = <A, I, R>(schema: Schema.Schema<A, I, R>): {
377
+ export const schemaBody = <A, I, R>(schema: Schema.Schema<A, I, R>, options?: ParseOptions | undefined): {
377
378
  (body: A): (self: ClientRequest.ClientRequest) => Effect.Effect<ClientRequest.ClientRequest, Body.BodyError, R>
378
379
  (self: ClientRequest.ClientRequest, body: A): Effect.Effect<ClientRequest.ClientRequest, Body.BodyError, R>
379
380
  } => {
380
- const encode = internalBody.jsonSchema(schema)
381
+ const encode = internalBody.jsonSchema(schema, options)
381
382
  return dual<
382
383
  (
383
384
  body: A
@@ -1,3 +1,4 @@
1
+ import type { ParseOptions } from "@effect/schema/AST"
1
2
  import type * as ParseResult from "@effect/schema/ParseResult"
2
3
  import * as Schema from "@effect/schema/Schema"
3
4
  import * as Effect from "effect/Effect"
@@ -7,6 +8,7 @@ import * as Stream from "effect/Stream"
7
8
  import * as Error from "../../Http/ClientError.js"
8
9
  import type * as ClientRequest from "../../Http/ClientRequest.js"
9
10
  import type * as ClientResponse from "../../Http/ClientResponse.js"
11
+ import * as Cookies from "../../Http/Cookies.js"
10
12
  import * as Headers from "../../Http/Headers.js"
11
13
  import * as IncomingMessage from "../../Http/IncomingMessage.js"
12
14
  import * as UrlParams from "../../Http/UrlParams.js"
@@ -49,6 +51,14 @@ class ClientResponseImpl extends Inspectable.Class implements ClientResponse.Cli
49
51
  return Headers.fromInput(this.source.headers)
50
52
  }
51
53
 
54
+ cachedCookies?: Cookies.Cookies
55
+ get cookies(): Cookies.Cookies {
56
+ if (this.cachedCookies) {
57
+ return this.cachedCookies
58
+ }
59
+ return this.cachedCookies = Cookies.fromSetCookie(this.source.headers.getSetCookie())
60
+ }
61
+
52
62
  get remoteAddress(): Option.Option<string> {
53
63
  return Option.none()
54
64
  }
@@ -151,8 +161,8 @@ export const schemaJson = <
151
161
  readonly body?: unknown | undefined
152
162
  },
153
163
  A
154
- >(schema: Schema.Schema<A, I, R>) => {
155
- const parse = Schema.decodeUnknown(schema)
164
+ >(schema: Schema.Schema<A, I, R>, options?: ParseOptions | undefined) => {
165
+ const parse = Schema.decodeUnknown(schema, options)
156
166
  return (self: ClientResponse.ClientResponse): Effect.Effect<A, Error.ResponseError | ParseResult.ParseError, R> =>
157
167
  Effect.flatMap(
158
168
  self.json,
@@ -173,8 +183,8 @@ export const schemaNoBody = <
173
183
  readonly headers?: Readonly<Record<string, string>> | undefined
174
184
  },
175
185
  A
176
- >(schema: Schema.Schema<A, I, R>) => {
177
- const parse = Schema.decodeUnknown(schema)
186
+ >(schema: Schema.Schema<A, I, R>, options?: ParseOptions | undefined) => {
187
+ const parse = Schema.decodeUnknown(schema, options)
178
188
  return (self: ClientResponse.ClientResponse): Effect.Effect<A, ParseResult.ParseError, R> =>
179
189
  parse({
180
190
  status: self.status,
@@ -215,8 +225,8 @@ export const schemaJsonEffect = <
215
225
  readonly body?: unknown | undefined
216
226
  },
217
227
  A
218
- >(schema: Schema.Schema<A, I, R>) => {
219
- const decode = schemaJson(schema)
228
+ >(schema: Schema.Schema<A, I, R>, options?: ParseOptions | undefined) => {
229
+ const decode = schemaJson(schema, options)
220
230
  return <E, R2>(effect: Effect.Effect<ClientResponse.ClientResponse, E, R2>) =>
221
231
  Effect.scoped(Effect.flatMap(effect, decode))
222
232
  }
@@ -229,8 +239,8 @@ export const schemaNoBodyEffect = <
229
239
  readonly headers?: Readonly<Record<string, string>> | undefined
230
240
  },
231
241
  A
232
- >(schema: Schema.Schema<A, I, R>) => {
233
- const decode = schemaNoBody(schema)
242
+ >(schema: Schema.Schema<A, I, R>, options?: ParseOptions | undefined) => {
243
+ const decode = schemaNoBody(schema, options)
234
244
  return <E, R2>(effect: Effect.Effect<ClientResponse.ClientResponse, E, R2>) =>
235
245
  Effect.scoped(Effect.flatMap(effect, decode))
236
246
  }
@@ -1,3 +1,4 @@
1
+ import type { ParseOptions } from "@effect/schema/AST"
1
2
  import type * as ParseResult from "@effect/schema/ParseResult"
2
3
  import * as Schema from "@effect/schema/Schema"
3
4
  import * as Cause from "effect/Cause"
@@ -108,14 +109,15 @@ export const filesSchema: Schema.Schema<ReadonlyArray<Multipart.PersistedFile>>
108
109
 
109
110
  /** @internal */
110
111
  export const schemaPersisted = <R, I extends Partial<Multipart.Persisted>, A>(
111
- schema: Schema.Schema<A, I, R>
112
+ schema: Schema.Schema<A, I, R>,
113
+ options?: ParseOptions | undefined
112
114
  ) => {
113
- const parse = Schema.decodeUnknown(schema)
115
+ const parse = Schema.decodeUnknown(schema, options)
114
116
  return (persisted: Multipart.Persisted) => parse(persisted)
115
117
  }
116
118
 
117
119
  /** @internal */
118
- export const schemaJson = <A, I, R>(schema: Schema.Schema<A, I, R>): {
120
+ export const schemaJson = <A, I, R>(schema: Schema.Schema<A, I, R>, options?: ParseOptions | undefined): {
119
121
  (
120
122
  field: string
121
123
  ): (persisted: Multipart.Persisted) => Effect.Effect<A, ParseResult.ParseError, R>
@@ -140,7 +142,8 @@ export const schemaJson = <A, I, R>(schema: Schema.Schema<A, I, R>): {
140
142
  Schema.decodeUnknown(
141
143
  Schema.struct({
142
144
  [field]: fromJson
143
- })
145
+ }),
146
+ options
144
147
  )(persisted),
145
148
  (_) => _[field]
146
149
  ))
@@ -1,3 +1,4 @@
1
+ import type { ParseOptions } from "@effect/schema/AST"
1
2
  import * as Schema from "@effect/schema/Schema"
2
3
  import type * as Cause from "effect/Cause"
3
4
  import * as Chunk from "effect/Chunk"
@@ -37,22 +38,95 @@ export const params = Effect.map(RouteContext, (_) => _.params)
37
38
  export const searchParams = Effect.map(RouteContext, (_) => _.searchParams)
38
39
 
39
40
  /** @internal */
40
- export const schemaParams = <R, I extends Readonly<Record<string, string>>, A>(schema: Schema.Schema<A, I, R>) => {
41
- const parse = Schema.decodeUnknown(schema)
41
+ export const schemaJson = <
42
+ R,
43
+ I extends {
44
+ readonly method?: Method.Method
45
+ readonly url?: string
46
+ readonly cookies?: Readonly<Record<string, string>>
47
+ readonly headers?: Readonly<Record<string, string>>
48
+ readonly pathParams?: Readonly<Record<string, string>>
49
+ readonly searchParams?: Readonly<Record<string, string>>
50
+ readonly body?: any
51
+ },
52
+ A
53
+ >(
54
+ schema: Schema.Schema<A, I, R>,
55
+ options?: ParseOptions | undefined
56
+ ) => {
57
+ const parse = Schema.decodeUnknown(schema, options)
58
+ return Effect.flatMap(
59
+ ServerRequest.ServerRequest,
60
+ (request) =>
61
+ Effect.flatMap(Effect.zip(request.json, RouteContext), ([body, context]) =>
62
+ parse({
63
+ method: request.method,
64
+ url: request.url,
65
+ headers: request.headers,
66
+ cookies: request.cookies,
67
+ pathParams: context.params,
68
+ searchParams: context.searchParams,
69
+ body
70
+ }))
71
+ )
72
+ }
73
+
74
+ /** @internal */
75
+ export const schemaNoBody = <
76
+ R,
77
+ I extends {
78
+ readonly method?: Method.Method
79
+ readonly url?: string
80
+ readonly cookies?: Readonly<Record<string, string>>
81
+ readonly headers?: Readonly<Record<string, string>>
82
+ readonly pathParams?: Readonly<Record<string, string>>
83
+ readonly searchParams?: Readonly<Record<string, string>>
84
+ },
85
+ A
86
+ >(
87
+ schema: Schema.Schema<A, I, R>,
88
+ options?: ParseOptions | undefined
89
+ ) => {
90
+ const parse = Schema.decodeUnknown(schema, options)
91
+ return Effect.flatMap(
92
+ ServerRequest.ServerRequest,
93
+ (request) =>
94
+ Effect.flatMap(RouteContext, (context) =>
95
+ parse({
96
+ method: request.method,
97
+ url: request.url,
98
+ headers: request.headers,
99
+ cookies: request.cookies,
100
+ pathParams: context.params,
101
+ searchParams: context.searchParams
102
+ }))
103
+ )
104
+ }
105
+
106
+ /** @internal */
107
+ export const schemaParams = <R, I extends Readonly<Record<string, string>>, A>(
108
+ schema: Schema.Schema<A, I, R>,
109
+ options?: ParseOptions | undefined
110
+ ) => {
111
+ const parse = Schema.decodeUnknown(schema, options)
42
112
  return Effect.flatMap(RouteContext, (_) => parse({ ..._.searchParams, ..._.params }))
43
113
  }
44
114
 
45
115
  /** @internal */
46
- export const schemaPathParams = <R, I extends Readonly<Record<string, string>>, A>(schema: Schema.Schema<A, I, R>) => {
47
- const parse = Schema.decodeUnknown(schema)
116
+ export const schemaPathParams = <R, I extends Readonly<Record<string, string>>, A>(
117
+ schema: Schema.Schema<A, I, R>,
118
+ options?: ParseOptions | undefined
119
+ ) => {
120
+ const parse = Schema.decodeUnknown(schema, options)
48
121
  return Effect.flatMap(RouteContext, (_) => parse(_.params))
49
122
  }
50
123
 
51
124
  /** @internal */
52
125
  export const schemaSearchParams = <R, I extends Readonly<Record<string, string>>, A>(
53
- schema: Schema.Schema<A, I, R>
126
+ schema: Schema.Schema<A, I, R>,
127
+ options?: ParseOptions | undefined
54
128
  ) => {
55
- const parse = Schema.decodeUnknown(schema)
129
+ const parse = Schema.decodeUnknown(schema, options)
56
130
  return Effect.flatMap(RouteContext, (_) => parse(_.searchParams))
57
131
  }
58
132
 
@@ -1,13 +1,16 @@
1
+ import type { ParseOptions } from "@effect/schema/AST"
1
2
  import type * as ParseResult from "@effect/schema/ParseResult"
2
- import type * as Schema from "@effect/schema/Schema"
3
+ import * as Schema from "@effect/schema/Schema"
3
4
  import * as Channel from "effect/Channel"
4
5
  import * as Context from "effect/Context"
5
6
  import * as Effect from "effect/Effect"
6
7
  import * as Inspectable from "effect/Inspectable"
7
8
  import * as Option from "effect/Option"
9
+ import type { ReadonlyRecord } from "effect/ReadonlyRecord"
8
10
  import type * as Scope from "effect/Scope"
9
11
  import * as Stream from "effect/Stream"
10
12
  import type * as FileSystem from "../../FileSystem.js"
13
+ import * as Cookies from "../../Http/Cookies.js"
11
14
  import * as Headers from "../../Http/Headers.js"
12
15
  import * as IncomingMessage from "../../Http/IncomingMessage.js"
13
16
  import type { Method } from "../../Http/Method.js"
@@ -34,14 +37,26 @@ export const upgradeChannel = <IE = never>() => Channel.unwrap(Effect.map(upgrad
34
37
  export const multipartPersisted = Effect.flatMap(serverRequestTag, (request) => request.multipart)
35
38
 
36
39
  /** @internal */
37
- export const schemaHeaders = <R, I extends Readonly<Record<string, string>>, A>(schema: Schema.Schema<A, I, R>) => {
38
- const parse = IncomingMessage.schemaHeaders(schema)
40
+ export const schemaCookies = <R, I extends Readonly<Record<string, string>>, A>(
41
+ schema: Schema.Schema<A, I, R>,
42
+ options?: ParseOptions | undefined
43
+ ) => {
44
+ const parse = Schema.decodeUnknown(schema, options)
45
+ return Effect.flatMap(serverRequestTag, (req) => parse(req.cookies))
46
+ }
47
+
48
+ /** @internal */
49
+ export const schemaHeaders = <R, I extends Readonly<Record<string, string>>, A>(
50
+ schema: Schema.Schema<A, I, R>,
51
+ options?: ParseOptions | undefined
52
+ ) => {
53
+ const parse = IncomingMessage.schemaHeaders(schema, options)
39
54
  return Effect.flatMap(serverRequestTag, parse)
40
55
  }
41
56
 
42
57
  /** @internal */
43
- export const schemaBodyJson = <A, I, R>(schema: Schema.Schema<A, I, R>) => {
44
- const parse = IncomingMessage.schemaBodyJson(schema)
58
+ export const schemaBodyJson = <A, I, R>(schema: Schema.Schema<A, I, R>, options?: ParseOptions | undefined) => {
59
+ const parse = IncomingMessage.schemaBodyJson(schema, options)
45
60
  return Effect.flatMap(serverRequestTag, parse)
46
61
  }
47
62
 
@@ -50,10 +65,11 @@ const isMultipart = (request: ServerRequest.ServerRequest) =>
50
65
 
51
66
  /** @internal */
52
67
  export const schemaBodyForm = <R, I extends Partial<Multipart.Persisted>, A>(
53
- schema: Schema.Schema<A, I, R>
68
+ schema: Schema.Schema<A, I, R>,
69
+ options?: ParseOptions | undefined
54
70
  ) => {
55
- const parseMultipart = Multipart.schemaPersisted(schema)
56
- const parseUrlParams = IncomingMessage.schemaBodyUrlParams(schema as Schema.Schema<A, any, R>)
71
+ const parseMultipart = Multipart.schemaPersisted(schema, options)
72
+ const parseUrlParams = IncomingMessage.schemaBodyUrlParams(schema as Schema.Schema<A, any, R>, options)
57
73
  return Effect.flatMap(serverRequestTag, (request): Effect.Effect<
58
74
  A,
59
75
  Multipart.MultipartError | ParseResult.ParseError | Error.RequestError,
@@ -68,24 +84,26 @@ export const schemaBodyForm = <R, I extends Partial<Multipart.Persisted>, A>(
68
84
 
69
85
  /** @internal */
70
86
  export const schemaBodyUrlParams = <R, I extends Readonly<Record<string, string>>, A>(
71
- schema: Schema.Schema<A, I, R>
87
+ schema: Schema.Schema<A, I, R>,
88
+ options?: ParseOptions | undefined
72
89
  ) => {
73
- const parse = IncomingMessage.schemaBodyUrlParams(schema)
90
+ const parse = IncomingMessage.schemaBodyUrlParams(schema, options)
74
91
  return Effect.flatMap(serverRequestTag, parse)
75
92
  }
76
93
 
77
94
  /** @internal */
78
95
  export const schemaBodyMultipart = <R, I extends Partial<Multipart.Persisted>, A>(
79
- schema: Schema.Schema<A, I, R>
96
+ schema: Schema.Schema<A, I, R>,
97
+ options?: ParseOptions | undefined
80
98
  ) => {
81
- const parse = Multipart.schemaPersisted(schema)
99
+ const parse = Multipart.schemaPersisted(schema, options)
82
100
  return Effect.flatMap(multipartPersisted, parse)
83
101
  }
84
102
 
85
103
  /** @internal */
86
- export const schemaBodyFormJson = <A, I, R>(schema: Schema.Schema<A, I, R>) => {
87
- const parseMultipart = Multipart.schemaJson(schema)
88
- const parseUrlParams = UrlParams.schemaJson(schema)
104
+ export const schemaBodyFormJson = <A, I, R>(schema: Schema.Schema<A, I, R>, options?: ParseOptions | undefined) => {
105
+ const parseMultipart = Multipart.schemaJson(schema, options)
106
+ const parseUrlParams = UrlParams.schemaJson(schema, options)
89
107
  return (field: string) =>
90
108
  Effect.flatMap(
91
109
  serverRequestTag,
@@ -164,6 +182,14 @@ class ServerRequestImpl extends Inspectable.Class implements ServerRequest.Serve
164
182
  return this.headersOverride
165
183
  }
166
184
 
185
+ private cachedCookies: ReadonlyRecord<string, string> | undefined
186
+ get cookies() {
187
+ if (this.cachedCookies) {
188
+ return this.cachedCookies
189
+ }
190
+ return this.cachedCookies = Cookies.parseHeader(this.headers.cookie ?? "")
191
+ }
192
+
167
193
  get stream(): Stream.Stream<Uint8Array, Error.RequestError> {
168
194
  return this.source.body
169
195
  ? Stream.fromReadableStream(() => this.source.body as any, (_) =>