@effect/platform 0.48.14 → 0.48.16

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 (248) hide show
  1. package/Http/Cookies/package.json +6 -0
  2. package/README.md +235 -46
  3. package/dist/cjs/Command.js +1 -1
  4. package/dist/cjs/Command.js.map +1 -1
  5. package/dist/cjs/CommandExecutor.js +1 -1
  6. package/dist/cjs/CommandExecutor.js.map +1 -1
  7. package/dist/cjs/Effectify.js +1 -1
  8. package/dist/cjs/Effectify.js.map +1 -1
  9. package/dist/cjs/Error.js +1 -1
  10. package/dist/cjs/Error.js.map +1 -1
  11. package/dist/cjs/FileSystem.js +1 -1
  12. package/dist/cjs/FileSystem.js.map +1 -1
  13. package/dist/cjs/Http/App.js +1 -1
  14. package/dist/cjs/Http/App.js.map +1 -1
  15. package/dist/cjs/Http/Body.js +1 -1
  16. package/dist/cjs/Http/Body.js.map +1 -1
  17. package/dist/cjs/Http/Client.js +7 -2
  18. package/dist/cjs/Http/Client.js.map +1 -1
  19. package/dist/cjs/Http/ClientError.js +1 -1
  20. package/dist/cjs/Http/ClientError.js.map +1 -1
  21. package/dist/cjs/Http/ClientRequest.js +1 -1
  22. package/dist/cjs/Http/ClientRequest.js.map +1 -1
  23. package/dist/cjs/Http/ClientResponse.js +1 -1
  24. package/dist/cjs/Http/ClientResponse.js.map +1 -1
  25. package/dist/cjs/Http/Cookies.js +543 -0
  26. package/dist/cjs/Http/Cookies.js.map +1 -0
  27. package/dist/cjs/Http/Etag.js +1 -1
  28. package/dist/cjs/Http/Etag.js.map +1 -1
  29. package/dist/cjs/Http/Headers.js +3 -3
  30. package/dist/cjs/Http/Headers.js.map +1 -1
  31. package/dist/cjs/Http/IncomingMessage.js +1 -1
  32. package/dist/cjs/Http/IncomingMessage.js.map +1 -1
  33. package/dist/cjs/Http/Method.js.map +1 -1
  34. package/dist/cjs/Http/Middleware.js +1 -1
  35. package/dist/cjs/Http/Middleware.js.map +1 -1
  36. package/dist/cjs/Http/Multipart.js +1 -1
  37. package/dist/cjs/Http/Multipart.js.map +1 -1
  38. package/dist/cjs/Http/Multiplex.js +1 -1
  39. package/dist/cjs/Http/Multiplex.js.map +1 -1
  40. package/dist/cjs/Http/Platform.js +1 -1
  41. package/dist/cjs/Http/Platform.js.map +1 -1
  42. package/dist/cjs/Http/Router.js +1 -1
  43. package/dist/cjs/Http/Router.js.map +1 -1
  44. package/dist/cjs/Http/Server.js +1 -1
  45. package/dist/cjs/Http/Server.js.map +1 -1
  46. package/dist/cjs/Http/ServerError.js +1 -1
  47. package/dist/cjs/Http/ServerError.js.map +1 -1
  48. package/dist/cjs/Http/ServerRequest.js +1 -1
  49. package/dist/cjs/Http/ServerRequest.js.map +1 -1
  50. package/dist/cjs/Http/ServerResponse.js +37 -2
  51. package/dist/cjs/Http/ServerResponse.js.map +1 -1
  52. package/dist/cjs/Http/UrlParams.js +1 -1
  53. package/dist/cjs/Http/UrlParams.js.map +1 -1
  54. package/dist/cjs/HttpClient.js +4 -2
  55. package/dist/cjs/HttpClient.js.map +1 -1
  56. package/dist/cjs/HttpServer.js +4 -2
  57. package/dist/cjs/HttpServer.js.map +1 -1
  58. package/dist/cjs/KeyValueStore.js +1 -1
  59. package/dist/cjs/KeyValueStore.js.map +1 -1
  60. package/dist/cjs/Path.js +1 -1
  61. package/dist/cjs/Path.js.map +1 -1
  62. package/dist/cjs/PlatformLogger.js +1 -1
  63. package/dist/cjs/PlatformLogger.js.map +1 -1
  64. package/dist/cjs/Runtime.js +1 -1
  65. package/dist/cjs/Runtime.js.map +1 -1
  66. package/dist/cjs/Socket.js +1 -1
  67. package/dist/cjs/Socket.js.map +1 -1
  68. package/dist/cjs/Template.js +1 -1
  69. package/dist/cjs/Template.js.map +1 -1
  70. package/dist/cjs/Terminal.js +1 -1
  71. package/dist/cjs/Terminal.js.map +1 -1
  72. package/dist/cjs/Transferable.js +1 -1
  73. package/dist/cjs/Transferable.js.map +1 -1
  74. package/dist/cjs/Worker.js +1 -1
  75. package/dist/cjs/Worker.js.map +1 -1
  76. package/dist/cjs/WorkerError.js +1 -1
  77. package/dist/cjs/WorkerError.js.map +1 -1
  78. package/dist/cjs/WorkerRunner.js +1 -1
  79. package/dist/cjs/WorkerRunner.js.map +1 -1
  80. package/dist/cjs/index.js +1 -1
  81. package/dist/cjs/index.js.map +1 -1
  82. package/dist/cjs/internal/command.js +1 -1
  83. package/dist/cjs/internal/command.js.map +1 -1
  84. package/dist/cjs/internal/commandExecutor.js +1 -1
  85. package/dist/cjs/internal/commandExecutor.js.map +1 -1
  86. package/dist/cjs/internal/effectify.js +1 -1
  87. package/dist/cjs/internal/effectify.js.map +1 -1
  88. package/dist/cjs/internal/error.js +1 -1
  89. package/dist/cjs/internal/error.js.map +1 -1
  90. package/dist/cjs/internal/fileSystem.js +1 -1
  91. package/dist/cjs/internal/fileSystem.js.map +1 -1
  92. package/dist/cjs/internal/http/body.js +1 -1
  93. package/dist/cjs/internal/http/body.js.map +1 -1
  94. package/dist/cjs/internal/http/client.js +6 -2
  95. package/dist/cjs/internal/http/client.js.map +1 -1
  96. package/dist/cjs/internal/http/clientError.js.map +1 -1
  97. package/dist/cjs/internal/http/clientRequest.js +1 -1
  98. package/dist/cjs/internal/http/clientRequest.js.map +1 -1
  99. package/dist/cjs/internal/http/clientResponse.js +9 -1
  100. package/dist/cjs/internal/http/clientResponse.js.map +1 -1
  101. package/dist/cjs/internal/http/etag.js +1 -1
  102. package/dist/cjs/internal/http/etag.js.map +1 -1
  103. package/dist/cjs/internal/http/middleware.js +1 -1
  104. package/dist/cjs/internal/http/middleware.js.map +1 -1
  105. package/dist/cjs/internal/http/multipart.js +1 -1
  106. package/dist/cjs/internal/http/multipart.js.map +1 -1
  107. package/dist/cjs/internal/http/multiplex.js +1 -1
  108. package/dist/cjs/internal/http/multiplex.js.map +1 -1
  109. package/dist/cjs/internal/http/platform.js +1 -1
  110. package/dist/cjs/internal/http/platform.js.map +1 -1
  111. package/dist/cjs/internal/http/router.js +1 -1
  112. package/dist/cjs/internal/http/router.js.map +1 -1
  113. package/dist/cjs/internal/http/server.js +1 -1
  114. package/dist/cjs/internal/http/server.js.map +1 -1
  115. package/dist/cjs/internal/http/serverError.js +1 -1
  116. package/dist/cjs/internal/http/serverError.js.map +1 -1
  117. package/dist/cjs/internal/http/serverRequest.js +9 -1
  118. package/dist/cjs/internal/http/serverRequest.js.map +1 -1
  119. package/dist/cjs/internal/http/serverResponse.js +34 -17
  120. package/dist/cjs/internal/http/serverResponse.js.map +1 -1
  121. package/dist/cjs/internal/keyValueStore.js +1 -1
  122. package/dist/cjs/internal/keyValueStore.js.map +1 -1
  123. package/dist/cjs/internal/path.js +1 -1
  124. package/dist/cjs/internal/path.js.map +1 -1
  125. package/dist/cjs/internal/platformLogger.js +1 -1
  126. package/dist/cjs/internal/platformLogger.js.map +1 -1
  127. package/dist/cjs/internal/terminal.js.map +1 -1
  128. package/dist/cjs/internal/worker.js +1 -1
  129. package/dist/cjs/internal/worker.js.map +1 -1
  130. package/dist/cjs/internal/workerError.js.map +1 -1
  131. package/dist/cjs/internal/workerRunner.js +1 -1
  132. package/dist/cjs/internal/workerRunner.js.map +1 -1
  133. package/dist/dts/Error.d.ts.map +1 -1
  134. package/dist/dts/Http/App.d.ts +1 -1
  135. package/dist/dts/Http/App.d.ts.map +1 -1
  136. package/dist/dts/Http/Client.d.ts +10 -0
  137. package/dist/dts/Http/Client.d.ts.map +1 -1
  138. package/dist/dts/Http/ClientResponse.d.ts +2 -0
  139. package/dist/dts/Http/ClientResponse.d.ts.map +1 -1
  140. package/dist/dts/Http/Cookies.d.ts +245 -0
  141. package/dist/dts/Http/Cookies.d.ts.map +1 -0
  142. package/dist/dts/Http/Headers.d.ts +2 -2
  143. package/dist/dts/Http/Headers.d.ts.map +1 -1
  144. package/dist/dts/Http/IncomingMessage.d.ts +2 -2
  145. package/dist/dts/Http/IncomingMessage.d.ts.map +1 -1
  146. package/dist/dts/Http/ServerRequest.d.ts +2 -0
  147. package/dist/dts/Http/ServerRequest.d.ts.map +1 -1
  148. package/dist/dts/Http/ServerResponse.d.ts +75 -0
  149. package/dist/dts/Http/ServerResponse.d.ts.map +1 -1
  150. package/dist/dts/Http/UrlParams.d.ts +1 -1
  151. package/dist/dts/Http/UrlParams.d.ts.map +1 -1
  152. package/dist/dts/HttpClient.d.ts +8 -0
  153. package/dist/dts/HttpClient.d.ts.map +1 -1
  154. package/dist/dts/HttpServer.d.ts +8 -0
  155. package/dist/dts/HttpServer.d.ts.map +1 -1
  156. package/dist/dts/Socket.d.ts +3 -3
  157. package/dist/dts/Socket.d.ts.map +1 -1
  158. package/dist/dts/internal/http/router.d.ts.map +1 -1
  159. package/dist/esm/Command.js.map +1 -1
  160. package/dist/esm/CommandExecutor.js.map +1 -1
  161. package/dist/esm/Effectify.js.map +1 -1
  162. package/dist/esm/Error.js.map +1 -1
  163. package/dist/esm/FileSystem.js.map +1 -1
  164. package/dist/esm/Http/App.js.map +1 -1
  165. package/dist/esm/Http/Body.js.map +1 -1
  166. package/dist/esm/Http/Client.js +5 -0
  167. package/dist/esm/Http/Client.js.map +1 -1
  168. package/dist/esm/Http/ClientError.js.map +1 -1
  169. package/dist/esm/Http/ClientRequest.js.map +1 -1
  170. package/dist/esm/Http/ClientResponse.js.map +1 -1
  171. package/dist/esm/Http/Cookies.js +496 -0
  172. package/dist/esm/Http/Cookies.js.map +1 -0
  173. package/dist/esm/Http/Etag.js.map +1 -1
  174. package/dist/esm/Http/Headers.js +2 -2
  175. package/dist/esm/Http/Headers.js.map +1 -1
  176. package/dist/esm/Http/IncomingMessage.js.map +1 -1
  177. package/dist/esm/Http/Method.js.map +1 -1
  178. package/dist/esm/Http/Middleware.js.map +1 -1
  179. package/dist/esm/Http/Multipart.js.map +1 -1
  180. package/dist/esm/Http/Multiplex.js.map +1 -1
  181. package/dist/esm/Http/Platform.js.map +1 -1
  182. package/dist/esm/Http/Router.js.map +1 -1
  183. package/dist/esm/Http/Server.js.map +1 -1
  184. package/dist/esm/Http/ServerError.js.map +1 -1
  185. package/dist/esm/Http/ServerRequest.js.map +1 -1
  186. package/dist/esm/Http/ServerResponse.js +35 -0
  187. package/dist/esm/Http/ServerResponse.js.map +1 -1
  188. package/dist/esm/Http/UrlParams.js.map +1 -1
  189. package/dist/esm/HttpClient.js +8 -0
  190. package/dist/esm/HttpClient.js.map +1 -1
  191. package/dist/esm/HttpServer.js +8 -0
  192. package/dist/esm/HttpServer.js.map +1 -1
  193. package/dist/esm/KeyValueStore.js.map +1 -1
  194. package/dist/esm/Path.js.map +1 -1
  195. package/dist/esm/PlatformLogger.js.map +1 -1
  196. package/dist/esm/Runtime.js.map +1 -1
  197. package/dist/esm/Socket.js.map +1 -1
  198. package/dist/esm/Template.js.map +1 -1
  199. package/dist/esm/Terminal.js.map +1 -1
  200. package/dist/esm/Transferable.js.map +1 -1
  201. package/dist/esm/Worker.js.map +1 -1
  202. package/dist/esm/WorkerError.js.map +1 -1
  203. package/dist/esm/WorkerRunner.js.map +1 -1
  204. package/dist/esm/index.js.map +1 -1
  205. package/dist/esm/internal/command.js.map +1 -1
  206. package/dist/esm/internal/commandExecutor.js.map +1 -1
  207. package/dist/esm/internal/effectify.js.map +1 -1
  208. package/dist/esm/internal/error.js.map +1 -1
  209. package/dist/esm/internal/fileSystem.js.map +1 -1
  210. package/dist/esm/internal/http/body.js.map +1 -1
  211. package/dist/esm/internal/http/client.js +4 -0
  212. package/dist/esm/internal/http/client.js.map +1 -1
  213. package/dist/esm/internal/http/clientError.js.map +1 -1
  214. package/dist/esm/internal/http/clientRequest.js.map +1 -1
  215. package/dist/esm/internal/http/clientResponse.js +8 -0
  216. package/dist/esm/internal/http/clientResponse.js.map +1 -1
  217. package/dist/esm/internal/http/etag.js.map +1 -1
  218. package/dist/esm/internal/http/middleware.js.map +1 -1
  219. package/dist/esm/internal/http/multipart.js.map +1 -1
  220. package/dist/esm/internal/http/multiplex.js.map +1 -1
  221. package/dist/esm/internal/http/platform.js.map +1 -1
  222. package/dist/esm/internal/http/router.js.map +1 -1
  223. package/dist/esm/internal/http/server.js.map +1 -1
  224. package/dist/esm/internal/http/serverError.js.map +1 -1
  225. package/dist/esm/internal/http/serverRequest.js +8 -0
  226. package/dist/esm/internal/http/serverRequest.js.map +1 -1
  227. package/dist/esm/internal/http/serverResponse.js +32 -15
  228. package/dist/esm/internal/http/serverResponse.js.map +1 -1
  229. package/dist/esm/internal/keyValueStore.js.map +1 -1
  230. package/dist/esm/internal/path.js.map +1 -1
  231. package/dist/esm/internal/platformLogger.js.map +1 -1
  232. package/dist/esm/internal/terminal.js.map +1 -1
  233. package/dist/esm/internal/worker.js.map +1 -1
  234. package/dist/esm/internal/workerError.js.map +1 -1
  235. package/dist/esm/internal/workerRunner.js.map +1 -1
  236. package/package.json +12 -4
  237. package/src/Http/Client.ts +11 -0
  238. package/src/Http/ClientResponse.ts +2 -0
  239. package/src/Http/Cookies.ts +695 -0
  240. package/src/Http/Headers.ts +16 -8
  241. package/src/Http/ServerRequest.ts +2 -0
  242. package/src/Http/ServerResponse.ts +126 -0
  243. package/src/HttpClient.ts +8 -0
  244. package/src/HttpServer.ts +8 -0
  245. package/src/internal/http/client.ts +35 -0
  246. package/src/internal/http/clientResponse.ts +9 -0
  247. package/src/internal/http/serverRequest.ts +10 -0
  248. package/src/internal/http/serverResponse.ts +162 -0
@@ -0,0 +1,695 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+ import * as Duration from "effect/Duration"
5
+ import * as Either from "effect/Either"
6
+ import { dual } from "effect/Function"
7
+ import * as Inspectable from "effect/Inspectable"
8
+ import * as Option from "effect/Option"
9
+ import { type Pipeable, pipeArguments } from "effect/Pipeable"
10
+ import * as Predicate from "effect/Predicate"
11
+ import * as ReadonlyArray from "effect/ReadonlyArray"
12
+ import type * as Types from "effect/Types"
13
+ import { TypeIdError } from "../Error.js"
14
+
15
+ /**
16
+ * @since 1.0.0
17
+ * @category type ids
18
+ */
19
+ export const TypeId = Symbol.for("@effect/platform/Http/Cookies")
20
+
21
+ /**
22
+ * @since 1.0.0
23
+ * @category type ids
24
+ */
25
+ export type TypeId = typeof TypeId
26
+
27
+ /**
28
+ * @since 1.0.0
29
+ * @category refinements
30
+ */
31
+ export const isCookies = (u: unknown): u is Cookies => Predicate.hasProperty(u, TypeId)
32
+
33
+ /**
34
+ * @since 1.0.0
35
+ * @category models
36
+ */
37
+ export interface Cookies extends Pipeable, Inspectable.Inspectable {
38
+ readonly [TypeId]: TypeId
39
+ readonly cookies: ReadonlyArray<Cookie>
40
+ }
41
+
42
+ /**
43
+ * @since 1.0.0
44
+ * @category type ids
45
+ */
46
+ export const CookieTypeId = Symbol.for("@effect/platform/Http/Cookies/Cookie")
47
+
48
+ /**
49
+ * @since 1.0.0
50
+ * @category type ids
51
+ */
52
+ export type CookieTypeId = typeof CookieTypeId
53
+
54
+ /**
55
+ * @since 1.0.0
56
+ * @category cookie
57
+ */
58
+ export interface Cookie extends Inspectable.Inspectable {
59
+ readonly [CookieTypeId]: CookieTypeId
60
+ readonly name: string
61
+ readonly value: string
62
+ readonly valueEncoded: string
63
+ readonly options?: {
64
+ readonly domain?: string | undefined
65
+ readonly expires?: Date | undefined
66
+ readonly maxAge?: Duration.DurationInput | undefined
67
+ readonly path?: string | undefined
68
+ readonly priority?: "low" | "medium" | "high" | undefined
69
+ readonly httpOnly?: boolean | undefined
70
+ readonly secure?: boolean | undefined
71
+ readonly partitioned?: boolean | undefined
72
+ readonly sameSite?: "lax" | "strict" | "none" | undefined
73
+ } | undefined
74
+ }
75
+
76
+ /**
77
+ * @since 1.0.0
78
+ * @category type ids
79
+ */
80
+ export const ErrorTypeId = Symbol.for("@effect/platform/Http/Cookies/CookieError")
81
+
82
+ /**
83
+ * @since 1.0.0
84
+ * @category type ids
85
+ */
86
+ export type ErrorTypeId = typeof ErrorTypeId
87
+
88
+ /**
89
+ * @since 1.0.0
90
+ * @category errors
91
+ */
92
+ export class CookiesError extends TypeIdError(ErrorTypeId, "CookieError")<{
93
+ readonly reason: "InvalidName" | "InvalidValue" | "InvalidDomain" | "InvalidPath" | "InfinityMaxAge"
94
+ }> {
95
+ get message() {
96
+ return this.reason
97
+ }
98
+ }
99
+
100
+ const Proto: Omit<Cookies, "cookies"> = {
101
+ [TypeId]: TypeId,
102
+ ...Inspectable.BaseProto,
103
+ toJSON(this: Cookies) {
104
+ return {
105
+ _id: "@effect/platform/Http/Cookies",
106
+ cookies: this.cookies.map((cookie) => cookie.toJSON())
107
+ }
108
+ },
109
+ pipe() {
110
+ return pipeArguments(this, arguments)
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Create a Cookies object from an Iterable
116
+ *
117
+ * @since 1.0.0
118
+ * @category constructors
119
+ */
120
+ export const fromIterable = (cookies: Iterable<Cookie>): Cookies => {
121
+ const self = Object.create(Proto)
122
+ self.cookies = ReadonlyArray.fromIterable(cookies)
123
+ return self
124
+ }
125
+
126
+ /**
127
+ * Create a Cookies object from a set of Set-Cookie headers
128
+ *
129
+ * @since 1.0.0
130
+ * @category constructors
131
+ */
132
+ export const fromSetCookie = (headers: Iterable<string> | string): Cookies => {
133
+ const arrayHeaders = typeof headers === "string" ? [headers] : headers
134
+ const cookies: Array<Cookie> = []
135
+ for (const header of arrayHeaders) {
136
+ const cookie = parseSetCookie(header.trim())
137
+ if (Option.isSome(cookie)) {
138
+ cookies.push(cookie.value)
139
+ }
140
+ }
141
+
142
+ return fromIterable(cookies)
143
+ }
144
+
145
+ function parseSetCookie(header: string): Option.Option<Cookie> {
146
+ const parts = header.split(";").map((_) => _.trim()).filter((_) => _ !== "")
147
+ if (parts.length === 0) {
148
+ return Option.none()
149
+ }
150
+
151
+ const firstEqual = parts[0].indexOf("=")
152
+ if (firstEqual === -1) {
153
+ return Option.none()
154
+ }
155
+ const name = parts[0].slice(0, firstEqual)
156
+ if (!fieldContentRegExp.test(name)) {
157
+ return Option.none()
158
+ }
159
+
160
+ const valueEncoded = parts[0].slice(firstEqual + 1)
161
+ const value = tryDecodeURIComponent(valueEncoded)
162
+
163
+ if (parts.length === 1) {
164
+ return Option.some(Object.assign(Object.create(CookieProto), {
165
+ name,
166
+ value,
167
+ valueEncoded
168
+ }))
169
+ }
170
+
171
+ const options: Types.Mutable<Cookie["options"]> = {}
172
+
173
+ for (let i = 1; i < parts.length; i++) {
174
+ const part = parts[i]
175
+ const equalIndex = part.indexOf("=")
176
+ const key = equalIndex === -1 ? part : part.slice(0, equalIndex).trim()
177
+ const value = equalIndex === -1 ? undefined : part.slice(equalIndex + 1).trim()
178
+
179
+ switch (key.toLowerCase()) {
180
+ case "domain": {
181
+ if (value === undefined) {
182
+ break
183
+ }
184
+ const domain = value.trim().replace(/^\./, "")
185
+ if (domain) {
186
+ options.domain = domain
187
+ }
188
+ break
189
+ }
190
+ case "expires": {
191
+ if (value === undefined) {
192
+ break
193
+ }
194
+ const date = new Date(value)
195
+ if (!isNaN(date.getTime())) {
196
+ options.expires = date
197
+ }
198
+ break
199
+ }
200
+ case "max-age": {
201
+ if (value === undefined) {
202
+ break
203
+ }
204
+ const maxAge = parseInt(value, 10)
205
+ if (!isNaN(maxAge)) {
206
+ options.maxAge = Duration.seconds(maxAge)
207
+ }
208
+ break
209
+ }
210
+ case "path": {
211
+ if (value === undefined) {
212
+ break
213
+ }
214
+ if (value[0] === "/") {
215
+ options.path = value
216
+ }
217
+ break
218
+ }
219
+ case "priority": {
220
+ if (value === undefined) {
221
+ break
222
+ }
223
+ switch (value.toLowerCase()) {
224
+ case "low":
225
+ options.priority = "low"
226
+ break
227
+ case "medium":
228
+ options.priority = "medium"
229
+ break
230
+ case "high":
231
+ options.priority = "high"
232
+ break
233
+ }
234
+ break
235
+ }
236
+ case "httponly": {
237
+ options.httpOnly = true
238
+ break
239
+ }
240
+ case "secure": {
241
+ options.secure = true
242
+ break
243
+ }
244
+ case "partitioned": {
245
+ options.partitioned = true
246
+ break
247
+ }
248
+ case "samesite": {
249
+ if (value === undefined) {
250
+ break
251
+ }
252
+ switch (value.toLowerCase()) {
253
+ case "lax":
254
+ options.sameSite = "lax"
255
+ break
256
+ case "strict":
257
+ options.sameSite = "strict"
258
+ break
259
+ case "none":
260
+ options.sameSite = "none"
261
+ break
262
+ }
263
+ break
264
+ }
265
+ }
266
+ }
267
+
268
+ return Option.some(Object.assign(Object.create(CookieProto), {
269
+ name,
270
+ value,
271
+ valueEncoded,
272
+ options: Object.keys(options).length > 0 ? options : undefined
273
+ }))
274
+ }
275
+
276
+ /**
277
+ * An empty Cookies object
278
+ *
279
+ * @since 1.0.0
280
+ * @category constructors
281
+ */
282
+ export const empty: Cookies = fromIterable([])
283
+
284
+ /**
285
+ * @since 1.0.0
286
+ * @category refinements
287
+ */
288
+ export const isEmpty = (self: Cookies): boolean => self.cookies.length === 0
289
+
290
+ // eslint-disable-next-line no-control-regex
291
+ const fieldContentRegExp = /^[\u0009\u0020-\u007e\u0080-\u00ff]+$/
292
+
293
+ const CookieProto = {
294
+ [CookieTypeId]: CookieTypeId,
295
+ ...Inspectable.BaseProto,
296
+ toJSON(this: Cookie) {
297
+ return {
298
+ _id: "@effect/platform/Http/Cookies/Cookie",
299
+ name: this.name,
300
+ value: this.value,
301
+ options: this.options
302
+ }
303
+ }
304
+ }
305
+
306
+ /**
307
+ * Create a new cookie
308
+ *
309
+ * @since 1.0.0
310
+ * @category constructors
311
+ */
312
+ export function makeCookie(
313
+ name: string,
314
+ value: string,
315
+ options?: Cookie["options"] | undefined
316
+ ): Either.Either<Cookie, CookiesError> {
317
+ if (!fieldContentRegExp.test(name)) {
318
+ return Either.left(new CookiesError({ reason: "InvalidName" }))
319
+ }
320
+ const encodedValue = encodeURIComponent(value)
321
+ if (encodedValue && !fieldContentRegExp.test(encodedValue)) {
322
+ return Either.left(new CookiesError({ reason: "InvalidValue" }))
323
+ }
324
+
325
+ if (options !== undefined) {
326
+ if (options.domain !== undefined && !fieldContentRegExp.test(options.domain)) {
327
+ return Either.left(new CookiesError({ reason: "InvalidDomain" }))
328
+ }
329
+
330
+ if (options.path !== undefined && !fieldContentRegExp.test(options.path)) {
331
+ return Either.left(new CookiesError({ reason: "InvalidPath" }))
332
+ }
333
+
334
+ if (options.maxAge !== undefined && !Duration.isFinite(Duration.decode(options.maxAge))) {
335
+ return Either.left(new CookiesError({ reason: "InfinityMaxAge" }))
336
+ }
337
+ }
338
+
339
+ return Either.right(Object.assign(Object.create(CookieProto), {
340
+ name,
341
+ value,
342
+ valueEncoded: encodedValue,
343
+ options
344
+ }))
345
+ }
346
+
347
+ /**
348
+ * Create a new cookie, throwing an error if invalid
349
+ *
350
+ * @since 1.0.0
351
+ * @category constructors
352
+ */
353
+ export const unsafeMakeCookie = (
354
+ name: string,
355
+ value: string,
356
+ options?: Cookie["options"] | undefined
357
+ ): Cookie => Either.getOrThrow(makeCookie(name, value, options))
358
+
359
+ /**
360
+ * Add a cookie to a Cookies object
361
+ *
362
+ * @since 1.0.0
363
+ * @category combinators
364
+ */
365
+ export const append: {
366
+ (cookie: Cookie): (self: Cookies) => Cookies
367
+ (
368
+ self: Cookies,
369
+ cookie: Cookie
370
+ ): Cookies
371
+ } = dual(
372
+ 2,
373
+ (self: Cookies, cookie: Cookie) => fromIterable([...self.cookies, cookie])
374
+ )
375
+
376
+ /**
377
+ * Add multiple cookies to a Cookies object
378
+ *
379
+ * @since 1.0.0
380
+ * @category combinators
381
+ */
382
+ export const appendAll: {
383
+ (cookies: Iterable<Cookie>): (self: Cookies) => Cookies
384
+ (
385
+ self: Cookies,
386
+ cookies: Iterable<Cookie>
387
+ ): Cookies
388
+ } = dual(2, (self: Cookies, cookies: Iterable<Cookie>) =>
389
+ fromIterable(
390
+ ReadonlyArray.appendAll(self.cookies, cookies)
391
+ ))
392
+
393
+ /**
394
+ * Combine two Cookies objects, removing duplicates from the first
395
+ *
396
+ * @since 1.0.0
397
+ * @category combinators
398
+ */
399
+ export const merge: {
400
+ (that: Cookies): (self: Cookies) => Cookies
401
+ (
402
+ self: Cookies,
403
+ that: Cookies
404
+ ): Cookies
405
+ } = dual(2, (self: Cookies, that: Cookies) => {
406
+ const cookies = self.cookies.filter((c) => !that.cookies.some((c2) => c2.name === c.name))
407
+ // eslint-disable-next-line no-restricted-syntax
408
+ cookies.push(...that.cookies)
409
+ return fromIterable(cookies)
410
+ })
411
+
412
+ /**
413
+ * Remove a cookie by name
414
+ *
415
+ * @since 1.0.0
416
+ * @category combinators
417
+ */
418
+ export const remove: {
419
+ (name: string): (self: Cookies) => Cookies
420
+ (
421
+ self: Cookies,
422
+ name: string
423
+ ): Cookies
424
+ } = dual(2, (self: Cookies, cookie: Cookie) =>
425
+ fromIterable(
426
+ self.cookies.filter((c) => c.name !== cookie.name)
427
+ ))
428
+
429
+ /**
430
+ * Add a cookie to a Cookies object
431
+ *
432
+ * @since 1.0.0
433
+ * @category combinators
434
+ */
435
+ export const add: {
436
+ (
437
+ name: string,
438
+ value: string,
439
+ options?: Cookie["options"]
440
+ ): (self: Cookies) => Either.Either<Cookies, CookiesError>
441
+ (
442
+ self: Cookies,
443
+ name: string,
444
+ value: string,
445
+ options?: Cookie["options"]
446
+ ): Either.Either<Cookies, CookiesError>
447
+ } = dual(
448
+ (args) => isCookies(args[0]),
449
+ (self: Cookies, name: string, value: string, options?: Cookie["options"]) =>
450
+ Either.map(
451
+ makeCookie(name, value, options),
452
+ (cookie) => fromIterable([...self.cookies, cookie])
453
+ )
454
+ )
455
+
456
+ /**
457
+ * Add a cookie to a Cookies object
458
+ *
459
+ * @since 1.0.0
460
+ * @category combinators
461
+ */
462
+ export const unsafeAdd: {
463
+ (
464
+ name: string,
465
+ value: string,
466
+ options?: Cookie["options"]
467
+ ): (self: Cookies) => Cookies
468
+ (
469
+ self: Cookies,
470
+ name: string,
471
+ value: string,
472
+ options?: Cookie["options"]
473
+ ): Cookies
474
+ } = dual(
475
+ (args) => isCookies(args[0]),
476
+ (self: Cookies, name: string, value: string, options?: Cookie["options"]) =>
477
+ append(self, unsafeMakeCookie(name, value, options))
478
+ )
479
+
480
+ /**
481
+ * Add multiple cookies to a Cookies object
482
+ *
483
+ * @since 1.0.0
484
+ * @category combinators
485
+ */
486
+ export const addAll: {
487
+ (
488
+ cookies: Iterable<readonly [name: string, value: string, options?: Cookie["options"]]>
489
+ ): (self: Cookies) => Either.Either<Cookies, CookiesError>
490
+ (
491
+ self: Cookies,
492
+ cookies: Iterable<readonly [name: string, value: string, options?: Cookie["options"]]>
493
+ ): Either.Either<Cookies, CookiesError>
494
+ } = dual(
495
+ 2,
496
+ (
497
+ self: Cookies,
498
+ cookies: Iterable<readonly [name: string, value: string, options?: Cookie["options"]]>
499
+ ): Either.Either<Cookies, CookiesError> => {
500
+ const toAdd: Array<Cookie> = []
501
+ for (const [name, value, options] of cookies) {
502
+ const either = makeCookie(name, value, options)
503
+ if (Either.isLeft(either)) {
504
+ return either as Either.Left<CookiesError, never>
505
+ }
506
+ toAdd.push(either.right)
507
+ }
508
+ return Either.right(appendAll(self, toAdd))
509
+ }
510
+ )
511
+
512
+ /**
513
+ * Add multiple cookies to a Cookies object, throwing an error if invalid
514
+ *
515
+ * @since 1.0.0
516
+ * @category combinators
517
+ */
518
+ export const unsafeAddAll: {
519
+ (
520
+ cookies: Iterable<readonly [name: string, value: string, options?: Cookie["options"]]>
521
+ ): (self: Cookies) => Cookies
522
+ (
523
+ self: Cookies,
524
+ cookies: Iterable<readonly [name: string, value: string, options?: Cookie["options"]]>
525
+ ): Cookies
526
+ } = dual(
527
+ 2,
528
+ (
529
+ self: Cookies,
530
+ cookies: Iterable<readonly [name: string, value: string, options?: Cookie["options"]]>
531
+ ): Cookies => Either.getOrThrow(addAll(self, cookies))
532
+ )
533
+
534
+ /**
535
+ * Serialize a cookie into a string
536
+ *
537
+ * Adapted from https://github.com/fastify/fastify-cookie under MIT License
538
+ *
539
+ * @since 1.0.0
540
+ * @category encoding
541
+ */
542
+ export function serializeCookie(self: Cookie): string {
543
+ let str = self.name + "=" + self.valueEncoded
544
+
545
+ if (self.options === undefined) {
546
+ return str
547
+ }
548
+ const options = self.options
549
+
550
+ if (options.maxAge !== undefined) {
551
+ const maxAge = Duration.toSeconds(options.maxAge)
552
+ str += "; Max-Age=" + Math.trunc(maxAge)
553
+ }
554
+
555
+ if (options.domain !== undefined) {
556
+ str += "; Domain=" + options.domain
557
+ }
558
+
559
+ if (options.path !== undefined) {
560
+ str += "; Path=" + options.path
561
+ }
562
+
563
+ if (options.priority !== undefined) {
564
+ switch (options.priority) {
565
+ case "low":
566
+ str += "; Priority=Low"
567
+ break
568
+ case "medium":
569
+ str += "; Priority=Medium"
570
+ break
571
+ case "high":
572
+ str += "; Priority=High"
573
+ break
574
+ }
575
+ }
576
+
577
+ if (options.expires !== undefined) {
578
+ str += "; Expires=" + options.expires.toUTCString()
579
+ }
580
+
581
+ if (options.httpOnly) {
582
+ str += "; HttpOnly"
583
+ }
584
+
585
+ if (options.secure) {
586
+ str += "; Secure"
587
+ }
588
+
589
+ // Draft implementation to support Chrome from 2024-Q1 forward.
590
+ // See https://datatracker.ietf.org/doc/html/draft-cutler-httpbis-partitioned-cookies#section-2.1
591
+ if (options.partitioned) {
592
+ str += "; Partitioned"
593
+ }
594
+
595
+ if (options.sameSite !== undefined) {
596
+ switch (options.sameSite) {
597
+ case "lax":
598
+ str += "; SameSite=Lax"
599
+ break
600
+ case "strict":
601
+ str += "; SameSite=Strict"
602
+ break
603
+ case "none":
604
+ str += "; SameSite=None"
605
+ break
606
+ }
607
+ }
608
+
609
+ return str
610
+ }
611
+
612
+ /**
613
+ * Serialize a Cookies object into a Cookie header
614
+ *
615
+ * @since 1.0.0
616
+ * @category encoding
617
+ */
618
+ export const toCookieHeader = (self: Cookies): string =>
619
+ self.cookies.map((cookie) => `${cookie.name}=${cookie.valueEncoded}`).join("; ")
620
+
621
+ /**
622
+ * To record
623
+ *
624
+ * @since 1.0.0
625
+ * @category encoding
626
+ */
627
+ export const toRecord = (self: Cookies): Record<string, string> => {
628
+ const record: Record<string, string> = {}
629
+ for (let index = 0; index < self.cookies.length; index++) {
630
+ const cookie = self.cookies[index]
631
+ record[cookie.name] = cookie.value
632
+ }
633
+ return record
634
+ }
635
+
636
+ /**
637
+ * Serialize a Cookies object into Headers object containing one or more Set-Cookie headers
638
+ *
639
+ * @since 1.0.0
640
+ * @category encoding
641
+ */
642
+ export const toSetCookieHeaders = (self: Cookies): Array<string> => self.cookies.map(serializeCookie)
643
+
644
+ /**
645
+ * Parse a cookie header into a record of key-value pairs
646
+ *
647
+ * Adapted from https://github.com/fastify/fastify-cookie under MIT License
648
+ *
649
+ * @since 1.0.0
650
+ * @category decoding
651
+ */
652
+ export function parseHeader(header: string): Record<string, string> {
653
+ const result: Record<string, string> = {}
654
+
655
+ const strLen = header.length
656
+ let pos = 0
657
+ let terminatorPos = 0
658
+ // eslint-disable-next-line no-constant-condition
659
+ while (true) {
660
+ if (terminatorPos === strLen) break
661
+ terminatorPos = header.indexOf(";", pos)
662
+ if (terminatorPos === -1) terminatorPos = strLen // This is the last pair
663
+
664
+ let eqIdx = header.indexOf("=", pos)
665
+ if (eqIdx === -1) break // No key-value pairs left
666
+ if (eqIdx > terminatorPos) {
667
+ // Malformed key-value pair
668
+ pos = terminatorPos + 1
669
+ continue
670
+ }
671
+
672
+ const key = header.substring(pos, eqIdx++).trim()
673
+ if (result[key] === undefined) {
674
+ const val = header.charCodeAt(eqIdx) === 0x22
675
+ ? header.substring(eqIdx + 1, terminatorPos - 1).trim()
676
+ : header.substring(eqIdx, terminatorPos).trim()
677
+
678
+ result[key] = !(val.indexOf("%") === -1)
679
+ ? tryDecodeURIComponent(val)
680
+ : val
681
+ }
682
+
683
+ pos = terminatorPos + 1
684
+ }
685
+
686
+ return result
687
+ }
688
+
689
+ const tryDecodeURIComponent = (str: string): string => {
690
+ try {
691
+ return decodeURIComponent(str)
692
+ } catch (_) {
693
+ return str
694
+ }
695
+ }