git.iko.soy/rowtype-yoga/purescript-yoga-fetch-om
on main help sign in
.c8rc.jsonnew file+22
since splitsnapshots
unifiedsplit
@@ -0,0 +1,22 @@
1+{
2+ "all": true,
3+ "include": [
4+ "output/Yoga.Fetch.Om*/index.js",
5+ "output/Yoga.Fetch.Om*/foreign.js"
6+ ],
7+ "exclude": [
8+ "output/Yoga.Fetch.Om.ExtractParams/index.js",
9+ "output/Yoga.Fetch.Om.SplitResponses/index.js"
10+ ],
11+ "reporter": [
12+ "text",
13+ "html",
14+ "lcov"
15+ ],
16+ "reports-dir": "coverage",
17+ "check-coverage": true,
18+ "statements": 95,
19+ "branches": 90,
20+ "functions": 85,
21+ "lines": 95
22+}
.github/workflows/ci.yml+7−2
@@ -12,5 +12,10 @@ jobs:
12 steps:
12 steps:
13 - uses: actions/checkout@v4
13 - uses: actions/checkout@v4
14 - uses: rowtype-yoga/purescript-yoga-actions/.github/actions/setup@main
14 - uses: rowtype-yoga/purescript-yoga-actions/.github/actions/setup@main
15− - run: spago build
15+ - run: bun run coverage
16− - run: spago test
16+ - uses: actions/upload-artifact@v4
17+ if: always()
18+ with:
19+ name: coverage
20+ path: coverage/
21+ - run: bun compile-fail-tests/run.js
.gitignore+2
@@ -1,5 +1,7 @@
1output/
1output/
2output-compile-fail/
2output-compile-fail/
3+coverage/
4+generated-docs/
3node_modules/
5node_modules/
4.spago/
6.spago/
5.psc-ide-port
7.psc-ide-port
LICENSEnew file+21
@@ -0,0 +1,21 @@
1+The MIT License (MIT)
2+
3+Copyright (c) 2026 Mark Eibes
4+
5+Permission is hereby granted, free of charge, to any person obtaining a copy
6+of this software and associated documentation files (the "Software"), to deal
7+in the Software without restriction, including without limitation the rights
8+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+copies of the Software, and to permit persons to whom the Software is
10+furnished to do so, subject to the following conditions:
11+
12+The above copyright notice and this permission notice shall be included in all
13+copies or substantial portions of the Software.
14+
15+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+SOFTWARE.
README.md+74−17
@@ -8,6 +8,34 @@ Derive type-safe fetch clients from `purescript-yoga-http-api` route definitions
8spago install yoga-fetch-om
8spago install yoga-fetch-om
9```
9```
10
10
11+Optional query examples below use [`justifill`](https://pursuit.purescript.org/packages/purescript-justifill):
12+
13+```bash
14+spago install justifill
15+```
16+
17+## Migrating from 0.7
18+
19+Version 0.8 exposes optional query parameters as explicit `Maybe` fields. Calls that passed plain values no longer compile:
20+
21+```purescript
22+-- 0.7: offset omitted
23+users <- api.listUsers { limit: 10 }
24+
25+-- 0.8: every optional field is explicit
26+users <- api.listUsers { limit: Just 10, offset: Nothing }
27+allUsers <- api.listUsers { limit: Nothing, offset: Nothing }
28+```
29+
30+Import `Maybe(..)` from `Data.Maybe` when constructing these records directly. Alternatively, [`justifill`](https://pursuit.purescript.org/packages/purescript-justifill) wraps supplied values in `Just` and fills omitted fields with `Nothing`:
31+
32+```purescript
33+-- offset remains omitted at the call site
34+users <- api.listUsers (justifill { limit: 10 })
35+```
36+
37+Path parameters and request bodies keep their existing argument shapes.
38+
11## Quick Start
39## Quick Start
12
40
13### Example 1: Simple GET and POST Requests
41### Example 1: Simple GET and POST Requests
@@ -30,8 +58,13 @@ main = do
30### Example 2: Type-Safe API Client with Full CRUD
58### Example 2: Type-Safe API Client with Full CRUD
31
59
32```purescript
60```purescript
61+import Justifill (justifill)
62+
33type UserAPI =
63type UserAPI =
64+ { health ::
65+ Route GET "health" {}
66+ ( ok :: { body :: { status :: String } } )
34− { getUser ::
67+ , getUser ::
35 Route GET ("users" / "id" : Int) {}
68 Route GET ("users" / "id" : Int) {}
36 ( ok :: { body :: User }
69 ( ok :: { body :: User }
37 , notFound :: { body :: ErrorMessage }
70 , notFound :: { body :: ErrorMessage }
@@ -59,7 +92,8 @@ type UserAPI =
59
92
60api = client @UserAPI "https://api.example.com"
93api = client @UserAPI "https://api.example.com"
61
94
62−-- Create a user
95+-- Generated methods use ordinary function application.
96+health <- api.health
63user <- api.createUser { name: "Alice", email: "alice@example.com" }
97user <- api.createUser { name: "Alice", email: "alice@example.com" }
64 # handleErrors
98 # handleErrors
65 { badRequest: \err -> do
99 { badRequest: \err -> do
@@ -67,15 +101,21 @@ user <- api.createUser { name: "Alice", email: "alice@example.com" }
67 throw err
101 throw err
68 }
102 }
69
103
70−-- Update with path param + body
104+-- Path parameters and request bodies remain separate arguments.
105+updated <- api.updateUser
106+ { id: user.id }
71−updated <- api.updateUser { id: user.id } { name: "Alice Updated", email: user.email }
107+ { name: "Alice Updated", email: user.email }
72 # handleErrors
108 # handleErrors
73 { notFound: \_ -> throw userNotFound
109 { notFound: \_ -> throw userNotFound
74 , badRequest: \err -> throw validationError
110 , badRequest: \err -> throw validationError
75 }
111 }
76
112
77−-- Query with pagination
113+-- Optional query parameters are explicit `Maybe` fields. Justifill can wrap
114+-- supplied values in `Just` and fill omitted fields with `Nothing`.
78−users <- api.listUsers { limit: 10, offset: 0 }
115+users <- api.listUsers (justifill { limit: 10 })
116+
117+-- The equivalent call without Justifill:
118+allUsers <- api.listUsers { limit: Nothing, offset: Nothing }
79```
119```
80
120
81## More Examples
121## More Examples
@@ -92,10 +132,10 @@ See the test files for complete, runnable examples with all imports:
92
132
93### ✅ Type-Safe Everything
133### ✅ Type-Safe Everything
94
134
95−- **Path parameters**: `/users/:id` requires `{ id: Int }`
135+- **Path parameters**: `/users/:id` requires `{ id :: Int }`; names and values are percent-encoded
96−- **Query parameters**: Type-safe query strings with `?`
136+- **Query parameters**: Type-safe, percent-encoded query strings with explicit `Maybe` fields for optional values
97−- **Request bodies**: Automatic JSON serialization
137+- **Request bodies**: `JSON`, `PlainText`, and URL-encoded `FormData`
98−- **Response bodies**: Automatic JSON parsing
138+- **Response bodies**: Parsed JSON, `PlainText` as `String`, and `Streaming a` as `Strom {} () a`
99- **Error handling**: Exhaustive pattern matching on variants
139- **Error handling**: Exhaustive pattern matching on variants
100
140
101### ✅ Single Source of Truth
141### ✅ Single Source of Truth
@@ -115,12 +155,12 @@ Changes to routes automatically update both client and server!
115### ✅ Automatic Derivation
155### ✅ Automatic Derivation
116
156
117No manual client code:
157No manual client code:
118−- ✅ URL building with path parameter substitution
158+- ✅ URL building with segment-safe path substitution
119−- ✅ Query string construction
159+- ✅ Query construction that preserves existing queries and fragments
120−- ✅ JSON request serialization
160+- ✅ JSON, plain-text, and URL-encoded request serialization
121−- ✅ JSON response parsing
161+- ✅ JSON and plain-text response decoding
162+- ✅ Incremental UTF-8 and binary response streams
122- ✅ Status code → variant mapping
163- ✅ Status code → variant mapping
123−- ✅ CORS and credentials handling
124
164
125### ✅ Integration with yoga-om
165### ✅ Integration with yoga-om
126
166
@@ -140,8 +180,9 @@ The library uses PureScript's type system to:
140
180
1411. **Extract parameters** from route definitions at compile time
1811. **Extract parameters** from route definitions at compile time
142 - Path params: `"users" / "id" : Int` → `{ id :: Int }`
182 - Path params: `"users" / "id" : Int` → `{ id :: Int }`
183+ - Optional query params: `:? { limit :: Int }` → `{ limit :: Maybe Int }`
143− - Query params: `:? { limit :: Int }` → `{ limit :: Int }`
184+ - Required query params: `:? { limit :: Required Int }` → `{ limit :: Int }`
144− - Body params: `{ body :: JSON User }` → request body
185+ - Body params: `{ body :: JSON User }` → `User`
145
186
1462. **Build URLs** automatically
1872. **Build URLs** automatically
147 - Pattern: `/users/:id` + params: `{ id: 42 }` → `/users/42`
188 - Pattern: `/users/:id` + params: `{ id: 42 }` → `/users/42`
@@ -186,6 +227,21 @@ api = client @UserAPI "https://api.example.com"
186- ✅ Variant response handling
227- ✅ Variant response handling
187- ✅ Om monad integration
228- ✅ Om monad integration
188
229
230+## Testing
231+
232+```sh
233+bun test
234+bun run test:compile-fail
235+bun run coverage
236+```
237+The suite combines example-based specifications with QuickCheck properties for
238+URL encoding, suffix preservation, repeated parameters, optional fields, and
239+query-separator invariants.
240+
241+The coverage command uses compiler source maps to report PureScript source
242+coverage, includes JavaScript FFI modules, enforces regression thresholds, and
243+writes HTML and LCOV reports to `coverage/`.
244+
189## License
245## License
190
246
191MIT
247MIT
@@ -196,3 +252,4 @@ MIT
196- [purescript-yoga-fastify-om](https://github.com/rowtype-yoga/purescript-yoga-fastify-om) - Server-side counterpart
252- [purescript-yoga-fastify-om](https://github.com/rowtype-yoga/purescript-yoga-fastify-om) - Server-side counterpart
197- [purescript-yoga-json](https://github.com/rowtype-yoga/purescript-yoga-json) - JSON serialization
253- [purescript-yoga-json](https://github.com/rowtype-yoga/purescript-yoga-json) - JSON serialization
198- [purescript-yoga-om](https://github.com/rowtype-yoga/purescript-yoga-om) - Om monad
254- [purescript-yoga-om](https://github.com/rowtype-yoga/purescript-yoga-om) - Om monad
255+
bun.lock+220−113
@@ -3,11 +3,24 @@
3 "workspaces": {
3 "workspaces": {
4 "": {
4 "": {
5 "name": "purescript-yoga-fetch-om",
5 "name": "purescript-yoga-fetch-om",
6+ "dependencies": {
7+ "pino": "^10.3.1",
8+ },
6 "devDependencies": {
9 "devDependencies": {
10+ "@fastify/cookie": "^11.1.2",
11+ "@fastify/cors": "^11.3.0",
12+ "@fastify/formbody": "^9.0.0",
13+ "@fastify/helmet": "^13.1.0",
14+ "@fastify/multipart": "^10.1.0",
15+ "@fastify/rate-limit": "^11.2.0",
16+ "@fastify/websocket": "^11.3.0",
17+ "argon2": "^0.45.1",
18+ "c8": "^12.0.0",
7 "fastify": "^5.7.4",
19 "fastify": "^5.7.4",
20+ "jose": "^6.2.8",
8 "jsdom": "^28.0.0",
21 "jsdom": "^28.0.0",
9 "purescript": "^0.15.15",
22 "purescript": "^0.15.15",
10− "spago": "0.93.42",
23+ "spago": "^1.0.3",
11 "vitest": "^2.1.8",
24 "vitest": "^2.1.8",
12 },
25 },
13 },
26 },
@@ -21,6 +34,8 @@
21
34
22 "@asamuzakjp/nwsapi": ["@asamuzakjp/nwsapi@2.3.9", "", {}, "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q=="],
35 "@asamuzakjp/nwsapi": ["@asamuzakjp/nwsapi@2.3.9", "", {}, "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q=="],
23
36
37+ "@bcoe/v8-coverage": ["@bcoe/v8-coverage@1.0.2", "", {}, "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA=="],
38+
24 "@csstools/color-helpers": ["@csstools/color-helpers@6.0.1", "", {}, "sha512-NmXRccUJMk2AWA5A7e5a//3bCIMyOu2hAtdRYrhPPHjDxINuCwX1w6rnIZ4xjLcp0ayv6h8Pc3X0eJUGiAAXHQ=="],
39 "@csstools/color-helpers": ["@csstools/color-helpers@6.0.1", "", {}, "sha512-NmXRccUJMk2AWA5A7e5a//3bCIMyOu2hAtdRYrhPPHjDxINuCwX1w6rnIZ4xjLcp0ayv6h8Pc3X0eJUGiAAXHQ=="],
25
40
26 "@csstools/css-calc": ["@csstools/css-calc@3.0.0", "", { "peerDependencies": { "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" } }, "sha512-q4d82GTl8BIlh/dTnVsWmxnbWJeb3kiU8eUH71UxlxnS+WIaALmtzTL8gR15PkYOexMQYVk0CO4qIG93C1IvPA=="],
41 "@csstools/css-calc": ["@csstools/css-calc@3.0.0", "", { "peerDependencies": { "@csstools/css-parser-algorithms": "^4.0.0", "@csstools/css-tokenizer": "^4.0.0" } }, "sha512-q4d82GTl8BIlh/dTnVsWmxnbWJeb3kiU8eUH71UxlxnS+WIaALmtzTL8gR15PkYOexMQYVk0CO4qIG93C1IvPA=="],
@@ -33,6 +48,8 @@
33
48
34 "@csstools/css-tokenizer": ["@csstools/css-tokenizer@4.0.0", "", {}, "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA=="],
49 "@csstools/css-tokenizer": ["@csstools/css-tokenizer@4.0.0", "", {}, "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA=="],
35
50
51+ "@epic-web/invariant": ["@epic-web/invariant@1.0.0", "", {}, "sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA=="],
52+
36 "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.21.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ=="],
53 "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.21.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ=="],
37
54
38 "@esbuild/android-arm": ["@esbuild/android-arm@0.21.5", "", { "os": "android", "cpu": "arm" }, "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg=="],
55 "@esbuild/android-arm": ["@esbuild/android-arm@0.21.5", "", { "os": "android", "cpu": "arm" }, "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg=="],
@@ -83,37 +100,63 @@
83
100
84 "@fastify/ajv-compiler": ["@fastify/ajv-compiler@4.0.5", "", { "dependencies": { "ajv": "^8.12.0", "ajv-formats": "^3.0.1", "fast-uri": "^3.0.0" } }, "sha512-KoWKW+MhvfTRWL4qrhUwAAZoaChluo0m0vbiJlGMt2GXvL4LVPQEjt8kSpHI3IBq5Rez8fg+XeH3cneztq+C7A=="],
101 "@fastify/ajv-compiler": ["@fastify/ajv-compiler@4.0.5", "", { "dependencies": { "ajv": "^8.12.0", "ajv-formats": "^3.0.1", "fast-uri": "^3.0.0" } }, "sha512-KoWKW+MhvfTRWL4qrhUwAAZoaChluo0m0vbiJlGMt2GXvL4LVPQEjt8kSpHI3IBq5Rez8fg+XeH3cneztq+C7A=="],
85
102
103+ "@fastify/busboy": ["@fastify/busboy@3.2.1", "", {}, "sha512-tgK4O+57iz5ycYNGXE5ZWj1ES03lD2XnnBYWSbU/3wYZRMQzCUq7Ycds/RdyBZQeL5MU4fxBt6lzbIWf/Bickw=="],
104+
105+ "@fastify/cookie": ["@fastify/cookie@11.1.2", "", { "dependencies": { "cookie": "^2.0.0", "fastify-plugin": "^6.0.0" } }, "sha512-Dtrpk/YOGUsbRMvP/8ZqPpwnMRv0qSqodFdoQ2B589Obc7jw4s4Qla+cV72Bsm7WsZJnqlYFX/i7uSBq0xzg6g=="],
106+
107+ "@fastify/cors": ["@fastify/cors@11.3.0", "", { "dependencies": { "fastify-plugin": "^6.0.0", "toad-cache": "^3.7.0" } }, "sha512-ggQGua+xHv1MvePbPr0v//xLYEsCXbWspquXCJS9Ot5YoRXq8J8ZWzHnxDBVnbtXosvistXo6LtNzOJswf64Fw=="],
108+
109+ "@fastify/deepmerge": ["@fastify/deepmerge@3.2.1", "", {}, "sha512-N5Oqvltoa2r9z1tbx4xjky0oRR60v+T47Ic4J1ukoVQcptLOrIdRnCSdTGmOmajZuHVKlTnfcmrjyqsGEW1ztA=="],
110+
86 "@fastify/error": ["@fastify/error@4.2.0", "", {}, "sha512-RSo3sVDXfHskiBZKBPRgnQTtIqpi/7zhJOEmAxCiBcM7d0uwdGdxLlsCaLzGs8v8NnxIRlfG0N51p5yFaOentQ=="],
111 "@fastify/error": ["@fastify/error@4.2.0", "", {}, "sha512-RSo3sVDXfHskiBZKBPRgnQTtIqpi/7zhJOEmAxCiBcM7d0uwdGdxLlsCaLzGs8v8NnxIRlfG0N51p5yFaOentQ=="],
87
112
88 "@fastify/fast-json-stringify-compiler": ["@fastify/fast-json-stringify-compiler@5.0.3", "", { "dependencies": { "fast-json-stringify": "^6.0.0" } }, "sha512-uik7yYHkLr6fxd8hJSZ8c+xF4WafPK+XzneQDPU+D10r5X19GW8lJcom2YijX2+qtFF1ENJlHXKFM9ouXNJYgQ=="],
113 "@fastify/fast-json-stringify-compiler": ["@fastify/fast-json-stringify-compiler@5.0.3", "", { "dependencies": { "fast-json-stringify": "^6.0.0" } }, "sha512-uik7yYHkLr6fxd8hJSZ8c+xF4WafPK+XzneQDPU+D10r5X19GW8lJcom2YijX2+qtFF1ENJlHXKFM9ouXNJYgQ=="],
89
114
115+ "@fastify/formbody": ["@fastify/formbody@9.0.0", "", { "dependencies": { "fast-querystring": "^1.1.2", "fastify-plugin": "^6.0.0" } }, "sha512-T/af26CSrUARBCvsEmv+DJLPfZlrRKESzqironxP1j7qzuLyKcoZtj6MuTGShuKx1THXugoie2oFbUJxXfGFzA=="],
116+
90 "@fastify/forwarded": ["@fastify/forwarded@3.0.1", "", {}, "sha512-JqDochHFqXs3C3Ml3gOY58zM7OqO9ENqPo0UqAjAjH8L01fRZqwX9iLeX34//kiJubF7r2ZQHtBRU36vONbLlw=="],
117 "@fastify/forwarded": ["@fastify/forwarded@3.0.1", "", {}, "sha512-JqDochHFqXs3C3Ml3gOY58zM7OqO9ENqPo0UqAjAjH8L01fRZqwX9iLeX34//kiJubF7r2ZQHtBRU36vONbLlw=="],
91
118
119+ "@fastify/helmet": ["@fastify/helmet@13.1.0", "", { "dependencies": { "fastify-plugin": "^6.0.0", "helmet": "^8.0.0" } }, "sha512-SvVOU0IrzYJW1BvSkfq9G1WUdW3dnaRUvg6m0BtgGMBmML62No0VmSu087jecH58SFbicbREgZTPJ89mAguupA=="],
120+
92 "@fastify/merge-json-schemas": ["@fastify/merge-json-schemas@0.2.1", "", { "dependencies": { "dequal": "^2.0.3" } }, "sha512-OA3KGBCy6KtIvLf8DINC5880o5iBlDX4SxzLQS8HorJAbqluzLRn80UXU0bxZn7UOFhFgpRJDasfwn9nG4FG4A=="],
121 "@fastify/merge-json-schemas": ["@fastify/merge-json-schemas@0.2.1", "", { "dependencies": { "dequal": "^2.0.3" } }, "sha512-OA3KGBCy6KtIvLf8DINC5880o5iBlDX4SxzLQS8HorJAbqluzLRn80UXU0bxZn7UOFhFgpRJDasfwn9nG4FG4A=="],
93
122
123+ "@fastify/multipart": ["@fastify/multipart@10.1.0", "", { "dependencies": { "@fastify/busboy": "^3.0.0", "@fastify/deepmerge": "^3.0.0", "@fastify/error": "^4.0.0", "fastify-plugin": "^6.0.0", "secure-json-parse": "^4.0.0" } }, "sha512-b2r6CovmLQvLFJ5HJDtxVigZjcO9TwkRGslhiNQxsGJwilm5B3eqvXPOVLudC44zXMXJITpQ/iEATIE7zoXqcQ=="],
124+
94 "@fastify/proxy-addr": ["@fastify/proxy-addr@5.1.0", "", { "dependencies": { "@fastify/forwarded": "^3.0.0", "ipaddr.js": "^2.1.0" } }, "sha512-INS+6gh91cLUjB+PVHfu1UqcB76Sqtpyp7bnL+FYojhjygvOPA9ctiD/JDKsyD9Xgu4hUhCSJBPig/w7duNajw=="],
125 "@fastify/proxy-addr": ["@fastify/proxy-addr@5.1.0", "", { "dependencies": { "@fastify/forwarded": "^3.0.0", "ipaddr.js": "^2.1.0" } }, "sha512-INS+6gh91cLUjB+PVHfu1UqcB76Sqtpyp7bnL+FYojhjygvOPA9ctiD/JDKsyD9Xgu4hUhCSJBPig/w7duNajw=="],
95
126
127+ "@fastify/rate-limit": ["@fastify/rate-limit@11.2.0", "", { "dependencies": { "@lukeed/ms": "^2.0.2", "fastify-plugin": "^6.0.0", "ip-address": "^10.2.0", "toad-cache": "^3.7.0" } }, "sha512-X7osJd4XSvMoejYrnJkSZYYjY1eNYoBqhjlzf1RakC2204qExFqZFTKj5+T7VuzA/iUI9Z3UoSqQRkB2HpG0oQ=="],
128+
129+ "@fastify/websocket": ["@fastify/websocket@11.3.0", "", { "dependencies": { "duplexify": "^4.1.3", "fastify-plugin": "^6.0.0", "ws": "^8.16.0" } }, "sha512-g89ag4BCcD9YP5wBZXixzoLnuf5j89p/sXFcfpCiv2pdEkYYukBEoK3heVzqsp0EAtszVDc2BBZG0KZqeAShIA=="],
130+
96 "@gar/promisify": ["@gar/promisify@1.1.3", "", {}, "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw=="],
131 "@gar/promisify": ["@gar/promisify@1.1.3", "", {}, "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw=="],
97
132
98− "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="],
133+ "@isaacs/cliui": ["@isaacs/cliui@9.0.0", "", {}, "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg=="],
99
134
100 "@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="],
135 "@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="],
101
136
137+ "@istanbuljs/schema": ["@istanbuljs/schema@0.1.6", "", {}, "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw=="],
138+
139+ "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
140+
102 "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
141 "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
103
142
104− "@nodelib/fs.scandir": ["@nodelib/fs.scandir@3.0.0", "", { "dependencies": { "@nodelib/fs.stat": "3.0.0", "run-parallel": "^1.2.0" } }, "sha512-ktI9+PxfHYtKjF3cLTUAh2N+b8MijCRPNwKJNqTVdL0gB0QxLU2rIRaZ1t71oEa3YBDE6bukH1sR0+CDnpp/Mg=="],
143+ "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
144+
145+ "@lukeed/ms": ["@lukeed/ms@2.0.2", "", {}, "sha512-9I2Zn6+NJLfaGoz9jN3lpwDgAYvfGeNYdbAIjJOqzs4Tpc+VU3Jqq4IofSUBKajiDS8k9fZIg18/z13mpk1bsA=="],
105
146
106− "@nodelib/fs.stat": ["@nodelib/fs.stat@3.0.0", "", {}, "sha512-2tQOI38s19P9i7X/Drt0v8iMA+KMsgdhB/dyPER+e+2Y8L1Z7QvnuRdW/uLuf5YRFUYmnj4bMA6qCuZHFI1GDQ=="],
147+ "@nodelib/fs.scandir": ["@nodelib/fs.scandir@4.0.1", "", { "dependencies": { "@nodelib/fs.stat": "4.0.0", "run-parallel": "^1.2.0" } }, "sha512-vAkI715yhnmiPupY+dq+xenu5Tdf2TBQ66jLvBIcCddtz+5Q8LbMKaf9CIJJreez8fQ8fgaY+RaywQx8RJIWpw=="],
107
148
108− "@nodelib/fs.walk": ["@nodelib/fs.walk@2.0.0", "", { "dependencies": { "@nodelib/fs.scandir": "3.0.0", "fastq": "^1.15.0" } }, "sha512-54voNDBobGdMl3BUXSu7UaDh1P85PGHWlJ5e0XhPugo1JulOyCtp2I+5ri4wplGDJ8QGwPEQW7/x3yTLU7yF1A=="],
149+ "@nodelib/fs.stat": ["@nodelib/fs.stat@4.0.0", "", {}, "sha512-ctr6bByzksKRCV0bavi8WoQevU6plSp2IkllIsEqaiKe2mwNNnaluhnRhcsgGZHrrHk57B3lf95MkLMO3STYcg=="],
150+
151+ "@nodelib/fs.walk": ["@nodelib/fs.walk@3.0.1", "", { "dependencies": { "@nodelib/fs.scandir": "4.0.1", "fastq": "^1.15.0" } }, "sha512-nIh/M6Kh3ZtOmlY00DaUYB4xeeV6F3/ts1l29iwl3/cfyY/OuCfUx+v08zgx8TKPTifXRcjjqVQ4KB2zOYSbyw=="],
109
152
110 "@npmcli/fs": ["@npmcli/fs@2.1.2", "", { "dependencies": { "@gar/promisify": "^1.1.3", "semver": "^7.3.5" } }, "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ=="],
153 "@npmcli/fs": ["@npmcli/fs@2.1.2", "", { "dependencies": { "@gar/promisify": "^1.1.3", "semver": "^7.3.5" } }, "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ=="],
111
154
112 "@npmcli/move-file": ["@npmcli/move-file@2.0.1", "", { "dependencies": { "mkdirp": "^1.0.4", "rimraf": "^3.0.2" } }, "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ=="],
155 "@npmcli/move-file": ["@npmcli/move-file@2.0.1", "", { "dependencies": { "mkdirp": "^1.0.4", "rimraf": "^3.0.2" } }, "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ=="],
113
156
114− "@pinojs/redact": ["@pinojs/redact@0.4.0", "", {}, "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg=="],
157+ "@phc/format": ["@phc/format@1.0.0", "", {}, "sha512-m7X9U6BG2+J+R1lSOdCiITLLrxm+cWlNI3HUFA92oLO77ObGNzaKdh8pMLqdZcshtkKuV84olNNXDfMc4FezBQ=="],
115
158
116− "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="],
159+ "@pinojs/redact": ["@pinojs/redact@0.4.0", "", {}, "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg=="],
117
160
118 "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.57.1", "", { "os": "android", "cpu": "arm" }, "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg=="],
161 "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.57.1", "", { "os": "android", "cpu": "arm" }, "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg=="],
119
162
@@ -169,6 +212,8 @@
169
212
170 "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
213 "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
171
214
215+ "@types/istanbul-lib-coverage": ["@types/istanbul-lib-coverage@2.0.6", "", {}, "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w=="],
216+
172 "@vitest/expect": ["@vitest/expect@2.1.9", "", { "dependencies": { "@vitest/spy": "2.1.9", "@vitest/utils": "2.1.9", "chai": "^5.1.2", "tinyrainbow": "^1.2.0" } }, "sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw=="],
217 "@vitest/expect": ["@vitest/expect@2.1.9", "", { "dependencies": { "@vitest/spy": "2.1.9", "@vitest/utils": "2.1.9", "chai": "^5.1.2", "tinyrainbow": "^1.2.0" } }, "sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw=="],
173
218
174 "@vitest/mocker": ["@vitest/mocker@2.1.9", "", { "dependencies": { "@vitest/spy": "2.1.9", "estree-walker": "^3.0.3", "magic-string": "^0.30.12" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^5.0.0" }, "optionalPeers": ["msw", "vite"] }, "sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg=="],
219 "@vitest/mocker": ["@vitest/mocker@2.1.9", "", { "dependencies": { "@vitest/spy": "2.1.9", "estree-walker": "^3.0.3", "magic-string": "^0.30.12" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^5.0.0" }, "optionalPeers": ["msw", "vite"] }, "sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg=="],
@@ -197,12 +242,14 @@
197
242
198 "ansi-escapes": ["ansi-escapes@4.3.2", "", { "dependencies": { "type-fest": "^0.21.3" } }, "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ=="],
243 "ansi-escapes": ["ansi-escapes@4.3.2", "", { "dependencies": { "type-fest": "^0.21.3" } }, "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ=="],
199
244
200− "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
245+ "ansi-regex": ["ansi-regex@6.3.0", "", {}, "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ=="],
201
246
202 "ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="],
247 "ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="],
203
248
204 "aproba": ["aproba@1.2.0", "", {}, "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="],
249 "aproba": ["aproba@1.2.0", "", {}, "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="],
205
250
251+ "argon2": ["argon2@0.45.1", "", { "dependencies": { "@phc/format": "^1.0.0", "cross-env": "^10.1.0", "node-addon-api": "^8.9.0", "node-gyp-build": "^4.8.4" } }, "sha512-skm+/WCjkGqCQxF7FG1LuZXM5yvbFjgbfiCGsud2oLgaDhh6b6dbH0b1EkghbM+xx4Bj8Ape+KKgixoIlWZicQ=="],
252+
206 "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
253 "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
207
254
208 "asn1": ["asn1@0.2.6", "", { "dependencies": { "safer-buffer": "~2.1.0" } }, "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ=="],
255 "asn1": ["asn1@0.2.6", "", { "dependencies": { "safer-buffer": "~2.1.0" } }, "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ=="],
@@ -215,28 +262,18 @@
215
262
216 "avvio": ["avvio@9.1.0", "", { "dependencies": { "@fastify/error": "^4.0.0", "fastq": "^1.17.1" } }, "sha512-fYASnYi600CsH/j9EQov7lECAniYiBFiiAtBNuZYLA2leLe9qOvZzqYHFjtIj6gD2VMoMLP14834LFWvr4IfDw=="],
263 "avvio": ["avvio@9.1.0", "", { "dependencies": { "@fastify/error": "^4.0.0", "fastq": "^1.17.1" } }, "sha512-fYASnYi600CsH/j9EQov7lECAniYiBFiiAtBNuZYLA2leLe9qOvZzqYHFjtIj6gD2VMoMLP14834LFWvr4IfDw=="],
217
264
218− "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
265+ "balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
219−
220− "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
221
266
222 "bcrypt-pbkdf": ["bcrypt-pbkdf@1.0.2", "", { "dependencies": { "tweetnacl": "^0.14.3" } }, "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w=="],
267 "bcrypt-pbkdf": ["bcrypt-pbkdf@1.0.2", "", { "dependencies": { "tweetnacl": "^0.14.3" } }, "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w=="],
223
268
224− "better-sqlite3": ["better-sqlite3@11.10.0", "", { "dependencies": { "bindings": "^1.5.0", "prebuild-install": "^7.1.1" } }, "sha512-EwhOpyXiOEL/lKzHz9AW1msWFNzGc/z+LzeB3/jnFJpxu+th2yqvzsSWas1v9jgs9+xiXJcD5A8CJxAG2TaghQ=="],
225−
226 "bidi-js": ["bidi-js@1.0.3", "", { "dependencies": { "require-from-string": "^2.0.2" } }, "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw=="],
269 "bidi-js": ["bidi-js@1.0.3", "", { "dependencies": { "require-from-string": "^2.0.2" } }, "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw=="],
227
270
228− "bindings": ["bindings@1.5.0", "", { "dependencies": { "file-uri-to-path": "1.0.0" } }, "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ=="],
229−
230− "bl": ["bl@4.1.0", "", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="],
231−
232 "bluebird": ["bluebird@3.7.2", "", {}, "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="],
271 "bluebird": ["bluebird@3.7.2", "", {}, "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="],
233
272
234− "brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
273+ "brace-expansion": ["brace-expansion@5.0.9", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg=="],
235
274
236 "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
275 "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
237
276
238− "buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="],
239−
240 "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="],
277 "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="],
241
278
242 "buildcheck": ["buildcheck@0.0.7", "", {}, "sha512-lHblz4ahamxpTmnsk+MNTRWsjYKv965MwOrSJyeD588rR3Jcu7swE+0wN5F+PbL5cjgu/9ObkhfzEPuofEMwLA=="],
279 "buildcheck": ["buildcheck@0.0.7", "", {}, "sha512-lHblz4ahamxpTmnsk+MNTRWsjYKv965MwOrSJyeD588rR3Jcu7swE+0wN5F+PbL5cjgu/9ObkhfzEPuofEMwLA=="],
@@ -245,6 +282,8 @@
245
282
246 "byline": ["byline@5.0.0", "", {}, "sha512-s6webAy+R4SR8XVuJWt2V2rGvhnrhxN+9S15GNuTK3wKPOXFF6RNc+8ug2XhH+2s4f+uudG4kUVYmYOQWL2g0Q=="],
283 "byline": ["byline@5.0.0", "", {}, "sha512-s6webAy+R4SR8XVuJWt2V2rGvhnrhxN+9S15GNuTK3wKPOXFF6RNc+8ug2XhH+2s4f+uudG4kUVYmYOQWL2g0Q=="],
247
284
285+ "c8": ["c8@12.0.0", "", { "dependencies": { "@bcoe/v8-coverage": "^1.0.1", "@istanbuljs/schema": "^0.1.3", "find-up": "^5.0.0", "foreground-child": "^3.1.1", "istanbul-lib-coverage": "^3.2.0", "istanbul-lib-report": "^3.0.1", "istanbul-reports": "^3.1.6", "test-exclude": "^8.0.0", "v8-to-istanbul": "^9.0.0", "yargs": "^18.0.0", "yargs-parser": "^21.1.1" }, "peerDependencies": { "monocart-coverage-reports": "^2" }, "optionalPeers": ["monocart-coverage-reports"], "bin": { "c8": "bin/c8.js" } }, "sha512-4zpJvrd1nKWutnnKC2pXkFmb6iM1l+ffN//o1CzlTNwW7GSOs9a1xrLqkC48nU8oEkjmPZLPiwMsIaOvoF4Pqg=="],
286+
248 "cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="],
287 "cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="],
249
288
250 "cacache": ["cacache@11.3.3", "", { "dependencies": { "bluebird": "^3.5.5", "chownr": "^1.1.1", "figgy-pudding": "^3.5.1", "glob": "^7.1.4", "graceful-fs": "^4.1.15", "lru-cache": "^5.1.1", "mississippi": "^3.0.0", "mkdirp": "^0.5.1", "move-concurrently": "^1.0.1", "promise-inflight": "^1.0.1", "rimraf": "^2.6.3", "ssri": "^6.0.1", "unique-filename": "^1.1.1", "y18n": "^4.0.0" } }, "sha512-p8WcneCytvzPxhDvYp31PD039vi77I12W+/KfR9S8AZbaiARFBCpsPJS+9uhWfeBfeAtW7o/4vt3MUqLkbY6nA=="],
289 "cacache": ["cacache@11.3.3", "", { "dependencies": { "bluebird": "^3.5.5", "chownr": "^1.1.1", "figgy-pudding": "^3.5.1", "glob": "^7.1.4", "graceful-fs": "^4.1.15", "lru-cache": "^5.1.1", "mississippi": "^3.0.0", "mkdirp": "^0.5.1", "move-concurrently": "^1.0.1", "promise-inflight": "^1.0.1", "rimraf": "^2.6.3", "ssri": "^6.0.1", "unique-filename": "^1.1.1", "y18n": "^4.0.0" } }, "sha512-p8WcneCytvzPxhDvYp31PD039vi77I12W+/KfR9S8AZbaiARFBCpsPJS+9uhWfeBfeAtW7o/4vt3MUqLkbY6nA=="],
@@ -261,6 +300,8 @@
261
300
262 "cli-cursor": ["cli-cursor@3.1.0", "", { "dependencies": { "restore-cursor": "^3.1.0" } }, "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw=="],
301 "cli-cursor": ["cli-cursor@3.1.0", "", { "dependencies": { "restore-cursor": "^3.1.0" } }, "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw=="],
263
302
303+ "cliui": ["cliui@9.0.1", "", { "dependencies": { "string-width": "^7.2.0", "strip-ansi": "^7.1.0", "wrap-ansi": "^9.0.0" } }, "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w=="],
304+
264 "color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="],
305 "color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="],
265
306
266 "color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="],
307 "color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="],
@@ -269,7 +310,9 @@
269
310
270 "concat-stream": ["concat-stream@1.6.2", "", { "dependencies": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^2.2.2", "typedarray": "^0.0.6" } }, "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw=="],
311 "concat-stream": ["concat-stream@1.6.2", "", { "dependencies": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^2.2.2", "typedarray": "^0.0.6" } }, "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw=="],
271
312
272− "cookie": ["cookie@1.1.1", "", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="],
313+ "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
314+
315+ "cookie": ["cookie@2.0.1", "", {}, "sha512-yuToqVvRrj6pfDXREyQAAv8SkAEk/8GS3jQRTiUMm66TVtBYmqQeoEjL2Lmq8Rpo6271vH76InTChTitEAm65w=="],
273
316
274 "copy-concurrently": ["copy-concurrently@1.0.5", "", { "dependencies": { "aproba": "^1.1.1", "fs-write-stream-atomic": "^1.0.8", "iferr": "^0.1.5", "mkdirp": "^0.5.1", "rimraf": "^2.5.4", "run-queue": "^1.0.0" } }, "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A=="],
317 "copy-concurrently": ["copy-concurrently@1.0.5", "", { "dependencies": { "aproba": "^1.1.1", "fs-write-stream-atomic": "^1.0.8", "iferr": "^0.1.5", "mkdirp": "^0.5.1", "rimraf": "^2.5.4", "run-queue": "^1.0.0" } }, "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A=="],
275
318
@@ -277,6 +320,8 @@
277
320
278 "cpu-features": ["cpu-features@0.0.10", "", { "dependencies": { "buildcheck": "~0.0.6", "nan": "^2.19.0" } }, "sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA=="],
321 "cpu-features": ["cpu-features@0.0.10", "", { "dependencies": { "buildcheck": "~0.0.6", "nan": "^2.19.0" } }, "sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA=="],
279
322
323+ "cross-env": ["cross-env@10.1.0", "", { "dependencies": { "@epic-web/invariant": "^1.0.0", "cross-spawn": "^7.0.6" }, "bin": { "cross-env": "dist/bin/cross-env.js", "cross-env-shell": "dist/bin/cross-env-shell.js" } }, "sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw=="],
324+
280 "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
325 "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
281
326
282 "css-tree": ["css-tree@3.1.0", "", { "dependencies": { "mdn-data": "2.12.2", "source-map-js": "^1.0.1" } }, "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w=="],
327 "css-tree": ["css-tree@3.1.0", "", { "dependencies": { "mdn-data": "2.12.2", "source-map-js": "^1.0.1" } }, "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w=="],
@@ -291,12 +336,8 @@
291
336
292 "decimal.js": ["decimal.js@10.6.0", "", {}, "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg=="],
337 "decimal.js": ["decimal.js@10.6.0", "", {}, "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg=="],
293
338
294− "decompress-response": ["decompress-response@6.0.0", "", { "dependencies": { "mimic-response": "^3.1.0" } }, "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ=="],
295−
296 "deep-eql": ["deep-eql@5.0.2", "", {}, "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q=="],
339 "deep-eql": ["deep-eql@5.0.2", "", {}, "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q=="],
297
340
298− "deep-extend": ["deep-extend@0.6.0", "", {}, "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="],
299−
300 "default-browser": ["default-browser@5.5.0", "", { "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" } }, "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw=="],
341 "default-browser": ["default-browser@5.5.0", "", { "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" } }, "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw=="],
301
342
302 "default-browser-id": ["default-browser-id@5.0.1", "", {}, "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q=="],
343 "default-browser-id": ["default-browser-id@5.0.1", "", {}, "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q=="],
@@ -305,13 +346,9 @@
305
346
306 "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="],
347 "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="],
307
348
308− "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
349+ "duplexify": ["duplexify@4.1.3", "", { "dependencies": { "end-of-stream": "^1.4.1", "inherits": "^2.0.3", "readable-stream": "^3.1.1", "stream-shift": "^1.0.2" } }, "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA=="],
309−
310− "duplexify": ["duplexify@3.7.1", "", { "dependencies": { "end-of-stream": "^1.0.0", "inherits": "^2.0.1", "readable-stream": "^2.0.0", "stream-shift": "^1.0.0" } }, "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g=="],
311
350
312− "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],
351+ "emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],
313−
314− "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
315
352
316 "encoding": ["encoding@0.1.13", "", { "dependencies": { "iconv-lite": "^0.6.2" } }, "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A=="],
353 "encoding": ["encoding@0.1.13", "", { "dependencies": { "iconv-lite": "^0.6.2" } }, "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A=="],
317
354
@@ -327,14 +364,14 @@
327
364
328 "esbuild": ["esbuild@0.21.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.21.5", "@esbuild/android-arm": "0.21.5", "@esbuild/android-arm64": "0.21.5", "@esbuild/android-x64": "0.21.5", "@esbuild/darwin-arm64": "0.21.5", "@esbuild/darwin-x64": "0.21.5", "@esbuild/freebsd-arm64": "0.21.5", "@esbuild/freebsd-x64": "0.21.5", "@esbuild/linux-arm": "0.21.5", "@esbuild/linux-arm64": "0.21.5", "@esbuild/linux-ia32": "0.21.5", "@esbuild/linux-loong64": "0.21.5", "@esbuild/linux-mips64el": "0.21.5", "@esbuild/linux-ppc64": "0.21.5", "@esbuild/linux-riscv64": "0.21.5", "@esbuild/linux-s390x": "0.21.5", "@esbuild/linux-x64": "0.21.5", "@esbuild/netbsd-x64": "0.21.5", "@esbuild/openbsd-x64": "0.21.5", "@esbuild/sunos-x64": "0.21.5", "@esbuild/win32-arm64": "0.21.5", "@esbuild/win32-ia32": "0.21.5", "@esbuild/win32-x64": "0.21.5" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw=="],
365 "esbuild": ["esbuild@0.21.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.21.5", "@esbuild/android-arm": "0.21.5", "@esbuild/android-arm64": "0.21.5", "@esbuild/android-x64": "0.21.5", "@esbuild/darwin-arm64": "0.21.5", "@esbuild/darwin-x64": "0.21.5", "@esbuild/freebsd-arm64": "0.21.5", "@esbuild/freebsd-x64": "0.21.5", "@esbuild/linux-arm": "0.21.5", "@esbuild/linux-arm64": "0.21.5", "@esbuild/linux-ia32": "0.21.5", "@esbuild/linux-loong64": "0.21.5", "@esbuild/linux-mips64el": "0.21.5", "@esbuild/linux-ppc64": "0.21.5", "@esbuild/linux-riscv64": "0.21.5", "@esbuild/linux-s390x": "0.21.5", "@esbuild/linux-x64": "0.21.5", "@esbuild/netbsd-x64": "0.21.5", "@esbuild/openbsd-x64": "0.21.5", "@esbuild/sunos-x64": "0.21.5", "@esbuild/win32-arm64": "0.21.5", "@esbuild/win32-ia32": "0.21.5", "@esbuild/win32-x64": "0.21.5" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw=="],
329
366
367+ "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
368+
330 "escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="],
369 "escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="],
331
370
332 "estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="],
371 "estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="],
333
372
334 "execa": ["execa@2.1.0", "", { "dependencies": { "cross-spawn": "^7.0.0", "get-stream": "^5.0.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^3.0.0", "onetime": "^5.1.0", "p-finally": "^2.0.0", "signal-exit": "^3.0.2", "strip-final-newline": "^2.0.0" } }, "sha512-Y/URAVapfbYy2Xp/gb6A0E7iR8xeqOCXsuuaoMn7A5PzrXUK84E1gyiEfq0wQd/GHA6GsoHWwhNq8anb0mleIw=="],
373 "execa": ["execa@2.1.0", "", { "dependencies": { "cross-spawn": "^7.0.0", "get-stream": "^5.0.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^3.0.0", "onetime": "^5.1.0", "p-finally": "^2.0.0", "signal-exit": "^3.0.2", "strip-final-newline": "^2.0.0" } }, "sha512-Y/URAVapfbYy2Xp/gb6A0E7iR8xeqOCXsuuaoMn7A5PzrXUK84E1gyiEfq0wQd/GHA6GsoHWwhNq8anb0mleIw=="],
335
374
336− "expand-template": ["expand-template@2.0.3", "", {}, "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg=="],
337−
338 "expect-type": ["expect-type@1.3.0", "", {}, "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA=="],
375 "expect-type": ["expect-type@1.3.0", "", {}, "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA=="],
339
376
340 "fast-decode-uri-component": ["fast-decode-uri-component@1.0.1", "", {}, "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="],
377 "fast-decode-uri-component": ["fast-decode-uri-component@1.0.1", "", {}, "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="],
@@ -349,26 +386,26 @@
349
386
350 "fastify": ["fastify@5.7.4", "", { "dependencies": { "@fastify/ajv-compiler": "^4.0.5", "@fastify/error": "^4.0.0", "@fastify/fast-json-stringify-compiler": "^5.0.0", "@fastify/proxy-addr": "^5.0.0", "abstract-logging": "^2.0.1", "avvio": "^9.0.0", "fast-json-stringify": "^6.0.0", "find-my-way": "^9.0.0", "light-my-request": "^6.0.0", "pino": "^10.1.0", "process-warning": "^5.0.0", "rfdc": "^1.3.1", "secure-json-parse": "^4.0.0", "semver": "^7.6.0", "toad-cache": "^3.7.0" } }, "sha512-e6l5NsRdaEP8rdD8VR0ErJASeyaRbzXYpmkrpr2SuvuMq6Si3lvsaVy5C+7gLanEkvjpMDzBXWE5HPeb/hgTxA=="],
387 "fastify": ["fastify@5.7.4", "", { "dependencies": { "@fastify/ajv-compiler": "^4.0.5", "@fastify/error": "^4.0.0", "@fastify/fast-json-stringify-compiler": "^5.0.0", "@fastify/proxy-addr": "^5.0.0", "abstract-logging": "^2.0.1", "avvio": "^9.0.0", "fast-json-stringify": "^6.0.0", "find-my-way": "^9.0.0", "light-my-request": "^6.0.0", "pino": "^10.1.0", "process-warning": "^5.0.0", "rfdc": "^1.3.1", "secure-json-parse": "^4.0.0", "semver": "^7.6.0", "toad-cache": "^3.7.0" } }, "sha512-e6l5NsRdaEP8rdD8VR0ErJASeyaRbzXYpmkrpr2SuvuMq6Si3lvsaVy5C+7gLanEkvjpMDzBXWE5HPeb/hgTxA=="],
351
388
389+ "fastify-plugin": ["fastify-plugin@6.0.0", "", {}, "sha512-fZOty7z3O7vOliF6d8bHE3wiEh1KcNnKEQensSgTk9C1DvN6nRLS++XVd86v33Hw/8u9Un8A1zDrQ8ujcQDHEg=="],
390+
352 "fastq": ["fastq@1.20.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw=="],
391 "fastq": ["fastq@1.20.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw=="],
353
392
354 "figgy-pudding": ["figgy-pudding@3.5.2", "", {}, "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw=="],
393 "figgy-pudding": ["figgy-pudding@3.5.2", "", {}, "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw=="],
355
394
356− "file-uri-to-path": ["file-uri-to-path@1.0.0", "", {}, "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="],
357−
358 "filesize": ["filesize@4.2.1", "", {}, "sha512-bP82Hi8VRZX/TUBKfE24iiUGsB/sfm2WUrwTQyAzQrhO3V9IhcBBNBXMyzLY5orACxRyYJ3d2HeRVX+eFv4lmA=="],
395 "filesize": ["filesize@4.2.1", "", {}, "sha512-bP82Hi8VRZX/TUBKfE24iiUGsB/sfm2WUrwTQyAzQrhO3V9IhcBBNBXMyzLY5orACxRyYJ3d2HeRVX+eFv4lmA=="],
359
396
360 "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
397 "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
361
398
362 "find-my-way": ["find-my-way@9.4.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-querystring": "^1.0.0", "safe-regex2": "^5.0.0" } }, "sha512-5Ye4vHsypZRYtS01ob/iwHzGRUDELlsoCftI/OZFhcLs1M0tkGPcXldE80TAZC5yYuJMBPJQQ43UHlqbJWiX2w=="],
399 "find-my-way": ["find-my-way@9.4.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-querystring": "^1.0.0", "safe-regex2": "^5.0.0" } }, "sha512-5Ye4vHsypZRYtS01ob/iwHzGRUDELlsoCftI/OZFhcLs1M0tkGPcXldE80TAZC5yYuJMBPJQQ43UHlqbJWiX2w=="],
363
400
401+ "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="],
402+
364 "flush-write-stream": ["flush-write-stream@1.1.1", "", { "dependencies": { "inherits": "^2.0.3", "readable-stream": "^2.3.6" } }, "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w=="],
403 "flush-write-stream": ["flush-write-stream@1.1.1", "", { "dependencies": { "inherits": "^2.0.3", "readable-stream": "^2.3.6" } }, "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w=="],
365
404
366 "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="],
405 "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="],
367
406
368 "from2": ["from2@2.3.0", "", { "dependencies": { "inherits": "^2.0.1", "readable-stream": "^2.0.0" } }, "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g=="],
407 "from2": ["from2@2.3.0", "", { "dependencies": { "inherits": "^2.0.1", "readable-stream": "^2.0.0" } }, "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g=="],
369
408
370− "fs-constants": ["fs-constants@1.0.0", "", {}, "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="],
371−
372 "fs-extra": ["fs-extra@11.3.3", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg=="],
409 "fs-extra": ["fs-extra@11.3.3", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg=="],
373
410
374 "fs-minipass": ["fs-minipass@2.1.0", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg=="],
411 "fs-minipass": ["fs-minipass@2.1.0", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg=="],
@@ -381,18 +418,24 @@
381
418
382 "fuse.js": ["fuse.js@7.1.0", "", {}, "sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ=="],
419 "fuse.js": ["fuse.js@7.1.0", "", {}, "sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ=="],
383
420
384− "get-stream": ["get-stream@5.2.0", "", { "dependencies": { "pump": "^3.0.0" } }, "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA=="],
421+ "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="],
385
422
386− "github-from-package": ["github-from-package@0.0.0", "", {}, "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw=="],
423+ "get-east-asian-width": ["get-east-asian-width@1.6.0", "", {}, "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA=="],
424+
425+ "get-stream": ["get-stream@5.2.0", "", { "dependencies": { "pump": "^3.0.0" } }, "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA=="],
387
426
388− "glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="],
427+ "glob": ["glob@11.1.0", "", { "dependencies": { "foreground-child": "^3.3.1", "jackspeak": "^4.1.1", "minimatch": "^10.1.1", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^2.0.0" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw=="],
389
428
390 "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
429 "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
391
430
392− "has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="],
431+ "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
432+
433+ "helmet": ["helmet@8.3.0", "", {}, "sha512-Qgpiaws3Sm30Av8Eah6sjMCZZwjlBu+E68rhpCWBshY1lb09HtLwj5GviX0OyQIn+ulUS0iX0AxN5n3tLZzz1w=="],
393
434
394 "html-encoding-sniffer": ["html-encoding-sniffer@6.0.0", "", { "dependencies": { "@exodus/bytes": "^1.6.0" } }, "sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg=="],
435 "html-encoding-sniffer": ["html-encoding-sniffer@6.0.0", "", { "dependencies": { "@exodus/bytes": "^1.6.0" } }, "sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg=="],
395
436
437+ "html-escaper": ["html-escaper@2.0.2", "", {}, "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg=="],
438+
396 "http-cache-semantics": ["http-cache-semantics@4.2.0", "", {}, "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ=="],
439 "http-cache-semantics": ["http-cache-semantics@4.2.0", "", {}, "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ=="],
397
440
398 "http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="],
441 "http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="],
@@ -403,8 +446,6 @@
403
446
404 "iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
447 "iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
405
448
406− "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
407−
408 "iferr": ["iferr@0.1.5", "", {}, "sha512-DUNFN5j7Tln0D+TxzloUjKB+CtVu6myn0JEFak6dG18mNt9YkQ6lzGCdafwofISZ1lLF3xRHJ98VKy9ynkcFaA=="],
449 "iferr": ["iferr@0.1.5", "", {}, "sha512-DUNFN5j7Tln0D+TxzloUjKB+CtVu6myn0JEFak6dG18mNt9YkQ6lzGCdafwofISZ1lLF3xRHJ98VKy9ynkcFaA=="],
409
450
410 "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="],
451 "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="],
@@ -417,9 +458,7 @@
417
458
418 "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
459 "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
419
460
420− "ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="],
461+ "ip-address": ["ip-address@10.5.0", "", {}, "sha512-R5SnVLJmgYYvf2F2ZgwSBnelz5G4q5AxIC277GDfUaNbrZKNANcBC7RHqYYePlszf4kBolVkJauG0ZjHHFh55g=="],
421−
422− "ip-address": ["ip-address@10.1.0", "", {}, "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q=="],
423
462
424 "ipaddr.js": ["ipaddr.js@2.3.0", "", {}, "sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg=="],
463 "ipaddr.js": ["ipaddr.js@2.3.0", "", {}, "sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg=="],
425
464
@@ -445,7 +484,15 @@
445
484
446 "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
485 "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
447
486
448− "jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="],
487+ "istanbul-lib-coverage": ["istanbul-lib-coverage@3.2.2", "", {}, "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg=="],
488+
489+ "istanbul-lib-report": ["istanbul-lib-report@3.0.1", "", { "dependencies": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^4.0.0", "supports-color": "^7.1.0" } }, "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw=="],
490+
491+ "istanbul-reports": ["istanbul-reports@3.2.0", "", { "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" } }, "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA=="],
492+
493+ "jackspeak": ["jackspeak@4.2.3", "", { "dependencies": { "@isaacs/cliui": "^9.0.0" } }, "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg=="],
494+
495+ "jose": ["jose@6.2.8", "", {}, "sha512-Bsdjwm3Qsd/P0jR+BHDe3LytDfY7WBq2HmCCLIwuVRHMuEC9ae7/R474GIUdF1NgCyZjzVo/A9DOiOBtXq8ZoQ=="],
449
496
450 "jsdom": ["jsdom@28.0.0", "", { "dependencies": { "@acemir/cssom": "^0.9.31", "@asamuzakjp/dom-selector": "^6.7.6", "@exodus/bytes": "^1.11.0", "cssstyle": "^5.3.7", "data-urls": "^7.0.0", "decimal.js": "^10.6.0", "html-encoding-sniffer": "^6.0.0", "http-proxy-agent": "^7.0.2", "https-proxy-agent": "^7.0.6", "is-potential-custom-element-name": "^1.0.1", "parse5": "^8.0.0", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", "tough-cookie": "^6.0.0", "undici": "^7.20.0", "w3c-xmlserializer": "^5.0.0", "webidl-conversions": "^8.0.1", "whatwg-mimetype": "^5.0.0", "whatwg-url": "^16.0.0", "xml-name-validator": "^5.0.0" }, "peerDependencies": { "canvas": "^3.0.0" }, "optionalPeers": ["canvas"] }, "sha512-KDYJgZ6T2TKdU8yBfYueq5EPG/EylMsBvCaenWMJb2OXmjgczzwveRCoJ+Hgj1lXPDyasvrgneSn4GBuR1hYyA=="],
497 "jsdom": ["jsdom@28.0.0", "", { "dependencies": { "@acemir/cssom": "^0.9.31", "@asamuzakjp/dom-selector": "^6.7.6", "@exodus/bytes": "^1.11.0", "cssstyle": "^5.3.7", "data-urls": "^7.0.0", "decimal.js": "^10.6.0", "html-encoding-sniffer": "^6.0.0", "http-proxy-agent": "^7.0.2", "https-proxy-agent": "^7.0.6", "is-potential-custom-element-name": "^1.0.1", "parse5": "^8.0.0", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", "tough-cookie": "^6.0.0", "undici": "^7.20.0", "w3c-xmlserializer": "^5.0.0", "webidl-conversions": "^8.0.1", "whatwg-mimetype": "^5.0.0", "whatwg-url": "^16.0.0", "xml-name-validator": "^5.0.0" }, "peerDependencies": { "canvas": "^3.0.0" }, "optionalPeers": ["canvas"] }, "sha512-KDYJgZ6T2TKdU8yBfYueq5EPG/EylMsBvCaenWMJb2OXmjgczzwveRCoJ+Hgj1lXPDyasvrgneSn4GBuR1hYyA=="],
451
498
@@ -459,6 +506,8 @@
459
506
460 "linkify-it": ["linkify-it@5.0.0", "", { "dependencies": { "uc.micro": "^2.0.0" } }, "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ=="],
507 "linkify-it": ["linkify-it@5.0.0", "", { "dependencies": { "uc.micro": "^2.0.0" } }, "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ=="],
461
508
509+ "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="],
510+
462 "log-symbols": ["log-symbols@3.0.0", "", { "dependencies": { "chalk": "^2.4.2" } }, "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ=="],
511 "log-symbols": ["log-symbols@3.0.0", "", { "dependencies": { "chalk": "^2.4.2" } }, "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ=="],
463
512
464 "log-update": ["log-update@4.0.0", "", { "dependencies": { "ansi-escapes": "^4.3.0", "cli-cursor": "^3.1.0", "slice-ansi": "^4.0.0", "wrap-ansi": "^6.2.0" } }, "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg=="],
513 "log-update": ["log-update@4.0.0", "", { "dependencies": { "ansi-escapes": "^4.3.0", "cli-cursor": "^3.1.0", "slice-ansi": "^4.0.0", "wrap-ansi": "^6.2.0" } }, "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg=="],
@@ -469,6 +518,8 @@
469
518
470 "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
519 "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
471
520
521+ "make-dir": ["make-dir@4.0.0", "", { "dependencies": { "semver": "^7.5.3" } }, "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw=="],
522+
472 "make-fetch-happen": ["make-fetch-happen@10.2.1", "", { "dependencies": { "agentkeepalive": "^4.2.1", "cacache": "^16.1.0", "http-cache-semantics": "^4.1.0", "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0", "is-lambda": "^1.0.1", "lru-cache": "^7.7.1", "minipass": "^3.1.6", "minipass-collect": "^1.0.2", "minipass-fetch": "^2.0.3", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^0.6.3", "promise-retry": "^2.0.1", "socks-proxy-agent": "^7.0.0", "ssri": "^9.0.0" } }, "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w=="],
523 "make-fetch-happen": ["make-fetch-happen@10.2.1", "", { "dependencies": { "agentkeepalive": "^4.2.1", "cacache": "^16.1.0", "http-cache-semantics": "^4.1.0", "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0", "is-lambda": "^1.0.1", "lru-cache": "^7.7.1", "minipass": "^3.1.6", "minipass-collect": "^1.0.2", "minipass-fetch": "^2.0.3", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^0.6.3", "promise-retry": "^2.0.1", "socks-proxy-agent": "^7.0.0", "ssri": "^9.0.0" } }, "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w=="],
473
524
474 "markdown-it": ["markdown-it@14.1.0", "", { "dependencies": { "argparse": "^2.0.1", "entities": "^4.4.0", "linkify-it": "^5.0.0", "mdurl": "^2.0.0", "punycode.js": "^2.3.1", "uc.micro": "^2.1.0" }, "bin": { "markdown-it": "bin/markdown-it.mjs" } }, "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg=="],
525 "markdown-it": ["markdown-it@14.1.0", "", { "dependencies": { "argparse": "^2.0.1", "entities": "^4.4.0", "linkify-it": "^5.0.0", "mdurl": "^2.0.0", "punycode.js": "^2.3.1", "uc.micro": "^2.1.0" }, "bin": { "markdown-it": "bin/markdown-it.mjs" } }, "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg=="],
@@ -483,9 +534,7 @@
483
534
484 "mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="],
535 "mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="],
485
536
486− "mimic-response": ["mimic-response@3.1.0", "", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="],
537+ "minimatch": ["minimatch@10.2.6", "", { "dependencies": { "brace-expansion": "^5.0.8" } }, "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A=="],
487−
488− "minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
489
538
490 "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
539 "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
491
540
@@ -507,8 +556,6 @@
507
556
508 "mkdirp": ["mkdirp@0.5.6", "", { "dependencies": { "minimist": "^1.2.6" }, "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw=="],
557 "mkdirp": ["mkdirp@0.5.6", "", { "dependencies": { "minimist": "^1.2.6" }, "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw=="],
509
558
510− "mkdirp-classic": ["mkdirp-classic@0.5.3", "", {}, "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="],
511−
512 "move-concurrently": ["move-concurrently@1.0.1", "", { "dependencies": { "aproba": "^1.1.1", "copy-concurrently": "^1.0.0", "fs-write-stream-atomic": "^1.0.8", "mkdirp": "^0.5.1", "rimraf": "^2.5.4", "run-queue": "^1.0.3" } }, "sha512-hdrFxZOycD/g6A6SoI2bB5NA/5NEqD0569+S47WZhPvm46sD50ZHdYaFmnua5lndde9rCHGjmfK7Z8BuCt/PcQ=="],
559 "move-concurrently": ["move-concurrently@1.0.1", "", { "dependencies": { "aproba": "^1.1.1", "copy-concurrently": "^1.0.0", "fs-write-stream-atomic": "^1.0.8", "mkdirp": "^0.5.1", "rimraf": "^2.5.4", "run-queue": "^1.0.3" } }, "sha512-hdrFxZOycD/g6A6SoI2bB5NA/5NEqD0569+S47WZhPvm46sD50ZHdYaFmnua5lndde9rCHGjmfK7Z8BuCt/PcQ=="],
513
560
514 "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
561 "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
@@ -517,11 +564,11 @@
517
564
518 "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
565 "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
519
566
520− "napi-build-utils": ["napi-build-utils@2.0.0", "", {}, "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA=="],
521−
522 "negotiator": ["negotiator@0.6.4", "", {}, "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w=="],
567 "negotiator": ["negotiator@0.6.4", "", {}, "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w=="],
523
568
524− "node-abi": ["node-abi@3.87.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-+CGM1L1CgmtheLcBuleyYOn7NWPVu0s0EJH2C4puxgEZb9h8QpR9G2dBfZJOAUhi7VQxuBPMd0hiISWcTyiYyQ=="],
569+ "node-addon-api": ["node-addon-api@8.9.2", "", {}, "sha512-VijLXbi3UACN69I0JVXJsX4tjACjNoQDgv2gTF6sx2wWEi8tkSg2eX8p5gSIFi8z2+DL3oHmY6OyKce38SDolg=="],
570+
571+ "node-gyp-build": ["node-gyp-build@4.8.4", "", { "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", "node-gyp-build-test": "build-test.js" } }, "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ=="],
525
572
526 "npm-run-path": ["npm-run-path@3.1.0", "", { "dependencies": { "path-key": "^3.0.0" } }, "sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg=="],
573 "npm-run-path": ["npm-run-path@3.1.0", "", { "dependencies": { "path-key": "^3.0.0" } }, "sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg=="],
527
574
@@ -535,6 +582,10 @@
535
582
536 "p-finally": ["p-finally@2.0.1", "", {}, "sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw=="],
583 "p-finally": ["p-finally@2.0.1", "", {}, "sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw=="],
537
584
585+ "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="],
586+
587+ "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="],
588+
538 "p-map": ["p-map@4.0.0", "", { "dependencies": { "aggregate-error": "^3.0.0" } }, "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ=="],
589 "p-map": ["p-map@4.0.0", "", { "dependencies": { "aggregate-error": "^3.0.0" } }, "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ=="],
539
590
540 "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="],
591 "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="],
@@ -543,11 +594,13 @@
543
594
544 "parse5": ["parse5@8.0.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA=="],
595 "parse5": ["parse5@8.0.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA=="],
545
596
597+ "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="],
598+
546 "path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="],
599 "path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="],
547
600
548 "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
601 "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
549
602
550− "path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
603+ "path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="],
551
604
552 "pathe": ["pathe@1.1.2", "", {}, "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="],
605 "pathe": ["pathe@1.1.2", "", {}, "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="],
553
606
@@ -565,8 +618,6 @@
565
618
566 "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
619 "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
567
620
568− "prebuild-install": ["prebuild-install@7.1.3", "", { "dependencies": { "detect-libc": "^2.0.0", "expand-template": "^2.0.3", "github-from-package": "0.0.0", "minimist": "^1.2.3", "mkdirp-classic": "^0.5.3", "napi-build-utils": "^2.0.0", "node-abi": "^3.3.0", "pump": "^3.0.0", "rc": "^1.2.7", "simple-get": "^4.0.0", "tar-fs": "^2.0.0", "tunnel-agent": "^0.6.0" }, "bin": { "prebuild-install": "bin.js" } }, "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug=="],
569−
570 "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="],
621 "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="],
571
622
572 "process-warning": ["process-warning@5.0.0", "", {}, "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA=="],
623 "process-warning": ["process-warning@5.0.0", "", {}, "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA=="],
@@ -591,9 +642,7 @@
591
642
592 "quick-format-unescaped": ["quick-format-unescaped@4.0.4", "", {}, "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="],
643 "quick-format-unescaped": ["quick-format-unescaped@4.0.4", "", {}, "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="],
593
644
594− "rc": ["rc@1.2.8", "", { "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "bin": { "rc": "./cli.js" } }, "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw=="],
645+ "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="],
595−
596− "readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
597
646
598 "readline-sync": ["readline-sync@1.4.10", "", {}, "sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw=="],
647 "readline-sync": ["readline-sync@1.4.10", "", {}, "sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw=="],
599
648
@@ -643,11 +692,7 @@
643
692
644 "siginfo": ["siginfo@2.0.0", "", {}, "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g=="],
693 "siginfo": ["siginfo@2.0.0", "", {}, "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g=="],
645
694
646− "signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="],
695+ "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
647−
648− "simple-concat": ["simple-concat@1.0.1", "", {}, "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q=="],
649−
650− "simple-get": ["simple-get@4.0.1", "", { "dependencies": { "decompress-response": "^6.0.0", "once": "^1.3.1", "simple-concat": "^1.0.0" } }, "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA=="],
651
696
652 "slice-ansi": ["slice-ansi@4.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", "is-fullwidth-code-point": "^3.0.0" } }, "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ=="],
697 "slice-ansi": ["slice-ansi@4.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", "is-fullwidth-code-point": "^3.0.0" } }, "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ=="],
653
698
@@ -661,7 +706,7 @@
661
706
662 "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
707 "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
663
708
664− "spago": ["spago@0.93.42", "", { "dependencies": { "@nodelib/fs.walk": "^2.0.0", "better-sqlite3": "^11.0.0", "env-paths": "^3.0.0", "fs-extra": "^11.2.0", "fuse.js": "^7.0.0", "glob": "^10.4.1", "markdown-it": "^14.1.0", "micromatch": "^4.0.7", "open": "^10.1.0", "picomatch": "^4.0.2", "punycode": "^2.3.1", "readline-sync": "^1.4.10", "semver": "^7.6.2", "spdx-expression-parse": "^4.0.0", "ssh2": "^1.15.0", "supports-color": "^9.4.0", "tar": "^7.2.0", "tmp": "^0.2.3", "xhr2": "^0.2.1", "yaml": "^2.4.5" }, "bin": { "spago": "bin/bundle.js" } }, "sha512-R8/CCfR3jtbN3NFZOso+sBTKsaGDu96j8X55JA8CDx12GyB3f64wpwbIXKJ8Y+E4UMjYWhTB2vkP+kqf4R5Y5w=="],
709+ "spago": ["spago@1.0.4", "", { "dependencies": { "@nodelib/fs.walk": "^3.0.1", "env-paths": "^3.0.0", "fs-extra": "^11.3.0", "fuse.js": "^7.1.0", "glob": "^11.0.1", "markdown-it": "^14.1.0", "micromatch": "^4.0.8", "open": "^10.1.0", "picomatch": "^4.0.2", "punycode": "^2.3.1", "readline-sync": "^1.4.10", "semver": "^7.7.1", "spdx-expression-parse": "^4.0.0", "ssh2": "^1.16.0", "supports-color": "^10.0.0", "tar": "^7.4.3", "tmp": "^0.2.3", "xhr2": "^0.2.1", "yaml": "^2.7.0" }, "bin": { "spago": "bin/bundle.js" } }, "sha512-iv1HBJppzGJRWWd/DZ32oselcKrhq/PboBdXy5VMX4GiwRqLCUUp3loZ6Yhm8zymNRKHkN/w52cxX6k521nwng=="],
665
710
666 "spdx-exceptions": ["spdx-exceptions@2.5.0", "", {}, "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w=="],
711 "spdx-exceptions": ["spdx-exceptions@2.5.0", "", {}, "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w=="],
667
712
@@ -683,29 +728,21 @@
683
728
684 "stream-shift": ["stream-shift@1.0.3", "", {}, "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ=="],
729 "stream-shift": ["stream-shift@1.0.3", "", {}, "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ=="],
685
730
686− "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
731+ "string-width": ["string-width@8.2.2", "", { "dependencies": { "get-east-asian-width": "^1.5.0", "strip-ansi": "^7.1.2" } }, "sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg=="],
687
732
688− "string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
733+ "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="],
689
734
690− "string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
735+ "strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="],
691−
692− "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
693−
694− "strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
695
736
696 "strip-final-newline": ["strip-final-newline@2.0.0", "", {}, "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="],
737 "strip-final-newline": ["strip-final-newline@2.0.0", "", {}, "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="],
697
738
698− "strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="],
739+ "supports-color": ["supports-color@10.2.2", "", {}, "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g=="],
699−
700− "supports-color": ["supports-color@9.4.0", "", {}, "sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw=="],
701
740
702 "symbol-tree": ["symbol-tree@3.2.4", "", {}, "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw=="],
741 "symbol-tree": ["symbol-tree@3.2.4", "", {}, "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw=="],
703
742
704 "tar": ["tar@7.5.7", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ=="],
743 "tar": ["tar@7.5.7", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ=="],
705
744
706− "tar-fs": ["tar-fs@2.1.4", "", { "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", "pump": "^3.0.0", "tar-stream": "^2.1.4" } }, "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ=="],
745+ "test-exclude": ["test-exclude@8.0.0", "", { "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^13.0.6", "minimatch": "^10.2.2" } }, "sha512-ZOffsNrXYggvU1mDGHk54I96r26P8SyMjO5slMKSc7+IWmtB/MQKnEC2fP51imB3/pT6YK5cT5E8f+Dd9KdyOQ=="],
707−
708− "tar-stream": ["tar-stream@2.2.0", "", { "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" } }, "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ=="],
709
746
710 "thread-stream": ["thread-stream@4.0.0", "", { "dependencies": { "real-require": "^0.2.0" } }, "sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA=="],
747 "thread-stream": ["thread-stream@4.0.0", "", { "dependencies": { "real-require": "^0.2.0" } }, "sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA=="],
711
748
@@ -735,8 +772,6 @@
735
772
736 "tr46": ["tr46@6.0.0", "", { "dependencies": { "punycode": "^2.3.1" } }, "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw=="],
773 "tr46": ["tr46@6.0.0", "", { "dependencies": { "punycode": "^2.3.1" } }, "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw=="],
737
774
738− "tunnel-agent": ["tunnel-agent@0.6.0", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w=="],
739−
740 "tweetnacl": ["tweetnacl@0.14.5", "", {}, "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA=="],
775 "tweetnacl": ["tweetnacl@0.14.5", "", {}, "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA=="],
741
776
742 "type-fest": ["type-fest@0.21.3", "", {}, "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="],
777 "type-fest": ["type-fest@0.21.3", "", {}, "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="],
@@ -755,6 +790,8 @@
755
790
756 "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
791 "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
757
792
793+ "v8-to-istanbul": ["v8-to-istanbul@9.3.0", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", "convert-source-map": "^2.0.0" } }, "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA=="],
794+
758 "vite": ["vite@5.4.21", "", { "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", "rollup": "^4.20.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["@types/node", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser"], "bin": { "vite": "bin/vite.js" } }, "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw=="],
795 "vite": ["vite@5.4.21", "", { "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", "rollup": "^4.20.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["@types/node", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser"], "bin": { "vite": "bin/vite.js" } }, "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw=="],
759
796
760 "vite-node": ["vite-node@2.1.9", "", { "dependencies": { "cac": "^6.7.14", "debug": "^4.3.7", "es-module-lexer": "^1.5.4", "pathe": "^1.1.2", "vite": "^5.0.0" }, "bin": { "vite-node": "vite-node.mjs" } }, "sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA=="],
797 "vite-node": ["vite-node@2.1.9", "", { "dependencies": { "cac": "^6.7.14", "debug": "^4.3.7", "es-module-lexer": "^1.5.4", "pathe": "^1.1.2", "vite": "^5.0.0" }, "bin": { "vite-node": "vite-node.mjs" } }, "sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA=="],
@@ -773,12 +810,12 @@
773
810
774 "why-is-node-running": ["why-is-node-running@2.3.0", "", { "dependencies": { "siginfo": "^2.0.0", "stackback": "0.0.2" }, "bin": { "why-is-node-running": "cli.js" } }, "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w=="],
811 "why-is-node-running": ["why-is-node-running@2.3.0", "", { "dependencies": { "siginfo": "^2.0.0", "stackback": "0.0.2" }, "bin": { "why-is-node-running": "cli.js" } }, "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w=="],
775
812
776− "wrap-ansi": ["wrap-ansi@6.2.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA=="],
813+ "wrap-ansi": ["wrap-ansi@9.0.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww=="],
777−
778− "wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
779
814
780 "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
815 "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
781
816
817+ "ws": ["ws@8.21.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw=="],
818+
782 "wsl-utils": ["wsl-utils@0.1.0", "", { "dependencies": { "is-wsl": "^3.1.0" } }, "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw=="],
819 "wsl-utils": ["wsl-utils@0.1.0", "", { "dependencies": { "is-wsl": "^3.1.0" } }, "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw=="],
783
820
784 "xhr2": ["xhr2@0.2.1", "", {}, "sha512-sID0rrVCqkVNUn8t6xuv9+6FViXjUVXq8H5rWOH2rz9fDNQEd4g0EA2XlcEdJXRz5BMEn4O1pJFdT+z4YHhoWw=="],
821 "xhr2": ["xhr2@0.2.1", "", {}, "sha512-sID0rrVCqkVNUn8t6xuv9+6FViXjUVXq8H5rWOH2rz9fDNQEd4g0EA2XlcEdJXRz5BMEn4O1pJFdT+z4YHhoWw=="],
@@ -789,42 +826,58 @@
789
826
790 "xtend": ["xtend@4.0.2", "", {}, "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="],
827 "xtend": ["xtend@4.0.2", "", {}, "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="],
791
828
792− "y18n": ["y18n@4.0.3", "", {}, "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="],
829+ "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="],
793
830
794 "yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="],
831 "yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="],
795
832
796 "yaml": ["yaml@2.8.2", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A=="],
833 "yaml": ["yaml@2.8.2", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A=="],
797
834
798− "zen-observable": ["zen-observable@0.8.15", "", {}, "sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ=="],
835+ "yargs": ["yargs@18.1.0", "", { "dependencies": { "cliui": "^9.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "string-width": "^8.2.1", "y18n": "^5.0.5", "yargs-parser": "^22.0.0" } }, "sha512-2rAgRKu54VsHkqI0/tYkmluGXHD4KW7yZoycuqDQ15QOTnc2VVfy0nN/1eMhnQLO00A+dwtK20xuCnc1YGeUyg=="],
799
836
800− "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="],
837+ "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],
801
838
802− "@isaacs/cliui/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="],
839+ "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
803
840
804− "@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="],
841+ "zen-observable": ["zen-observable@0.8.15", "", {}, "sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ=="],
805
842
806 "@npmcli/move-file/mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="],
843 "@npmcli/move-file/mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="],
807
844
808 "@npmcli/move-file/rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" } }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="],
845 "@npmcli/move-file/rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" } }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="],
809
846
810− "bl/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="],
811−
812 "cacache/chownr": ["chownr@1.1.4", "", {}, "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="],
847 "cacache/chownr": ["chownr@1.1.4", "", {}, "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="],
813
848
814 "cacache/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
849 "cacache/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
815
850
816 "cacache/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
851 "cacache/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
817
852
853+ "cacache/y18n": ["y18n@4.0.3", "", {}, "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="],
854+
818 "chalk/supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "^3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="],
855 "chalk/supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "^3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="],
819
856
857+ "cliui/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
858+
859+ "concat-stream/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
860+
820 "cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
861 "cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
821
862
822− "foreground-child/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
863+ "execa/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="],
864+
865+ "flush-write-stream/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
866+
867+ "from2/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
823
868
824 "fs-minipass/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
869 "fs-minipass/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
825
870
871+ "fs-write-stream-atomic/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
872+
873+ "istanbul-lib-report/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
874+
875+ "light-my-request/cookie": ["cookie@1.1.1", "", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="],
876+
826 "light-my-request/process-warning": ["process-warning@4.0.1", "", {}, "sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q=="],
877 "light-my-request/process-warning": ["process-warning@4.0.1", "", {}, "sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q=="],
827
878
879+ "log-update/wrap-ansi": ["wrap-ansi@6.2.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA=="],
880+
828 "make-fetch-happen/cacache": ["cacache@16.1.3", "", { "dependencies": { "@npmcli/fs": "^2.1.0", "@npmcli/move-file": "^2.0.0", "chownr": "^2.0.0", "fs-minipass": "^2.1.0", "glob": "^8.0.1", "infer-owner": "^1.0.4", "lru-cache": "^7.7.1", "minipass": "^3.1.6", "minipass-collect": "^1.0.2", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "mkdirp": "^1.0.4", "p-map": "^4.0.0", "promise-inflight": "^1.0.1", "rimraf": "^3.0.2", "ssri": "^9.0.0", "tar": "^6.1.11", "unique-filename": "^2.0.0" } }, "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ=="],
881 "make-fetch-happen/cacache": ["cacache@16.1.3", "", { "dependencies": { "@npmcli/fs": "^2.1.0", "@npmcli/move-file": "^2.0.0", "chownr": "^2.0.0", "fs-minipass": "^2.1.0", "glob": "^8.0.1", "infer-owner": "^1.0.4", "lru-cache": "^7.7.1", "minipass": "^3.1.6", "minipass-collect": "^1.0.2", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "mkdirp": "^1.0.4", "p-map": "^4.0.0", "promise-inflight": "^1.0.1", "rimraf": "^3.0.2", "ssri": "^9.0.0", "tar": "^6.1.11", "unique-filename": "^2.0.0" } }, "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ=="],
829
882
830 "make-fetch-happen/http-proxy-agent": ["http-proxy-agent@5.0.0", "", { "dependencies": { "@tootallnate/once": "2", "agent-base": "6", "debug": "4" } }, "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w=="],
883 "make-fetch-happen/http-proxy-agent": ["http-proxy-agent@5.0.0", "", { "dependencies": { "@tootallnate/once": "2", "agent-base": "6", "debug": "4" } }, "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w=="],
@@ -853,7 +906,11 @@
853
906
854 "minipass-sized/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
907 "minipass-sized/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
855
908
856− "path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
909+ "mississippi/duplexify": ["duplexify@3.7.1", "", { "dependencies": { "end-of-stream": "^1.0.0", "inherits": "^2.0.1", "readable-stream": "^2.0.0", "stream-shift": "^1.0.0" } }, "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g=="],
910+
911+ "parallel-transform/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
912+
913+ "pumpify/duplexify": ["duplexify@3.7.1", "", { "dependencies": { "end-of-stream": "^1.0.0", "inherits": "^2.0.1", "readable-stream": "^2.0.0", "stream-shift": "^1.0.0" } }, "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g=="],
857
914
858 "pumpify/pump": ["pump@2.0.1", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA=="],
915 "pumpify/pump": ["pump@2.0.1", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA=="],
859
916
@@ -861,40 +918,58 @@
861
918
862 "purescript-installer/tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="],
919 "purescript-installer/tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="],
863
920
864− "readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
921+ "restore-cursor/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="],
865
922
866 "rimraf/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
923 "rimraf/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
867
924
868 "slice-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
925 "slice-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
869
926
927+ "socks/ip-address": ["ip-address@10.1.0", "", {}, "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q=="],
928+
870 "socks-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="],
929 "socks-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="],
871
930
872− "string_decoder/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
931+ "test-exclude/glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", "path-scurry": "^2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="],
873
932
874− "tar-fs/chownr": ["chownr@1.1.4", "", {}, "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="],
933+ "through2/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
875
934
876− "tar-stream/readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="],
935+ "wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],
877
936
878− "wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
937+ "wrap-ansi/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
879
938
880− "wrap-ansi-cjs/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
939+ "yargs/yargs-parser": ["yargs-parser@22.0.0", "", {}, "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw=="],
881
940
882− "@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
941+ "@npmcli/move-file/rimraf/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
883
942
884− "@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
943+ "cacache/glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
885
944
886− "@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],
945+ "cacache/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
887
946
888− "@npmcli/move-file/rimraf/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
947+ "chalk/supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="],
889
948
890− "bl/readable-stream/string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="],
949+ "concat-stream/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
891
950
892− "cacache/glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
951+ "concat-stream/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
893
952
894− "cacache/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
953+ "flush-write-stream/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
954+
955+ "flush-write-stream/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
956+
957+ "from2/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
958+
959+ "from2/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
895
960
896 "fs-minipass/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
961 "fs-minipass/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
897
962
963+ "fs-write-stream-atomic/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
964+
965+ "fs-write-stream-atomic/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
966+
967+ "log-update/wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
968+
969+ "log-update/wrap-ansi/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
970+
971+ "log-update/wrap-ansi/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
972+
898 "make-fetch-happen/cacache/chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="],
973 "make-fetch-happen/cacache/chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="],
899
974
900 "make-fetch-happen/cacache/glob": ["glob@8.1.0", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^5.0.1", "once": "^1.3.0" } }, "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ=="],
975 "make-fetch-happen/cacache/glob": ["glob@8.1.0", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^5.0.1", "once": "^1.3.0" } }, "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ=="],
@@ -925,6 +1000,14 @@
925
1000
926 "minipass-sized/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
1001 "minipass-sized/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
927
1002
1003+ "mississippi/duplexify/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
1004+
1005+ "parallel-transform/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
1006+
1007+ "parallel-transform/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
1008+
1009+ "pumpify/duplexify/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
1010+
928 "purescript-installer/tar/chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="],
1011 "purescript-installer/tar/chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="],
929
1012
930 "purescript-installer/tar/minipass": ["minipass@5.0.0", "", {}, "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="],
1013 "purescript-installer/tar/minipass": ["minipass@5.0.0", "", {}, "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="],
@@ -939,16 +1022,22 @@
939
1022
940 "slice-ansi/ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
1023 "slice-ansi/ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
941
1024
942− "tar-stream/readable-stream/string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="],
1025+ "test-exclude/glob/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="],
943
1026
944− "wrap-ansi-cjs/ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
1027+ "through2/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
945
1028
946− "wrap-ansi/ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
1029+ "through2/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
947
1030
948 "@npmcli/move-file/rimraf/glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
1031 "@npmcli/move-file/rimraf/glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
949
1032
950 "cacache/glob/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
1033 "cacache/glob/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
951
1034
1035+ "log-update/wrap-ansi/ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
1036+
1037+ "log-update/wrap-ansi/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
1038+
1039+ "log-update/wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
1040+
952 "make-fetch-happen/cacache/glob/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="],
1041 "make-fetch-happen/cacache/glob/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="],
953
1042
954 "make-fetch-happen/cacache/rimraf/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
1043 "make-fetch-happen/cacache/rimraf/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
@@ -961,22 +1050,40 @@
961
1050
962 "make-fetch-happen/cacache/unique-filename/unique-slug": ["unique-slug@3.0.0", "", { "dependencies": { "imurmurhash": "^0.1.4" } }, "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w=="],
1051 "make-fetch-happen/cacache/unique-filename/unique-slug": ["unique-slug@3.0.0", "", { "dependencies": { "imurmurhash": "^0.1.4" } }, "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w=="],
963
1052
1053+ "mississippi/duplexify/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
1054+
1055+ "mississippi/duplexify/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
1056+
1057+ "pumpify/duplexify/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
1058+
1059+ "pumpify/duplexify/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
1060+
964 "purescript-installer/tar/minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
1061 "purescript-installer/tar/minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
965
1062
966 "rimraf/glob/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
1063 "rimraf/glob/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
967
1064
968 "slice-ansi/ansi-styles/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
1065 "slice-ansi/ansi-styles/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
969
1066
970− "wrap-ansi-cjs/ansi-styles/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
1067+ "@npmcli/move-file/rimraf/glob/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
971
1068
972− "wrap-ansi/ansi-styles/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
1069+ "cacache/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
973
1070
974− "@npmcli/move-file/rimraf/glob/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
1071+ "log-update/wrap-ansi/ansi-styles/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
1072+
1073+ "make-fetch-happen/cacache/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
975
1074
976 "make-fetch-happen/cacache/rimraf/glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
1075 "make-fetch-happen/cacache/rimraf/glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
977
1076
978 "make-fetch-happen/cacache/tar/minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
1077 "make-fetch-happen/cacache/tar/minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
979
1078
1079+ "rimraf/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
1080+
1081+ "@npmcli/move-file/rimraf/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
1082+
1083+ "make-fetch-happen/cacache/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
1084+
980 "make-fetch-happen/cacache/rimraf/glob/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
1085 "make-fetch-happen/cacache/rimraf/glob/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
1086+
1087+ "make-fetch-happen/cacache/rimraf/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
981 }
1088 }
982}
1089}
compile-fail-tests/ClientBadBodyType.pursnew file+12
@@ -0,0 +1,12 @@
1+-- EXPECT: String
2+module CompileFail.ClientBadBodyType where
3+
4+import Yoga.Fetch.Om (JSON, POST, Route, client)
5+
6+type UserApi =
7+ { createUser :: Route POST "users" { body :: JSON { name :: String } } (ok :: { body :: {} })
8+ }
9+
10+api = client @UserApi ""
11+
12+bad = api.createUser { name: 42 }
compile-fail-tests/ClientBadCurriedBodyType.pursnew file+12
@@ -0,0 +1,12 @@
1+-- EXPECT: String
2+module CompileFail.ClientBadCurriedBodyType where
3+
4+import Yoga.Fetch.Om (JSON, POST, Route, client, type (/), type (:))
5+
6+type UserApi =
7+ { updateUser :: Route POST ("users" / "id" : Int) { body :: JSON { name :: String } } (ok :: { body :: {} })
8+ }
9+
10+api = client @UserApi ""
11+
12+bad = api.updateUser { id: 1 } { name: 42 }
compile-fail-tests/ClientBadHeaderType.pursnew file+13
@@ -0,0 +1,13 @@
1+-- EXPECT: BearerToken
2+module CompileFail.ClientBadHeaderType where
3+
4+import Yoga.Fetch.Om (GET, Route, client)
5+import Yoga.HTTP.API.Route (BearerToken)
6+
7+type UserApi =
8+ { me :: Route GET "me" { headers :: { authorization :: BearerToken } } (ok :: { body :: {} })
9+ }
10+
11+api = client @UserApi ""
12+
13+bad = api.me { authorization: "secret" }
compile-fail-tests/ClientBadOptionalQueryType.pursnew file+13
@@ -0,0 +1,13 @@
1+-- EXPECT: limit
2+module CompileFail.ClientBadOptionalQueryType where
3+
4+import Justifill (justifill)
5+import Yoga.Fetch.Om (GET, Route, client, type (:?))
6+
7+type UserApi =
8+ { listUsers :: Route GET ("users" :? { limit :: Int, offset :: Int }) {} (ok :: { body :: {} })
9+ }
10+
11+api = client @UserApi ""
12+
13+bad = api.listUsers (justifill { limit: "10" })
compile-fail-tests/ClientBadPathType.pursnew file+12
@@ -0,0 +1,12 @@
1+-- EXPECT: Int
2+module CompileFail.ClientBadPathType where
3+
4+import Yoga.Fetch.Om (GET, Route, client, type (/), type (:))
5+
6+type UserApi =
7+ { getUser :: Route GET ("users" / "id" : Int) {} (ok :: { body :: {} })
8+ }
9+
10+api = client @UserApi ""
11+
12+bad = api.getUser { id: "1" }
compile-fail-tests/ClientExtraBodyField.pursnew file+12
@@ -0,0 +1,12 @@
1+-- EXPECT: extra
2+module CompileFail.ClientExtraBodyField where
3+
4+import Yoga.Fetch.Om (JSON, POST, Route, client)
5+
6+type UserApi =
7+ { createUser :: Route POST "users" { body :: JSON { name :: String } } (ok :: { body :: {} })
8+ }
9+
10+api = client @UserApi ""
11+
12+bad = api.createUser { name: "Alice", extra: true }
compile-fail-tests/ClientExtraHeaderField.pursnew file+13
@@ -0,0 +1,13 @@
1+-- EXPECT: extra
2+module CompileFail.ClientExtraHeaderField where
3+
4+import Yoga.Fetch.Om (GET, Route, client)
5+import Yoga.HTTP.API.Route (BearerToken(..))
6+
7+type UserApi =
8+ { me :: Route GET "me" { headers :: { authorization :: BearerToken } } (ok :: { body :: {} })
9+ }
10+
11+api = client @UserApi ""
12+
13+bad = api.me { authorization: BearerToken "secret", extra: true }
compile-fail-tests/ClientExtraOptionalQueryField.pursnew file+13
@@ -0,0 +1,13 @@
1+-- EXPECT: extra
2+module CompileFail.ClientExtraOptionalQueryField where
3+
4+import Justifill (justifill)
5+import Yoga.Fetch.Om (GET, Route, client, type (:?))
6+
7+type UserApi =
8+ { listUsers :: Route GET ("users" :? { limit :: Int, offset :: Int }) {} (ok :: { body :: {} })
9+ }
10+
11+api = client @UserApi ""
12+
13+bad = api.listUsers (justifill { limit: 1, extra: "nope" })
compile-fail-tests/ClientExtraPathField.pursnew file+12
@@ -0,0 +1,12 @@
1+-- EXPECT: extra
2+module CompileFail.ClientExtraPathField where
3+
4+import Yoga.Fetch.Om (GET, Route, client, type (/), type (:))
5+
6+type UserApi =
7+ { getUser :: Route GET ("users" / "id" : Int) {} (ok :: { body :: {} })
8+ }
9+
10+api = client @UserApi ""
11+
12+bad = api.getUser { id: 1, extra: true }
compile-fail-tests/ClientMissingBodyArgument.pursnew file+12
@@ -0,0 +1,12 @@
1+-- EXPECT: Function
2+module CompileFail.ClientMissingBodyArgument where
3+
4+import Yoga.Fetch.Om (JSON, POST, Route, client, type (/), type (:))
5+import Yoga.Om (Om)
6+
7+type UserApi =
8+ { updateUser :: Route POST ("users" / "id" : Int) { body :: JSON { token :: String } } (ok :: { body :: {} })
9+ }
10+
11+api :: forall ctx err. { updateUser :: { id :: Int } -> Om { | ctx } err {} }
12+api = client @UserApi ""
compile-fail-tests/ClientMissingBodyField.pursnew file+12
@@ -0,0 +1,12 @@
1+-- EXPECT: name :: String
2+module CompileFail.ClientMissingBodyField where
3+
4+import Yoga.Fetch.Om (JSON, POST, Route, client)
5+
6+type UserApi =
7+ { createUser :: Route POST "users" { body :: JSON { name :: String, age :: Int } } (ok :: { body :: {} })
8+ }
9+
10+api = client @UserApi ""
11+
12+bad = api.createUser { age: 42 }
compile-fail-tests/ClientMissingHeaderArgument.pursnew file+13
@@ -0,0 +1,13 @@
1+-- EXPECT: Function
2+module CompileFail.ClientMissingHeaderArgument where
3+
4+import Yoga.Fetch.Om (GET, Route, client, type (/), type (:))
5+import Yoga.HTTP.API.Route (BearerToken)
6+import Yoga.Om (Om)
7+
8+type UserApi =
9+ { getUser :: Route GET ("users" / "id" : Int) { headers :: { authorization :: BearerToken } } (ok :: { body :: {} })
10+ }
11+
12+api :: forall ctx err. { getUser :: { id :: Int } -> Om { | ctx } err {} }
13+api = client @UserApi ""
compile-fail-tests/ClientMissingHeaderField.pursnew file+13
@@ -0,0 +1,13 @@
1+-- EXPECT: authorization :: BearerToken
2+module CompileFail.ClientMissingHeaderField where
3+
4+import Yoga.Fetch.Om (GET, Route, client)
5+import Yoga.HTTP.API.Route (BearerToken)
6+
7+type UserApi =
8+ { me :: Route GET "me" { headers :: { authorization :: BearerToken } } (ok :: { body :: {} })
9+ }
10+
11+api = client @UserApi ""
12+
13+bad = api.me {}
compile-fail-tests/ClientMissingPathField.pursnew file+12
@@ -0,0 +1,12 @@
1+-- EXPECT: id :: Int
2+module CompileFail.ClientMissingPathField where
3+
4+import Yoga.Fetch.Om (GET, Route, client, type (/), type (:))
5+
6+type UserApi =
7+ { getUser :: Route GET ("users" / "id" : Int) {} (ok :: { body :: {} })
8+ }
9+
10+api = client @UserApi ""
11+
12+bad = api.getUser {}
compile-fail-tests/ClientMissingRequiredQuery.pursnew file+13
@@ -0,0 +1,13 @@
1+-- EXPECT: id :: Int
2+module CompileFail.ClientMissingRequiredQuery where
3+
4+import Justifill (justifill)
5+import Yoga.Fetch.Om (GET, Required, Route, client, type (:?))
6+
7+type UserApi =
8+ { getUser :: Route GET ("users" :? { id :: Required Int, token :: Required String }) {} (ok :: { body :: {} })
9+ }
10+
11+api = client @UserApi ""
12+
13+bad = api.getUser (justifill { token: "secret" })
compile-fail-tests/ClientMissingThirdArgument.pursnew file+13
@@ -0,0 +1,13 @@
1+-- EXPECT: Function
2+module CompileFail.ClientMissingThirdArgument where
3+
4+import Yoga.Fetch.Om (JSON, POST, Route, client, type (/), type (:))
5+import Yoga.HTTP.API.Route (BearerToken)
6+import Yoga.Om (Om)
7+
8+type UserApi =
9+ { updateUser :: Route POST ("users" / "id" : Int) { headers :: { authorization :: BearerToken }, body :: JSON { token :: String } } (ok :: { body :: {} })
10+ }
11+
12+api :: forall ctx err. { updateUser :: { id :: Int } -> { authorization :: BearerToken } -> Om { | ctx } err {} }
13+api = client @UserApi ""
compile-fail-tests/run.jsnew file+101
@@ -0,0 +1,101 @@
1+import { mkdtempSync, readdirSync, readFileSync, rmSync } from "node:fs";
2+import { tmpdir } from "node:os";
3+import { basename, join } from "node:path";
4+
5+const cwd = new URL("..", import.meta.url).pathname;
6+const casesDir = join(cwd, "compile-fail-tests");
7+const decoder = new TextDecoder();
8+
9+function run(args, options = {}) {
10+ const proc = Bun.spawnSync(args, {
11+ cwd,
12+ stdout: options.stdout ?? "pipe",
13+ stderr: options.stderr ?? "pipe",
14+ });
15+ return {
16+ code: proc.exitCode,
17+ stdout: proc.stdout ? decoder.decode(proc.stdout) : "",
18+ stderr: proc.stderr ? decoder.decode(proc.stderr) : "",
19+ };
20+}
21+
22+function printResult(label, result) {
23+ console.error(`\n${label} failed with exit code ${result.code}`);
24+ if (result.stdout) console.error(result.stdout);
25+ if (result.stderr) console.error(result.stderr);
26+}
27+
28+function expectedSubstring(file) {
29+ const firstLine = readFileSync(file, "utf8").split("\n", 1)[0];
30+ return firstLine.startsWith("-- EXPECT: ") ? firstLine.slice("-- EXPECT: ".length) : null;
31+}
32+
33+const sourcesResult = run(["bunx", "spago", "sources", "--quiet", "--json"]);
34+if (sourcesResult.code !== 0) {
35+ printResult("spago sources", sourcesResult);
36+ process.exit(1);
37+}
38+
39+const excludedSourceGlobs = new Set([
40+ "test/**/*.purs",
41+ "../purescript-yoga-fastify-om/src/**/*.purs",
42+ "../purescript-yoga-fastify-om/local-packages/yoga-fastify/src/**/*.purs",
43+]);
44+
45+const librarySources = JSON.parse(sourcesResult.stdout)
46+ .filter((source) => !excludedSourceGlobs.has(source));
47+
48+const cases = readdirSync(casesDir)
49+ .filter((file) => file.endsWith(".purs"))
50+ .sort()
51+ .map((file) => join("compile-fail-tests", file));
52+
53+const libOutput = mkdtempSync(join(tmpdir(), "yoga-fetch-om-lib-"));
54+
55+try {
56+ const libResult = run(["bunx", "purs", "compile", ...librarySources, "--output", libOutput], { stdout: "ignore" });
57+ if (libResult.code !== 0) {
58+ printResult("library compile", libResult);
59+ process.exit(1);
60+ }
61+
62+ let failed = 0;
63+
64+ for (const testCase of cases) {
65+ const failOutput = mkdtempSync(join(tmpdir(), "yoga-fetch-om-compile-fail-"));
66+ try {
67+ const result = run([
68+ "bunx",
69+ "purs",
70+ "compile",
71+ ...librarySources,
72+ testCase,
73+ "--output",
74+ failOutput,
75+ ]);
76+
77+ const output = `${result.stdout}\n${result.stderr}`;
78+ const expected = expectedSubstring(join(cwd, testCase));
79+ const name = basename(testCase, ".purs");
80+
81+ if (result.code === 0) {
82+ console.error(`FAIL ${name} - compiled successfully (should have failed)`);
83+ failed++;
84+ } else if (expected && !output.includes(expected)) {
85+ printResult(`FAIL ${name}`, result);
86+ console.error(`Expected failure to contain: ${expected}`);
87+ failed++;
88+ } else {
89+ console.log(`PASS ${name}`);
90+ }
91+ } finally {
92+ rmSync(failOutput, { recursive: true, force: true });
93+ }
94+ }
95+
96+ if (failed > 0) {
97+ process.exit(1);
98+ }
99+} finally {
100+ rmSync(libOutput, { recursive: true, force: true });
101+}
package.json+18−4
@@ -1,12 +1,14 @@
1{
1{
2 "name": "purescript-yoga-fetch-om",
2 "name": "purescript-yoga-fetch-om",
3− "version": "0.4.0",
3+ "version": "0.8.1",
4 "description": "Derive type-safe fetch clients from yoga HTTP API definitions",
4 "description": "Derive type-safe fetch clients from yoga HTTP API definitions",
5 "type": "module",
5 "type": "module",
6 "scripts": {
6 "scripts": {
7 "build": "spago build",
7 "build": "spago build",
8 "test": "spago test",
8 "test": "spago test",
9− "clean": "rm -rf output .spago",
9+ "coverage": "spago build && c8 spago test",
10+ "test:compile-fail": "bun compile-fail-tests/run.js",
11+ "clean": "rm -rf output .spago coverage",
10 "watch": "spago build --watch",
12 "watch": "spago build --watch",
11 "repl": "spago repl",
13 "repl": "spago repl",
12 "docs": "spago docs",
14 "docs": "spago docs",
@@ -24,11 +26,23 @@
24 "author": "",
26 "author": "",
25 "license": "MIT",
27 "license": "MIT",
26 "devDependencies": {
28 "devDependencies": {
29+ "@fastify/cookie": "^11.1.2",
30+ "@fastify/cors": "^11.3.0",
31+ "@fastify/formbody": "^9.0.0",
32+ "@fastify/helmet": "^13.1.0",
33+ "@fastify/multipart": "^10.1.0",
34+ "@fastify/rate-limit": "^11.2.0",
35+ "@fastify/websocket": "^11.3.0",
36+ "argon2": "^0.45.1",
37+ "c8": "^12.0.0",
27 "fastify": "^5.7.4",
38 "fastify": "^5.7.4",
39+ "jose": "^6.2.8",
28 "jsdom": "^28.0.0",
40 "jsdom": "^28.0.0",
29 "purescript": "^0.15.15",
41 "purescript": "^0.15.15",
30− "spago": "0.93.42",
42+ "spago": "^1.0.3",
31 "vitest": "^2.1.8"
43 "vitest": "^2.1.8"
32 },
44 },
33− "dependencies": {}
45+ "dependencies": {
46+ "pino": "^10.3.1"
47+ }
34}
48}
spago.lock+143−843
@@ -6,7 +6,7 @@
6 "core": {
6 "core": {
7 "dependencies": [
7 "dependencies": [
8 {
8 {
9− "aff": ">=7.0.0 <9.0.0"
9+ "aff": ">=8.0.0 <9.0.0"
10 },
10 },
11 {
11 {
12 "arraybuffer-types": ">=3.0.2 <4.0.0"
12 "arraybuffer-types": ">=3.0.2 <4.0.0"
@@ -24,7 +24,7 @@
24 "exceptions": ">=6.1.0 <7.0.0"
24 "exceptions": ">=6.1.0 <7.0.0"
25 },
25 },
26 {
26 {
27− "http-methods": ">=6.0.0 <7.0.0"
27+ "http-methods": ">=6.1.0 <7.0.0"
28 },
28 },
29 {
29 {
30 "js-fetch": ">=0.2.1 <0.3.0"
30 "js-fetch": ">=0.2.1 <0.3.0"
@@ -44,6 +44,9 @@
44 {
44 {
45 "strings": ">=6.0.1 <7.0.0"
45 "strings": ">=6.0.1 <7.0.0"
46 },
46 },
47+ {
48+ "tailrec": ">=6.1.0 <7.0.0"
49+ },
47 {
50 {
48 "transformers": ">=6.1.0 <7.0.0"
51 "transformers": ">=6.1.0 <7.0.0"
49 },
52 },
@@ -60,109 +63,39 @@
60 "variant": ">=8.0.0 <9.0.0"
63 "variant": ">=8.0.0 <9.0.0"
61 },
64 },
62 {
65 {
63− "yoga-http-api": ">=0.1.0 <0.3.0"
66+ "yoga-http-api": ">=0.3.4 <0.4.0"
64 },
67 },
65 {
68 {
66− "yoga-json": ">=5.2.0 <6.0.0"
69+ "yoga-json": ">=5.2.1 <6.0.0"
67 },
70 },
68 {
71 {
69− "yoga-om": ">=1.2.2 <2.0.0"
72+ "yoga-om": ">=1.5.2 <2.0.0"
70 },
73 },
71 {
74 {
72− "yoga-om-strom": ">=0.2.0 <0.5.0"
75+ "yoga-om-strom": ">=0.4.3 <0.5.0"
73 }
76 }
74− ],
77+ ]
75− "build_plan": [
78+ },
76− "aff",
79+ "test": {
77− "aff-retry",
80+ "dependencies": [
78− "ansi",
81+ {
79− "arraybuffer-types",
82+ "console": ">=6.0.0 <7.0.0"
80− "arrays",
83+ },
81− "avar",
82− "bifunctors",
83− "catenable-lists",
84− "console",
85− "const",
86− "contravariant",
87− "control",
88− "datetime",
89− "distributive",
90− "effect",
91− "either",
92 "enums",
84 "enums",
93− "exceptions",
94− "exists",
95 "foldable-traversable",
85 "foldable-traversable",
96 "foreign",
86 "foreign",
97 "foreign-object",
87 "foreign-object",
98− "fork",
99− "free",
100− "functions",
101− "functors",
102− "gen",
103− "heterogeneous",
104− "http-methods",
105− "identity",
106 "integers",
88 "integers",
107− "invariant",
108− "js-bigints",
109− "js-date",
110− "js-fetch",
111 "js-promise",
89 "js-promise",
112− "js-promise-aff",
90+ {
113− "lazy",
91+ "js-uri": ">=3.1.0 <4.0.0"
114− "lists",
92+ },
115− "literals",
93+ {
116− "maybe",
94+ "justifill": ">=0.5.0 <0.6.0"
117− "media-types",
95+ },
118− "mmorph",
119− "newtype",
120− "nonempty",
121− "now",
122− "nullable",
123− "numbers",
124− "ordered-collections",
125− "orders",
126− "parallel",
127 "partial",
96 "partial",
128− "pipes",
129− "prelude",
130− "profunctor",
131− "random",
132− "record",
133− "record-studio",
134− "ref-lifted",
135− "refs",
136− "safe-coerce",
137− "spec",
138− "st",
139− "strings",
140− "tailrec",
141− "transformers",
142− "tuples",
143− "type-equality",
144− "typelevel-prelude",
145− "uncurried-transformers",
146− "undefined-is-not-a-problem",
147− "unfoldable",
148− "unsafe-coerce",
149− "untagged-union",
150− "variant",
151− "web-events",
152− "web-file",
153− "web-streams",
154− "yoga-http-api",
155− "yoga-json",
156− "yoga-om",
157− "yoga-om-strom",
158− "yoga-options",
159− "yoga-tree"
160− ]
161− },
162− "test": {
163− "dependencies": [
164 {
97 {
165− "console": ">=6.0.0 <7.0.0"
98+ "quickcheck": ">=8.0.1 <9.0.0"
166 },
99 },
167 {
100 {
168 "refs": ">=6.0.0 <7.0.0"
101 "refs": ">=6.0.0 <7.0.0"
@@ -174,727 +107,17 @@
174 "spec-discovery": ">=8.0.0 <9.0.0"
107 "spec-discovery": ">=8.0.0 <9.0.0"
175 },
108 },
176 {
109 {
177− "yoga-fastify-om": ">=0.1.0 <0.4.0"
110+ "spec-quickcheck": ">=5.0.2 <6.0.0"
178− }
111+ },
179− ],
180− "build_plan": [
181− "aff",
182− "aff-retry",
183− "ansi",
184− "argonaut-codecs",
185− "argonaut-core",
186− "arraybuffer-types",
187− "arrays",
188− "avar",
189− "bifunctors",
190− "catenable-lists",
191− "console",
192− "const",
193− "contravariant",
194− "control",
195− "datetime",
196− "distributive",
197− "effect",
198− "either",
199− "enums",
200− "exceptions",
201− "exists",
202− "exitcodes",
203− "foldable-traversable",
204− "foreign",
205− "foreign-object",
206− "fork",
207− "free",
208− "functions",
209− "functors",
210− "gen",
211− "heterogeneous",
212− "identity",
213− "integers",
214− "invariant",
215− "js-bigints",
216− "js-date",
217− "js-promise",
218− "js-promise-aff",
219− "js-uri",
220− "lazy",
221− "lists",
222− "literals",
223− "maybe",
224− "mmorph",
225− "newtype",
226− "node-buffer",
227− "node-event-emitter",
228− "node-fs",
229− "node-path",
230− "node-process",
231− "node-streams",
232− "nonempty",
233− "now",
234− "nullable",
235− "numbers",
236− "open-memoize",
237− "optparse",
238− "ordered-collections",
239− "orders",
240− "parallel",
241− "partial",
242− "pipes",
243− "posix-types",
244− "prelude",
245− "profunctor",
246− "random",
247− "record",
248− "record-studio",
249− "ref-lifted",
250− "refs",
251− "routing-duplex",
252− "safe-coerce",
253− "spec",
254− "spec-discovery",
255− "spec-node",
256− "st",
257− "strings",
258− "tailrec",
259− "transformers",
260− "tuples",
261− "type-equality",
262− "typelevel-prelude",
263− "uncurried-transformers",
264− "undefined-is-not-a-problem",
265− "unfoldable",
266− "unsafe-coerce",
267− "untagged-union",
268− "variant",
269 "yoga-fastify",
112 "yoga-fastify",
270− "yoga-fastify-om",
113+ {
271− "yoga-http-api",
114+ "yoga-fastify-om": ">=0.4.7 <0.5.0"
272− "yoga-json",
115+ }
273− "yoga-om",
274− "yoga-om-layer",
275− "yoga-om-strom",
276− "yoga-options",
277− "yoga-tree"
278 ]
116 ]
279 }
117 }
280 }
118 }
281 },
119 },
282− "package_set": {
120+ "extra_packages": {}
283− "address": {
284− "registry": "73.0.0"
285− },
286− "compiler": ">=0.15.15 <0.16.0",
287− "content": {
288− "abc-parser": "2.1.0",
289− "ace": "9.1.0",
290− "address-rfc2821": "0.1.1",
291− "aff": "8.0.0",
292− "aff-bus": "6.0.0",
293− "aff-coroutines": "9.0.0",
294− "aff-promise": "4.0.0",
295− "aff-retry": "2.0.0",
296− "affjax": "13.0.0",
297− "affjax-node": "1.0.0",
298− "affjax-web": "1.0.0",
299− "ansi": "7.0.0",
300− "apexcharts": "0.5.0",
301− "applicative-phases": "1.0.0",
302− "argonaut": "9.0.0",
303− "argonaut-aeson-generic": "0.4.1",
304− "argonaut-codecs": "9.1.0",
305− "argonaut-core": "7.0.0",
306− "argonaut-generic": "8.0.0",
307− "argonaut-traversals": "10.0.0",
308− "argparse-basic": "2.0.0",
309− "array-builder": "0.1.2",
310− "array-search": "0.6.0",
311− "arraybuffer": "13.2.0",
312− "arraybuffer-builder": "3.1.0",
313− "arraybuffer-types": "3.0.2",
314− "arrays": "7.3.0",
315− "arrays-extra": "0.6.1",
316− "arrays-zipper": "2.0.1",
317− "ask": "1.0.0",
318− "assert": "6.0.0",
319− "assert-multiple": "0.4.0",
320− "avar": "5.0.1",
321− "axon": "0.0.3",
322− "b64": "0.0.8",
323− "barbies": "1.0.1",
324− "barlow-lens": "0.9.0",
325− "benchlib": "0.0.4",
326− "bifunctors": "6.1.0",
327− "bigints": "7.0.1",
328− "blessed": "1.0.0",
329− "bolson": "0.3.9",
330− "bookhound": "0.1.7",
331− "bower-json": "3.0.0",
332− "call-by-name": "4.0.1",
333− "canvas": "6.0.0",
334− "canvas-action": "9.0.0",
335− "cartesian": "1.0.6",
336− "catenable-lists": "7.0.0",
337− "cbor-stream": "1.3.0",
338− "chameleon": "1.0.0",
339− "chameleon-halogen": "1.0.3",
340− "chameleon-react-basic": "1.1.0",
341− "chameleon-styled": "2.5.0",
342− "chameleon-transformers": "1.0.0",
343− "channel": "1.0.0",
344− "checked-exceptions": "3.1.1",
345− "choku": "1.0.2",
346− "classless": "0.1.1",
347− "classless-arbitrary": "0.1.1",
348− "classless-decode-json": "0.1.1",
349− "classless-encode-json": "0.1.3",
350− "classnames": "2.0.0",
351− "codec": "6.1.0",
352− "codec-argonaut": "10.0.0",
353− "codec-json": "2.0.0",
354− "colors": "7.0.1",
355− "concur-core": "0.5.0",
356− "concur-react": "0.5.0",
357− "concurrent-queues": "3.0.0",
358− "console": "6.1.0",
359− "const": "6.0.0",
360− "contravariant": "6.0.0",
361− "control": "6.0.0",
362− "convertable-options": "1.0.0",
363− "coroutines": "7.0.0",
364− "css": "6.0.0",
365− "css-class-name-extractor": "0.0.4",
366− "css-frameworks": "1.1.0",
367− "csv-stream": "2.3.0",
368− "data-mvc": "0.0.2",
369− "datetime": "6.1.0",
370− "datetime-parsing": "0.2.0",
371− "debounce": "0.1.0",
372− "debug": "6.0.2",
373− "decimals": "7.1.0",
374− "default-values": "1.0.1",
375− "deku": "0.9.23",
376− "deno": "0.0.5",
377− "dissect": "1.0.0",
378− "distributive": "6.0.0",
379− "dodo-printer": "2.2.3",
380− "dom-filereader": "7.0.0",
381− "dom-indexed": "13.0.0",
382− "dom-simple": "0.4.0",
383− "dotenv": "4.0.3",
384− "droplet": "0.6.0",
385− "dts": "1.0.0",
386− "dual-numbers": "1.0.3",
387− "dynamic-buffer": "3.0.1",
388− "echarts-simple": "0.0.1",
389− "effect": "4.0.0",
390− "either": "6.1.0",
391− "elmish": "0.13.0",
392− "elmish-enzyme": "0.1.1",
393− "elmish-hooks": "0.11.0",
394− "elmish-html": "0.10.0",
395− "elmish-testing-library": "0.3.2",
396− "elmish-time-machine": "0.4.2",
397− "email-validate": "7.0.0",
398− "encoding": "0.0.9",
399− "enums": "6.0.1",
400− "env-names": "0.4.0",
401− "environment": "2.0.0",
402− "error": "2.0.0",
403− "eta-conversion": "0.3.2",
404− "exceptions": "6.1.0",
405− "exists": "6.0.0",
406− "exitcodes": "4.0.0",
407− "expect-inferred": "3.0.0",
408− "express": "0.9.1",
409− "ezfetch": "1.1.1",
410− "fahrtwind": "2.0.0",
411− "fakerjs": "0.0.1",
412− "fallback": "0.1.0",
413− "fast-vect": "1.2.0",
414− "fetch": "4.1.0",
415− "fetch-argonaut": "1.0.1",
416− "fetch-core": "5.1.0",
417− "fetch-yoga-json": "1.1.0",
418− "ffi-simple": "0.5.1",
419− "fft": "0.3.0",
420− "fft-js": "0.1.0",
421− "filterable": "5.0.0",
422− "fix-functor": "0.1.0",
423− "fixed-points": "7.0.0",
424− "fixed-precision": "5.0.0",
425− "flame": "1.6.0",
426− "float32": "2.0.0",
427− "fmt": "0.2.1",
428− "foldable-traversable": "6.0.0",
429− "foldable-traversable-extra": "0.0.6",
430− "foreign": "7.0.0",
431− "foreign-object": "4.1.0",
432− "foreign-readwrite": "3.4.0",
433− "forgetmenot": "0.1.0",
434− "fork": "6.0.0",
435− "form-urlencoded": "7.0.0",
436− "formatters": "7.0.0",
437− "framer-motion": "2.0.1",
438− "free": "7.1.0",
439− "freeap": "7.0.0",
440− "freer-free": "0.0.1",
441− "freet": "7.0.0",
442− "functions": "6.0.0",
443− "functor1": "3.0.0",
444− "functors": "5.0.0",
445− "fuzzy": "0.4.0",
446− "gen": "4.0.0",
447− "generate-values": "1.0.1",
448− "generic-router": "0.0.1",
449− "geojson": "0.0.5",
450− "geometria": "2.2.0",
451− "gesso": "1.0.1",
452− "gojs": "0.1.1",
453− "golem-fetch": "0.1.0",
454− "grain": "3.0.0",
455− "grain-router": "3.0.0",
456− "grain-virtualized": "3.0.0",
457− "graphql-client": "10.1.1",
458− "graphs": "8.1.0",
459− "group": "4.1.1",
460− "halogen": "7.0.0",
461− "halogen-bootstrap5": "5.3.2",
462− "halogen-canvas": "1.0.0",
463− "halogen-css": "10.0.0",
464− "halogen-declarative-canvas": "0.0.8",
465− "halogen-echarts-simple": "0.0.4",
466− "halogen-formless": "4.0.3",
467− "halogen-helix": "1.1.0",
468− "halogen-hooks": "0.6.3",
469− "halogen-hooks-extra": "0.9.0",
470− "halogen-infinite-scroll": "1.1.0",
471− "halogen-store": "0.5.4",
472− "halogen-storybook": "2.0.0",
473− "halogen-subscriptions": "2.0.0",
474− "halogen-svg-elems": "8.0.0",
475− "halogen-typewriter": "1.0.4",
476− "halogen-use-trigger-hooks": "1.0.0",
477− "halogen-vdom": "8.0.0",
478− "halogen-vdom-string-renderer": "0.5.0",
479− "halogen-xterm": "2.0.0",
480− "heckin": "2.0.1",
481− "heterogeneous": "0.7.0",
482− "homogeneous": "0.4.0",
483− "http-methods": "6.0.0",
484− "httpurple": "4.0.0",
485− "huffman": "0.4.0",
486− "humdrum": "0.0.1",
487− "hylograph-canvas": "0.1.0",
488− "hylograph-d3-kernel": "0.1.0",
489− "hylograph-graph": "0.1.0",
490− "hylograph-layout": "0.1.0",
491− "hylograph-music": "0.1.0",
492− "hylograph-optics": "0.1.0",
493− "hylograph-selection": "0.1.1",
494− "hylograph-simulation": "0.1.0",
495− "hylograph-simulation-core": "0.1.0",
496− "hylograph-simulation-halogen": "0.1.0",
497− "hylograph-transitions": "0.1.0",
498− "hylograph-wasm-kernel": "0.1.0",
499− "hyrule": "2.3.8",
500− "identity": "6.0.0",
501− "identy": "4.0.1",
502− "indexed-db": "1.0.0",
503− "indexed-monad": "3.0.0",
504− "ink": "0.0.1",
505− "int64": "3.0.0",
506− "integers": "6.0.0",
507− "interpolate": "5.0.2",
508− "intersection-observer": "1.0.1",
509− "invariant": "6.0.0",
510− "jarilo": "1.0.1",
511− "jelly": "0.10.0",
512− "jelly-router": "0.3.0",
513− "jelly-signal": "0.4.0",
514− "jest": "1.0.0",
515− "js-abort-controller": "1.0.0",
516− "js-bigints": "2.2.1",
517− "js-date": "8.0.0",
518− "js-fetch": "0.2.1",
519− "js-fileio": "3.0.0",
520− "js-intl": "1.1.4",
521− "js-iterators": "0.1.1",
522− "js-maps": "0.1.2",
523− "js-promise": "1.0.0",
524− "js-promise-aff": "1.0.0",
525− "js-timers": "6.1.0",
526− "js-uri": "3.1.0",
527− "jsdom": "1.0.0",
528− "json": "1.1.0",
529− "json-codecs": "5.0.0",
530− "justifill": "0.5.0",
531− "jwt": "0.0.9",
532− "labeled-data": "0.2.0",
533− "language-cst-parser": "0.14.1",
534− "lazy": "6.0.0",
535− "lazy-joe": "1.0.0",
536− "lcg": "4.0.0",
537− "leibniz": "5.0.0",
538− "leveldb": "1.0.1",
539− "liminal": "1.0.1",
540− "linalg": "6.0.0",
541− "lists": "7.0.0",
542− "literals": "1.0.2",
543− "logging": "3.0.0",
544− "logging-journald": "0.4.0",
545− "lumi-components": "18.0.0",
546− "machines": "7.0.0",
547− "maps-eager": "0.5.0",
548− "marionette": "1.0.0",
549− "marionette-react-basic-hooks": "0.1.1",
550− "marked": "0.1.0",
551− "matrices": "5.0.1",
552− "matryoshka": "1.0.0",
553− "maybe": "6.0.0",
554− "media-types": "6.0.0",
555− "meowclient": "1.0.0",
556− "midi": "4.0.0",
557− "milkis": "9.0.0",
558− "mimetype": "0.0.1",
559− "minibench": "4.0.1",
560− "mmorph": "7.0.0",
561− "monad-control": "5.0.0",
562− "monad-logger": "1.3.1",
563− "monad-loops": "0.5.0",
564− "monad-unlift": "1.0.1",
565− "monoid-extras": "0.0.1",
566− "monoidal": "0.16.0",
567− "morello": "0.4.0",
568− "mote": "3.0.0",
569− "motsunabe": "2.0.0",
570− "mvc": "0.0.1",
571− "mysql": "6.0.1",
572− "n3": "0.1.0",
573− "nano-id": "1.1.0",
574− "nanoid": "0.1.0",
575− "naturals": "3.0.0",
576− "nested-functor": "0.2.1",
577− "newtype": "5.0.0",
578− "nextjs": "0.1.1",
579− "nextui": "0.2.0",
580− "node-buffer": "9.0.0",
581− "node-child-process": "11.1.0",
582− "node-event-emitter": "3.0.0",
583− "node-execa": "5.0.0",
584− "node-fs": "9.2.0",
585− "node-glob-basic": "2.0.0",
586− "node-http": "9.1.0",
587− "node-http2": "1.1.1",
588− "node-human-signals": "1.0.0",
589− "node-net": "5.1.0",
590− "node-os": "5.1.0",
591− "node-path": "5.0.1",
592− "node-process": "11.2.0",
593− "node-readline": "8.1.1",
594− "node-sqlite3": "8.0.0",
595− "node-stream-pipes": "2.1.6",
596− "node-streams": "9.0.1",
597− "node-tls": "0.3.1",
598− "node-url": "7.0.1",
599− "node-workerbees": "0.3.1",
600− "node-zlib": "0.4.0",
601− "nonempty": "7.0.0",
602− "now": "6.0.0",
603− "npm-package-json": "2.0.0",
604− "nullable": "6.0.0",
605− "numberfield": "0.2.2",
606− "numbers": "9.0.1",
607− "oak": "3.1.1",
608− "oak-debug": "1.2.2",
609− "object-maps": "0.3.0",
610− "ocarina": "1.5.4",
611− "oooooooooorrrrrrrmm-lib": "0.0.1",
612− "open-colors-scales-and-schemes": "1.0.0",
613− "open-drawing": "6.0.4",
614− "open-folds": "6.4.0",
615− "open-foreign-generic": "11.0.3",
616− "open-memoize": "6.2.0",
617− "open-mkdirp-aff": "1.2.0",
618− "open-pairing": "6.2.0",
619− "open-smolder": "12.0.2",
620− "options": "7.0.0",
621− "optparse": "5.0.1",
622− "ordered-collections": "3.2.0",
623− "ordered-set": "0.4.0",
624− "orders": "6.0.0",
625− "org-doc": "0.1.0",
626− "owoify": "1.2.0",
627− "pairs": "9.0.1",
628− "parallel": "7.0.0",
629− "parsing": "11.0.0",
630− "parsing-dataview": "3.2.4",
631− "partial": "4.0.0",
632− "pathy": "9.0.0",
633− "pha": "0.13.0",
634− "phaser": "0.7.0",
635− "phylio": "1.1.2",
636− "pipes": "8.0.0",
637− "pirates-charm": "0.0.1",
638− "play": "1.0.0",
639− "pmock": "0.9.0",
640− "point-free": "1.0.0",
641− "pointed-list": "0.5.1",
642− "polymorphic-vectors": "4.0.0",
643− "posix-types": "6.0.0",
644− "postgresql": "2.0.21",
645− "precise": "6.0.0",
646− "precise-datetime": "7.0.0",
647− "prelude": "6.0.2",
648− "prettier-printer": "3.0.0",
649− "printf": "0.1.0",
650− "priority-queue": "0.1.2",
651− "profunctor": "6.0.1",
652− "profunctor-lenses": "8.0.0",
653− "protobuf": "4.4.0",
654− "psa-utils": "8.0.0",
655− "psci-support": "6.0.0",
656− "punycode": "1.0.0",
657− "pursfmt": "0.17.0",
658− "qualified-do": "2.2.0",
659− "quantities": "12.2.0",
660− "quickcheck": "8.0.1",
661− "quickcheck-combinators": "0.1.3",
662− "quickcheck-laws": "7.0.0",
663− "quickcheck-utf8": "0.0.0",
664− "random": "6.0.0",
665− "rationals": "6.0.0",
666− "rdf": "0.1.0",
667− "react": "11.0.0",
668− "react-aria": "0.2.0",
669− "react-basic": "17.0.0",
670− "react-basic-classic": "3.0.0",
671− "react-basic-dnd": "10.1.0",
672− "react-basic-dom": "7.0.0",
673− "react-basic-dom-beta": "0.1.1",
674− "react-basic-emotion": "7.1.0",
675− "react-basic-hooks": "9.0.0",
676− "react-basic-storybook": "2.0.0",
677− "react-dom": "8.0.0",
678− "react-halo": "3.0.0",
679− "react-icons": "1.1.5",
680− "react-markdown": "0.1.0",
681− "react-testing-library": "4.0.1",
682− "react-virtuoso": "1.0.0",
683− "reactix": "0.6.1",
684− "read": "1.0.1",
685− "recharts": "1.1.0",
686− "record": "4.0.0",
687− "record-extra": "5.0.1",
688− "record-extra-srghma": "0.2.8",
689− "record-ptional-fields": "0.1.2",
690− "record-studio": "1.0.4",
691− "refs": "6.0.0",
692− "remotedata": "5.0.1",
693− "repr": "0.5.0",
694− "resize-arrays": "0.0.1",
695− "resize-observer": "1.0.0",
696− "resource": "2.0.1",
697− "resourcet": "1.0.0",
698− "result": "1.0.3",
699− "return": "0.2.0",
700− "ring-modules": "5.0.1",
701− "rito": "0.3.4",
702− "roman": "0.4.0",
703− "rough-notation": "1.0.2",
704− "routing": "11.0.0",
705− "routing-duplex": "0.7.0",
706− "run": "5.0.0",
707− "safe-coerce": "2.0.0",
708− "safely": "4.0.1",
709− "school-of-music": "1.3.0",
710− "selection-foldable": "0.2.0",
711− "selective-functors": "1.0.1",
712− "semirings": "7.0.0",
713− "shuffle": "2.0.0",
714− "signal": "13.0.0",
715− "simple-emitter": "3.0.1",
716− "simple-i18n": "2.0.1",
717− "simple-json": "9.0.0",
718− "simple-json-generics": "0.2.1",
719− "simple-ulid": "3.0.0",
720− "sized-matrices": "1.0.0",
721− "sized-vectors": "5.0.2",
722− "slug": "3.2.0",
723− "small-ffi": "4.0.1",
724− "soundfonts": "4.1.0",
725− "sparse-matrices": "2.0.1",
726− "sparse-polynomials": "3.0.1",
727− "spec": "8.1.1",
728− "spec-discovery": "8.4.0",
729− "spec-mocha": "5.1.1",
730− "spec-node": "0.0.3",
731− "spec-quickcheck": "5.0.2",
732− "spec-reporter-xunit": "0.7.1",
733− "splitmix": "2.1.0",
734− "ssrs": "1.0.0",
735− "st": "6.2.0",
736− "statistics": "0.3.2",
737− "strictlypositiveint": "1.0.1",
738− "string-parsers": "8.0.0",
739− "strings": "6.0.1",
740− "strings-extra": "4.0.0",
741− "stringutils": "0.0.12",
742− "structured-logging": "1.0.0",
743− "substitute": "0.2.3",
744− "supply": "0.2.0",
745− "svg-parser": "3.0.0",
746− "systemd-journald": "0.3.0",
747− "tagged": "4.0.2",
748− "tailrec": "6.1.0",
749− "tanstack-query": "2.0.0",
750− "tecton": "0.2.1",
751− "tecton-halogen": "0.2.0",
752− "test-unit": "17.0.0",
753− "text-formatting": "0.1.0",
754− "thermite": "6.3.1",
755− "thermite-dom": "0.3.1",
756− "these": "6.0.0",
757− "threading": "0.0.3",
758− "tidy": "0.11.1",
759− "tidy-codegen": "4.0.1",
760− "tldr": "0.0.0",
761− "toestand": "0.9.0",
762− "transformation-matrix": "1.0.1",
763− "transformers": "6.1.0",
764− "transit": "1.0.0",
765− "tree-rose": "4.0.2",
766− "trivial-unfold": "0.5.0",
767− "ts-bridge": "4.0.0",
768− "tuples": "7.0.0",
769− "two-or-more": "1.0.0",
770− "type-equality": "4.0.1",
771− "typedenv": "2.0.1",
772− "typelevel": "6.0.0",
773− "typelevel-lists": "2.1.0",
774− "typelevel-peano": "1.0.1",
775− "typelevel-prelude": "7.0.0",
776− "typelevel-regex": "0.0.3",
777− "typelevel-rows": "0.1.0",
778− "typisch": "0.4.0",
779− "uint": "7.0.0",
780− "ulid": "3.0.1",
781− "uncurried-transformers": "1.1.0",
782− "undefined": "2.0.0",
783− "undefined-is-not-a-problem": "1.1.0",
784− "unfoldable": "6.0.0",
785− "unicode": "6.0.0",
786− "unique": "0.6.1",
787− "unlift": "1.0.1",
788− "unordered-collections": "3.1.0",
789− "unsafe-coerce": "6.0.0",
790− "unsafe-reference": "5.0.0",
791− "untagged-to-tagged": "0.1.4",
792− "untagged-union": "1.0.0",
793− "uri": "9.0.0",
794− "url-immutable": "1.0.0",
795− "url-regex-safe": "0.1.1",
796− "uuid": "9.0.0",
797− "uuidv4": "1.0.0",
798− "validation": "6.0.0",
799− "variant": "8.0.0",
800− "variant-encodings": "2.0.0",
801− "variant-gen": "1.0.0",
802− "vectorfield": "1.0.1",
803− "vectors": "2.1.0",
804− "versions": "7.0.0",
805− "visx": "0.0.2",
806− "vitest": "2.0.0",
807− "web-clipboard": "6.0.0",
808− "web-cssom": "2.0.0",
809− "web-cssom-view": "0.1.0",
810− "web-dom": "6.0.0",
811− "web-dom-parser": "8.0.0",
812− "web-dom-xpath": "3.0.0",
813− "web-encoding": "3.0.0",
814− "web-events": "4.0.0",
815− "web-fetch": "4.0.1",
816− "web-file": "4.0.0",
817− "web-geometry": "0.1.0",
818− "web-html": "4.1.1",
819− "web-pointerevents": "2.0.0",
820− "web-proletarian": "1.0.0",
821− "web-promise": "3.2.0",
822− "web-resize-observer": "2.1.0",
823− "web-router": "1.0.0",
824− "web-socket": "4.0.0",
825− "web-storage": "5.0.0",
826− "web-streams": "4.0.0",
827− "web-touchevents": "4.0.0",
828− "web-uievents": "5.0.0",
829− "web-url": "2.0.0",
830− "web-workers": "1.1.0",
831− "web-xhr": "5.0.1",
832− "webb-aff-list": "0.0.2",
833− "webb-array": "0.0.2",
834− "webb-channel": "0.0.3",
835− "webb-commandline": "0.0.3",
836− "webb-directory": "0.0.7",
837− "webb-file": "0.0.1",
838− "webb-map": "0.0.1",
839− "webb-monad": "0.0.2",
840− "webb-mutex": "0.0.7",
841− "webb-parsing": "0.0.5",
842− "webb-random": "0.0.1",
843− "webb-refer": "0.0.3",
844− "webb-set": "0.0.1",
845− "webb-slot": "0.0.1",
846− "webb-stateful": "0.0.3",
847− "webb-string": "0.0.1",
848− "webb-test": "0.0.1",
849− "webb-thread": "0.0.2",
850− "webb-writer": "0.0.3",
851− "webextension-polyfill": "0.1.0",
852− "webgpu": "0.0.1",
853− "which": "2.0.0",
854− "whine-core": "0.0.33",
855− "xterm": "1.0.0",
856− "yaml-next": "3.1.1",
857− "yoga-fetch": "1.0.1",
858− "yoga-json": "5.1.0",
859− "yoga-om": "0.1.0",
860− "yoga-postgres": "6.0.0",
861− "yoga-react-dom": "1.0.1",
862− "yoga-redis": "0.1.0",
863− "yoga-sql-types": "0.1.0",
864− "yoga-subtlecrypto": "0.1.0",
865− "yoga-test-docker": "0.1.0",
866− "yoga-tree": "1.0.0",
867− "yoga-tree-svg": "0.1.0",
868− "yoga-tree-utils": "1.0.0",
869− "z3": "0.0.2",
870− "zipperarray": "2.0.0"
871− }
872− },
873− "extra_packages": {
874− "ref-lifted": {
875− "path": "../purescript-ref-lifted"
876− },
877− "yoga-fastify": {
878− "path": "../purescript-yoga-fastify"
879− },
880− "yoga-fastify-om": {
881− "path": "../purescript-yoga-fastify-om"
882− },
883− "yoga-http-api": {
884− "path": "../purescript-yoga-http-api"
885− },
886− "yoga-json": "5.2.0",
887− "yoga-om": {
888− "path": "../purescript-yoga-om"
889− },
890− "yoga-om-layer": {
891− "path": "../purescript-yoga-om-layer"
892− },
893− "yoga-om-strom": {
894− "path": "../purescript-yoga-om-strom"
895− },
896− "yoga-options": "0.1.0"
897− }
898 },
121 },
899 "packages": {
122 "packages": {
900 "aff": {
123 "aff": {
@@ -1342,8 +565,8 @@
1342 },
565 },
1343 "http-methods": {
566 "http-methods": {
1344 "type": "registry",
567 "type": "registry",
1345− "version": "6.0.0",
568+ "version": "6.1.0",
1346− "integrity": "sha256-S0UjrJSgwJxEsFHM/pX77dM8V4HfvvDqdHPckQrtxMs=",
569+ "integrity": "sha256-WbjEmCv6rysY/aKwlrcspyzShi5bIQy+AFpDzPMnSP4=",
1347 "dependencies": [
570 "dependencies": [
1348 "either",
571 "either",
1349 "prelude",
572 "prelude",
@@ -1471,6 +694,17 @@
1471 "prelude"
694 "prelude"
1472 ]
695 ]
1473 },
696 },
697+ "justifill": {
698+ "type": "registry",
699+ "version": "0.5.0",
700+ "integrity": "sha256-IwoDO72+IROcUvFIwnronb/ny8SepssgTUG3Qp2TEKg=",
701+ "dependencies": [
702+ "maybe",
703+ "prelude",
704+ "record",
705+ "typelevel-prelude"
706+ ]
707+ },
1474 "lazy": {
708 "lazy": {
1475 "type": "registry",
709 "type": "registry",
1476 "version": "6.0.0",
710 "version": "6.0.0",
@@ -1482,6 +716,20 @@
1482 "prelude"
716 "prelude"
1483 ]
717 ]
1484 },
718 },
719+ "lcg": {
720+ "type": "registry",
721+ "version": "4.0.0",
722+ "integrity": "sha256-bUYyfXYmjTn7zSpj2hTiePywzsuD80fCjkonsrpdGOw=",
723+ "dependencies": [
724+ "effect",
725+ "integers",
726+ "maybe",
727+ "numbers",
728+ "partial",
729+ "prelude",
730+ "random"
731+ ]
732+ },
1485 "lists": {
733 "lists": {
1486 "type": "registry",
734 "type": "registry",
1487 "version": "7.0.0",
735 "version": "7.0.0",
@@ -1861,6 +1109,39 @@
1861 "tuples"
1109 "tuples"
1862 ]
1110 ]
1863 },
1111 },
1112+ "quickcheck": {
1113+ "type": "registry",
1114+ "version": "8.0.1",
1115+ "integrity": "sha256-SfW+maesCt0jnnFhfrgJZGPcWLj8oFcGbcDIVklmdzc=",
1116+ "dependencies": [
1117+ "arrays",
1118+ "console",
1119+ "control",
1120+ "effect",
1121+ "either",
1122+ "enums",
1123+ "exceptions",
1124+ "foldable-traversable",
1125+ "gen",
1126+ "identity",
1127+ "integers",
1128+ "lazy",
1129+ "lcg",
1130+ "lists",
1131+ "maybe",
1132+ "newtype",
1133+ "nonempty",
1134+ "numbers",
1135+ "partial",
1136+ "prelude",
1137+ "record",
1138+ "st",
1139+ "strings",
1140+ "tailrec",
1141+ "transformers",
1142+ "tuples"
1143+ ]
1144+ },
1864 "random": {
1145 "random": {
1865 "type": "registry",
1146 "type": "registry",
1866 "version": "6.0.0",
1147 "version": "6.0.0",
@@ -1894,15 +1175,6 @@
1894 "unsafe-coerce"
1175 "unsafe-coerce"
1895 ]
1176 ]
1896 },
1177 },
1897− "ref-lifted": {
1898− "type": "local",
1899− "path": "../purescript-ref-lifted",
1900− "dependencies": [
1901− "effect",
1902− "prelude",
1903− "refs"
1904− ]
1905− },
1906 "refs": {
1178 "refs": {
1907 "type": "registry",
1179 "type": "registry",
1908 "version": "6.0.0",
1180 "version": "6.0.0",
@@ -1943,8 +1215,8 @@
1943 },
1215 },
1944 "spec": {
1216 "spec": {
1945 "type": "registry",
1217 "type": "registry",
1946− "version": "8.1.1",
1218+ "version": "8.1.2",
1947− "integrity": "sha256-b6qjDb7lUJGLV+WEoywLu6BCXC4zGpfbN43mTL+vBeI=",
1219+ "integrity": "sha256-klPPJ6lBQI1CGOAdLJ+ZoGRt8XZippkTKjn53BrSkL0=",
1948 "dependencies": [
1220 "dependencies": [
1949 "aff",
1221 "aff",
1950 "ansi",
1222 "ansi",
@@ -1977,8 +1249,8 @@
1977 },
1249 },
1978 "spec-discovery": {
1250 "spec-discovery": {
1979 "type": "registry",
1251 "type": "registry",
1980− "version": "8.4.0",
1252+ "version": "8.4.1",
1981− "integrity": "sha256-aFp8bllT/wrxQu8hMlDchQQY08dQAz+Xdq2hZi5z3yY=",
1253+ "integrity": "sha256-guvY+NtSOBQmM+HqNJ7woX6taN8hS1wEz7JDmdKF11E=",
1982 "dependencies": [
1254 "dependencies": [
1983 "aff",
1255 "aff",
1984 "effect",
1256 "effect",
@@ -1990,8 +1262,8 @@
1990 },
1262 },
1991 "spec-node": {
1263 "spec-node": {
1992 "type": "registry",
1264 "type": "registry",
1993− "version": "0.0.3",
1265+ "version": "0.0.2",
1994− "integrity": "sha256-8/9+g0obbamV0YtqzmttbWs8HaWF7CEeW+eDtqzuAAo=",
1266+ "integrity": "sha256-HDW02z3Mj+daux0j9487ApDBX32/gX0od6YR4zvDRZI=",
1995 "dependencies": [
1267 "dependencies": [
1996 "aff",
1268 "aff",
1997 "argonaut-codecs",
1269 "argonaut-codecs",
@@ -2020,6 +1292,22 @@
2020 "tuples"
1292 "tuples"
2021 ]
1293 ]
2022 },
1294 },
1295+ "spec-quickcheck": {
1296+ "type": "registry",
1297+ "version": "5.0.2",
1298+ "integrity": "sha256-pmnLu9e9Yk+Yx4hi71XwbyuPS27ya4hjTOKk2KFK/Ns=",
1299+ "dependencies": [
1300+ "aff",
1301+ "arrays",
1302+ "effect",
1303+ "foldable-traversable",
1304+ "lists",
1305+ "maybe",
1306+ "prelude",
1307+ "quickcheck",
1308+ "tuples"
1309+ ]
1310+ },
2023 "st": {
1311 "st": {
2024 "type": "registry",
1312 "type": "registry",
2025 "version": "6.2.0",
1313 "version": "6.2.0",
@@ -2255,8 +1543,9 @@
2255 ]
1543 ]
2256 },
1544 },
2257 "yoga-fastify": {
1545 "yoga-fastify": {
2258− "type": "local",
1546+ "type": "registry",
2259− "path": "../purescript-yoga-fastify",
1547+ "version": "0.5.4",
1548+ "integrity": "sha256-YenjePRdiApMPpcvkXlzre7c4fIuvk5T19Z2uEAWhR4=",
2260 "dependencies": [
1549 "dependencies": [
2261 "aff",
1550 "aff",
2262 "arrays",
1551 "arrays",
@@ -2281,8 +1570,9 @@
2281 ]
1570 ]
2282 },
1571 },
2283 "yoga-fastify-om": {
1572 "yoga-fastify-om": {
2284− "type": "local",
1573+ "type": "registry",
2285− "path": "../purescript-yoga-fastify-om",
1574+ "version": "0.4.7",
1575+ "integrity": "sha256-KGQ7lHI7pcSiEQoEq6j6K+3XilcPy8wQ/M9C1y+uaEk=",
2286 "dependencies": [
1576 "dependencies": [
2287 "aff",
1577 "aff",
2288 "console",
1578 "console",
@@ -2294,12 +1584,14 @@
2294 "integers",
1584 "integers",
2295 "maybe",
1585 "maybe",
2296 "node-buffer",
1586 "node-buffer",
1587+ "numbers",
2297 "prelude",
1588 "prelude",
2298 "record",
1589 "record",
2299− "ref-lifted",
2300 "refs",
1590 "refs",
2301 "routing-duplex",
1591 "routing-duplex",
1592+ "strings",
2302 "transformers",
1593 "transformers",
1594+ "typelevel-prelude",
2303 "unsafe-coerce",
1595 "unsafe-coerce",
2304 "variant",
1596 "variant",
2305 "yoga-fastify",
1597 "yoga-fastify",
@@ -2311,19 +1603,26 @@
2311 ]
1603 ]
2312 },
1604 },
2313 "yoga-http-api": {
1605 "yoga-http-api": {
2314− "type": "local",
1606+ "type": "registry",
2315− "path": "../purescript-yoga-http-api",
1607+ "version": "0.3.4",
1608+ "integrity": "sha256-DSIJ8YWr5vB5IMpyaBALM+fx57lz3AAAR0MGtfHeWxo=",
2316 "dependencies": [
1609 "dependencies": [
2317 "aff",
1610 "aff",
1611+ "arraybuffer-types",
2318 "arrays",
1612 "arrays",
1613+ "effect",
2319 "either",
1614 "either",
2320 "foldable-traversable",
1615 "foldable-traversable",
2321 "foreign",
1616 "foreign",
2322 "foreign-object",
1617 "foreign-object",
2323 "identity",
1618 "identity",
2324 "integers",
1619 "integers",
1620+ "js-promise",
1621+ "js-promise-aff",
2325 "maybe",
1622 "maybe",
2326 "newtype",
1623 "newtype",
1624+ "nullable",
1625+ "numbers",
2327 "prelude",
1626 "prelude",
2328 "record",
1627 "record",
2329 "strings",
1628 "strings",
@@ -2337,8 +1636,8 @@
2337 },
1636 },
2338 "yoga-json": {
1637 "yoga-json": {
2339 "type": "registry",
1638 "type": "registry",
2340− "version": "5.2.0",
1639+ "version": "5.2.1",
2341− "integrity": "sha256-M+kkz6E1Gf+C4bKnhqoBFIoVcc74loi3rLULePbB204=",
1640+ "integrity": "sha256-12I7qIf27oKV/D/YRcHtGpN8n7GQ0Bm3uzvI4ZjOQrs=",
2342 "dependencies": [
1641 "dependencies": [
2343 "arrays",
1642 "arrays",
2344 "bifunctors",
1643 "bifunctors",
@@ -2375,8 +1674,9 @@
2375 ]
1674 ]
2376 },
1675 },
2377 "yoga-om": {
1676 "yoga-om": {
2378− "type": "local",
1677+ "type": "registry",
2379− "path": "../purescript-yoga-om",
1678+ "version": "1.5.2",
1679+ "integrity": "sha256-2ys14BF6NPgzFDFUIFk0EDxmqkA8+yghIA9TXHlOmE0=",
2380 "dependencies": [
1680 "dependencies": [
2381 "aff",
1681 "aff",
2382 "aff-retry",
1682 "aff-retry",
@@ -2388,13 +1688,13 @@
2388 "either",
1688 "either",
2389 "exceptions",
1689 "exceptions",
2390 "functions",
1690 "functions",
1691+ "heterogeneous",
2391 "maybe",
1692 "maybe",
2392 "newtype",
1693 "newtype",
2393 "parallel",
1694 "parallel",
2394 "prelude",
1695 "prelude",
2395 "record",
1696 "record",
2396 "record-studio",
1697 "record-studio",
2397− "ref-lifted",
2398 "refs",
1698 "refs",
2399 "tailrec",
1699 "tailrec",
2400 "transformers",
1700 "transformers",
@@ -2406,8 +1706,9 @@
2406 ]
1706 ]
2407 },
1707 },
2408 "yoga-om-layer": {
1708 "yoga-om-layer": {
2409− "type": "local",
1709+ "type": "registry",
2410− "path": "../purescript-yoga-om-layer",
1710+ "version": "1.2.2",
1711+ "integrity": "sha256-Usw2ZysteSYNkEG3CDmVVXUk7cgr1mntkmhbR33nF6M=",
2411 "dependencies": [
1712 "dependencies": [
2412 "aff",
1713 "aff",
2413 "aff-retry",
1714 "aff-retry",
@@ -2422,7 +1723,6 @@
2422 "prelude",
1723 "prelude",
2423 "record",
1724 "record",
2424 "record-studio",
1725 "record-studio",
2425− "ref-lifted",
2426 "refs",
1726 "refs",
2427 "transformers",
1727 "transformers",
2428 "type-equality",
1728 "type-equality",
@@ -2433,8 +1733,9 @@
2433 ]
1733 ]
2434 },
1734 },
2435 "yoga-om-strom": {
1735 "yoga-om-strom": {
2436− "type": "local",
1736+ "type": "registry",
2437− "path": "../purescript-yoga-om-strom",
1737+ "version": "0.4.3",
1738+ "integrity": "sha256-dxj1zveEES6lF+iiMHx+qOhUG3zmiJJnlNpwiAfUBRE=",
2438 "dependencies": [
1739 "dependencies": [
2439 "aff",
1740 "aff",
2440 "arrays",
1741 "arrays",
@@ -2452,7 +1753,6 @@
2452 "maybe",
1753 "maybe",
2453 "now",
1754 "now",
2454 "prelude",
1755 "prelude",
2455− "ref-lifted",
2456 "refs",
1756 "refs",
2457 "spec",
1757 "spec",
2458 "st",
1758 "st",
@@ -2465,8 +1765,8 @@
2465 },
1765 },
2466 "yoga-options": {
1766 "yoga-options": {
2467 "type": "registry",
1767 "type": "registry",
2468− "version": "0.1.0",
1768+ "version": "0.1.1",
2469− "integrity": "sha256-8u9uwmxqwNX7bmA7U+hQ60ZnZxLzvlyYTVNXSIWeXv4=",
1769+ "integrity": "sha256-INtZKI2rw7KcDikzmyXlglsEujSMqHT5jz3ho9dVYC8=",
2470 "dependencies": [
1770 "dependencies": [
2471 "identity",
1771 "identity",
2472 "literals",
1772 "literals",
spago.yaml+25−33
@@ -1,28 +1,8 @@
1−workspace:
1+workspace: {}
2− packageSet:
3− registry: 73.0.0
4− extraPackages:
5− yoga-fastify-om:
6− path: ../purescript-yoga-fastify-om
7− yoga-fastify:
8− path: ../purescript-yoga-fastify
9− yoga-http-api:
10− path: ../purescript-yoga-http-api
11− yoga-om:
12− path: ../purescript-yoga-om
13− yoga-om-layer:
14− path: ../purescript-yoga-om-layer
15− yoga-om-strom:
16− path: ../purescript-yoga-om-strom
17− yoga-options: "0.1.0"
18− yoga-json: "5.2.0"
19− ref-lifted:
20− path: ../purescript-ref-lifted
21−
22package:
2package:
23 name: yoga-fetch-om
3 name: yoga-fetch-om
24 publish:
4 publish:
25− version: 0.6.0
5+ version: 0.8.1
26 license: MIT
6 license: MIT
27 location:
7 location:
28 githubOwner: rowtype-yoga
8 githubOwner: rowtype-yoga
@@ -30,37 +10,49 @@ package:
30 include:
10 include:
31 - LICENSE
11 - LICENSE
32 - README.md
12 - README.md
33− - CHANGELOG.md
34 exclude:
13 exclude:
35 - .github
14 - .github
36 dependencies:
15 dependencies:
37− - aff: ">=7.0.0 <9.0.0"
16+ - aff: ">=8.0.0 <9.0.0"
17+ - arraybuffer-types: ">=3.0.2 <4.0.0"
38 - arrays: ">=7.3.0 <8.0.0"
18 - arrays: ">=7.3.0 <8.0.0"
39 - effect: ">=4.0.0 <5.0.0"
19 - effect: ">=4.0.0 <5.0.0"
40 - either: ">=6.1.0 <7.0.0"
20 - either: ">=6.1.0 <7.0.0"
41 - exceptions: ">=6.1.0 <7.0.0"
21 - exceptions: ">=6.1.0 <7.0.0"
42− - http-methods: ">=6.0.0 <7.0.0"
22+ - http-methods: ">=6.1.0 <7.0.0"
43 - js-fetch: ">=0.2.1 <0.3.0"
23 - js-fetch: ">=0.2.1 <0.3.0"
44 - js-promise-aff: ">=1.0.0 <2.0.0"
24 - js-promise-aff: ">=1.0.0 <2.0.0"
45 - maybe: ">=6.0.0 <7.0.0"
25 - maybe: ">=6.0.0 <7.0.0"
46 - prelude: ">=6.0.2 <7.0.0"
26 - prelude: ">=6.0.2 <7.0.0"
47 - record: ">=4.0.0 <5.0.0"
27 - record: ">=4.0.0 <5.0.0"
48 - strings: ">=6.0.1 <7.0.0"
28 - strings: ">=6.0.1 <7.0.0"
29+ - tailrec: ">=6.1.0 <7.0.0"
49 - transformers: ">=6.1.0 <7.0.0"
30 - transformers: ">=6.1.0 <7.0.0"
50 - tuples: ">=7.0.0 <8.0.0"
31 - tuples: ">=7.0.0 <8.0.0"
51 - typelevel-prelude: ">=7.0.0 <8.0.0"
32 - typelevel-prelude: ">=7.0.0 <8.0.0"
52 - unsafe-coerce: ">=6.0.0 <7.0.0"
33 - unsafe-coerce: ">=6.0.0 <7.0.0"
53 - variant: ">=8.0.0 <9.0.0"
34 - variant: ">=8.0.0 <9.0.0"
54− - yoga-http-api: ">=0.1.0 <0.3.0"
35+ - yoga-http-api: ">=0.3.4 <0.4.0"
55− - yoga-json: ">=5.2.0 <6.0.0"
36+ - yoga-json: ">=5.2.1 <6.0.0"
56− - arraybuffer-types: ">=3.0.2 <4.0.0"
37+ - yoga-om: ">=1.5.2 <2.0.0"
57− - yoga-om: ">=1.2.2 <2.0.0"
38+ - yoga-om-strom: ">=0.4.3 <0.5.0"
58− - yoga-om-strom: ">=0.2.0 <0.5.0"
59 test:
39 test:
60 main: Test.Main
40 main: Test.Main
61 dependencies:
41 dependencies:
62− - spec: ">=8.0.0 <9.0.0"
42+ - enums
63− - spec-discovery: ">=8.0.0 <9.0.0"
43+ - foldable-traversable
44+ - foreign
45+ - foreign-object
46+ - integers
47+ - js-promise
48+ - partial
49+ - yoga-fastify
64 - console: ">=6.0.0 <7.0.0"
50 - console: ">=6.0.0 <7.0.0"
65− - yoga-fastify-om: ">=0.1.0 <0.4.0"
51+ - js-uri: ">=3.1.0 <4.0.0"
52+ - justifill: ">=0.5.0 <0.6.0"
53+ - quickcheck: ">=8.0.1 <9.0.0"
66 - refs: ">=6.0.0 <7.0.0"
54 - refs: ">=6.0.0 <7.0.0"
55+ - spec: ">=8.0.0 <9.0.0"
56+ - spec-discovery: ">=8.0.0 <9.0.0"
57+ - spec-quickcheck: ">=5.0.2 <6.0.0"
58+ - yoga-fastify-om: ">=0.4.7 <0.5.0"
src/Yoga/Fetch/Om.jsnew file+1
@@ -0,0 +1 @@
1+export const mergeRecords = (left) => (right) => ({ ...right, ...left });
src/Yoga/Fetch/Om.purs+183−42
@@ -1,5 +1,8 @@
1module Yoga.Fetch.Om
1module Yoga.Fetch.Om
2 ( client
2 ( client
3+ , clientWith
4+ , ClientInputs
5+ , ClientWithConfig
3 , deriveClient
6 , deriveClient
4 , class DeriveClient
7 , class DeriveClient
5 , deriveClientImpl
8 , deriveClientImpl
@@ -7,19 +10,25 @@ module Yoga.Fetch.Om
7 , deriveClientRL
10 , deriveClientRL
8 , class DeriveClientFn
11 , class DeriveClientFn
9 , deriveClientFn
12 , deriveClientFn
13+ , class DeriveClientFnWith
14+ , deriveClientFnWith
15+ , class DeriveClientWith
16+ , deriveClientWithImpl
17+ , class DeriveClientWithRL
18+ , deriveClientWithRL
10 , class RecordRow
19 , class RecordRow
11 , class ToHeaders
20 , class ToHeaders
12 , toHeaders
21 , toHeaders
13 , module Yoga.HTTP.API.Route
22 , module Yoga.HTTP.API.Route
14 , module Yoga.HTTP.API.Path
23 , module Yoga.HTTP.API.Path
15− , plainText
16 , module Yoga.Fetch.Om.StreamDecode
24 , module Yoga.Fetch.Om.StreamDecode
17 , module Yoga.Fetch.Om.Simple
25 , module Yoga.Fetch.Om.Simple
18 ) where
26 ) where
19
27
20import Prelude
28import Prelude
21
29
22−import Data.Symbol (class IsSymbol)
30+import Data.Symbol (class IsSymbol, reflectSymbol)
31+import Data.Tuple.Nested ((/\))
23import Data.Variant (Variant)
32import Data.Variant (Variant)
24import Prim.Row as Row
33import Prim.Row as Row
25import Prim.RowList (class RowToList, RowList)
34import Prim.RowList (class RowToList, RowList)
@@ -29,20 +38,31 @@ import Type.Proxy (Proxy(..))
29import Unsafe.Coerce (unsafeCoerce)
38import Unsafe.Coerce (unsafeCoerce)
30import JS.Fetch.Headers (Headers)
39import JS.Fetch.Headers (Headers)
31import JS.Fetch.Headers as Headers
40import JS.Fetch.Headers as Headers
32−import Type.Row.Homogeneous (class Homogeneous)
33import Yoga.Fetch.Om.BuildUrl (class BuildUrl, buildUrl)
41import Yoga.Fetch.Om.BuildUrl (class BuildUrl, buildUrl)
34import Yoga.Fetch.Om.Simple (class DecodeResponse, decodeResponse, FetchError, FetchResponse, get, getWithHeaders, delete, deleteWithHeaders, delete_, post, postWithHeaders, post_, put, putWithHeaders, put_, patch, patchWithHeaders, patch_)
42import Yoga.Fetch.Om.Simple (class DecodeResponse, decodeResponse, FetchError, FetchResponse, get, getWithHeaders, delete, deleteWithHeaders, delete_, post, postWithHeaders, post_, put, putWithHeaders, put_, patch, patchWithHeaders, patch_)
35import Yoga.Fetch.Om.StreamDecode (class StreamDecode, decodeStream)
43import Yoga.Fetch.Om.StreamDecode (class StreamDecode, decodeStream)
36import Yoga.Fetch.Om.ClientFunction (class BuildClientFn, class CheckBodyIsUnit, buildClientFn)
44import Yoga.Fetch.Om.ClientFunction (class BuildClientFn, class CheckBodyIsUnit, buildClientFn)
37−import Yoga.Fetch.Om.ExtractParams (class ExtractRequestBody, class ExtractRequestHeaders)
45+import Yoga.Fetch.Om.ExtractParams (class ExtractRequestBody, class ExtractBodyEncoding, class ExtractRequestHeaders)
38−import Yoga.Fetch.Om.MakeRequest (class MakeRequest, class SerializeBody, class ContentType, makeRequest, serializeBody, contentType)
46+import Yoga.Fetch.Om.MakeRequest (class MakeRequest, class BodyEncoding, makeRequest, encodingContentType, encodeBody)
39import Yoga.Fetch.Om.ParseResponse (class ParseResponse, parseResponse)
47import Yoga.Fetch.Om.ParseResponse (class ParseResponse, parseResponse)
40import Yoga.Fetch.Om.SplitResponses (class SplitResponses)
48import Yoga.Fetch.Om.SplitResponses (class SplitResponses)
41import Yoga.Fetch.Om.Variant (class VariantOrValue, variantOrValue)
49import Yoga.Fetch.Om.Variant (class VariantOrValue, variantOrValue)
42import Yoga.HTTP.API.Path (Path, Root, Lit, Capture, PathCons, Param, QueryParams, Required, type (/), type (:), type (:?), class PathPattern)
50import Yoga.HTTP.API.Path (Path, Root, Lit, Capture, PathCons, Param, QueryParams, Required, type (/), type (:), type (:?), class PathPattern)
43−import Yoga.HTTP.API.Route (Route(..), GET, POST, PUT, DELETE, PATCH, Response(..), JSON, FormData, PlainText, Streaming, NoBody)
51+import Yoga.HTTP.API.Route (Route(..), GET, POST, PUT, DELETE, PATCH, QUERY, Response(..), JSON, FormData, PlainText, Streaming, NoBody, class HeaderValue, printHeader)
44import Yoga.HTTP.API.Route.Handler (class SegmentPathParams, class SegmentQueryParams)
52import Yoga.HTTP.API.Route.Handler (class SegmentPathParams, class SegmentQueryParams)
45−import Yoga.Om (class ToOm, Om, toOm)
53+import Yoga.Om (Om, toOm)
54+
55+type ClientInputs providedHeaders providedQuery =
56+ { headers :: Record providedHeaders
57+ , query :: Record providedQuery
58+ }
59+
60+type ClientWithConfig ctx err providedHeaders providedQuery =
61+ { baseUrl :: Om { | ctx } err String
62+ , provide :: Om { | ctx } err (ClientInputs providedHeaders providedQuery)
63+ }
64+
65+foreign import mergeRecords :: forall left right out. Record left -> Record right -> Record out
46
66
47-- | Extract row type from Record type
67-- | Extract row type from Record type
48class RecordRow :: Type -> Row Type -> Constraint
68class RecordRow :: Type -> Row Type -> Constraint
@@ -57,25 +77,38 @@ class ToHeaders headersRL headers where
57instance ToHeaders RL.Nil headers where
77instance ToHeaders RL.Nil headers where
58 toHeaders _ _ = Headers.empty
78 toHeaders _ _ = Headers.empty
59
79
60−else instance Homogeneous headers String => ToHeaders headersRL headers where
80+else instance
61− toHeaders _ = Headers.fromRecord
81+ ( IsSymbol name
82+ , HeaderValue ty
83+ , Row.Cons name ty tailRow headers
84+ , Row.Lacks name tailRow
85+ , ToHeaders tail tailRow
86+ ) =>
87+ ToHeaders (RL.Cons name ty tail) headers where
88+ toHeaders _ headers = Headers.fromFoldable ([ headerName /\ headerValue ] <> Headers.toArray rest)
89+ where
90+ headerName = reflectSymbol (Proxy :: Proxy name)
91+ headerValue = printHeader (Record.get (Proxy :: Proxy name) headers)
92+ rest = toHeaders (Proxy :: Proxy tail) (unsafeCoerce headers :: Record tailRow)
62
93
63−class DeriveClientFn :: forall k1. Type -> k1 -> Type -> Row Type -> Row Type -> Row Type -> Type -> Type -> Constraint
94+class DeriveClientFn
95+ :: forall k1. Type -> k1 -> Type -> Row Type -> Row Type -> Row Type -> Row Type -> Type -> Type -> Constraint
64class
96class
65− DeriveClientFn method segments request response routeErrors successRow result fn
97+ DeriveClientFn method segments request response ctx extraErr routeErrors result fn
66− | method segments request response -> routeErrors successRow result fn where
98+ | method segments request response -> routeErrors result
99+ , method segments request response ctx extraErr -> fn where
67 deriveClientFn :: String -> Proxy (Route method segments request response) -> fn
100 deriveClientFn :: String -> Proxy (Route method segments request response) -> fn
68
101
69instance
102instance
70 ( SegmentPathParams segments pathParams
103 ( SegmentPathParams segments pathParams
71 , SegmentQueryParams segments queryParams
104 , SegmentQueryParams segments queryParams
72 , ExtractRequestBody request body
105 , ExtractRequestBody request body
106+ , ExtractBodyEncoding request encoding
73 , ExtractRequestHeaders request headers
107 , ExtractRequestHeaders request headers
74 , PathPattern segments
108 , PathPattern segments
75 , BuildUrl segments pathParams queryParams
109 , BuildUrl segments pathParams queryParams
76 , MakeRequest method
110 , MakeRequest method
77− , SerializeBody body
111+ , BodyEncoding encoding body
78− , ContentType body
79 , SplitResponses response successRow routeErrors
112 , SplitResponses response successRow routeErrors
80 , ParseResponse routeErrors successRow
113 , ParseResponse routeErrors successRow
81 , RowToList successRow successRL
114 , RowToList successRow successRL
@@ -86,74 +119,182 @@ instance
86 , RowToList headers headersRL
119 , RowToList headers headersRL
87 , ToHeaders headersRL headers
120 , ToHeaders headersRL headers
88 , CheckBodyIsUnit body bodyFlag
121 , CheckBodyIsUnit body bodyFlag
89− , BuildClientFn pathQueryRL headersRL bodyFlag body pathQuery headers routeErrors result fn
122+ , Row.Union routeErrors extraErr errRow
123+ , BuildClientFn pathQueryRL headersRL bodyFlag body pathQuery headers (Record pathQuery) { | ctx } errRow result fn
90 ) =>
124 ) =>
91− DeriveClientFn method segments request response routeErrors successRow result fn where
125+ DeriveClientFn method segments request response ctx extraErr routeErrors result fn where
92 deriveClientFn baseUrl _ =
126 deriveClientFn baseUrl _ =
93− buildClientFn (Proxy :: _ pathQueryRL) (Proxy :: _ headersRL) (Proxy :: _ bodyFlag) impl
127+ buildClientFn (Proxy :: _ pathQueryRL) (Proxy :: _ headersRL) (Proxy :: _ bodyFlag) identity impl
94 where
128 where
95− impl :: Record pathQuery -> Record headers -> body -> Om (Record ()) routeErrors result
129+ impl :: Record pathQuery -> Record headers -> body -> Om { | ctx } errRow result
96− impl pathQueryRec headersRec bodyVal = do
130+ impl pathQueryRec headersRec bodyVal = widenOm do
97 let url = buildUrl baseUrl (Proxy :: _ segments) pathParamsRec queryParamsRec
131 let url = buildUrl baseUrl (Proxy :: _ segments) pathParamsRec queryParamsRec
98 let hdrs = toHeaders (Proxy :: _ headersRL) headersRec
132 let hdrs = toHeaders (Proxy :: _ headersRL) headersRec
99− fetchResp <- makeRequest (Proxy :: _ method) url hdrs (contentType (Proxy :: _ body)) (serializeBody bodyVal) # toOm
133+ let ct = encodingContentType (Proxy :: _ encoding)
134+ fetchResp <- makeRequest (Proxy :: _ method) url hdrs ct (encodeBody @encoding bodyVal) # toOm
100 variant <- parseResponse fetchResp :: Om (Record ()) routeErrors (Variant successRow)
135 variant <- parseResponse fetchResp :: Om (Record ()) routeErrors (Variant successRow)
101 variantOrValue (Proxy :: _ successRL) variant # pure
136 variantOrValue (Proxy :: _ successRL) variant # pure
102 where
137 where
103 pathParamsRec = unsafeCoerce pathQueryRec :: Record pathParams
138 pathParamsRec = unsafeCoerce pathQueryRec :: Record pathParams
104 queryParamsRec = unsafeCoerce pathQueryRec :: Record queryParams
139 queryParamsRec = unsafeCoerce pathQueryRec :: Record queryParams
105
140
106−class DeriveClient :: Row Type -> Row Type -> Constraint
141+ widenOm :: Om (Record ()) routeErrors ~> Om { | ctx } errRow
107−class DeriveClient routesRow clientsRow | routesRow -> clientsRow where
142+ widenOm = unsafeCoerce
143+
144+class DeriveClientFnWith
145+ :: forall k1. Type -> k1 -> Type -> Row Type -> Row Type -> Row Type -> Row Type -> Row Type -> Row Type -> Type -> Type -> Constraint
146+class
147+ DeriveClientFnWith method segments request response providedHeaders providedQuery ctx extraErr routeErrors result fn
148+ | method segments request response -> routeErrors result
149+ , method segments request response providedHeaders providedQuery ctx extraErr -> fn where
150+ deriveClientFnWith
151+ :: ClientWithConfig ctx extraErr providedHeaders providedQuery
152+ -> Proxy (Route method segments request response)
153+ -> fn
154+
155+instance
156+ ( SegmentPathParams segments pathParams
157+ , SegmentQueryParams segments queryParams
158+ , ExtractRequestBody request body
159+ , ExtractBodyEncoding request encoding
160+ , ExtractRequestHeaders request headers
161+ , PathPattern segments
162+ , BuildUrl segments pathParams queryParams
163+ , MakeRequest method
164+ , BodyEncoding encoding body
165+ , SplitResponses response successRow routeErrors
166+ , Row.Union pathParams queryParams pathQuery
167+ , Row.Nub pathQuery pathQuery
168+ , ParseResponse routeErrors successRow
169+ , RowToList successRow successRL
170+ , VariantOrValue successRL successRow result
171+ , Row.Union routeErrors extraErr errRow
172+ , Row.Union providedQuery remainingQuery queryParams
173+ , Row.Union pathParams remainingQuery callerPathQuery
174+ , Row.Nub callerPathQuery callerPathQuery
175+ , RowToList callerPathQuery callerPathQueryRL
176+ , RowToList headers headersRL
177+ , ToHeaders headersRL headers
178+ , Row.Union providedHeaders remainingHeaders headers
179+ , Row.Nub headers headers
180+ , RowToList remainingHeaders remainingHeadersRL
181+ , CheckBodyIsUnit body bodyFlag
182+ , BuildClientFn callerPathQueryRL remainingHeadersRL bodyFlag body callerPathQuery remainingHeaders (Record callerPathQuery) { | ctx } errRow result fn
183+ ) =>
184+ DeriveClientFnWith method segments request response providedHeaders providedQuery ctx extraErr routeErrors result fn where
185+ deriveClientFnWith config _ =
186+ buildClientFn (Proxy :: _ callerPathQueryRL) (Proxy :: _ remainingHeadersRL) (Proxy :: _ bodyFlag) identity impl
187+ where
188+ impl :: Record callerPathQuery -> Record remainingHeaders -> body -> Om { | ctx } errRow result
189+ impl pathQueryRec headersRec bodyVal = do
190+ baseUrl <- widenExtra config.baseUrl
191+ provided <- widenExtra config.provide
192+ let pathParamsRec = unsafeCoerce pathQueryRec :: Record pathParams
193+ let queryParamsRec = mergeRecords provided.query (unsafeCoerce pathQueryRec :: Record remainingQuery) :: Record queryParams
194+ let fullHeaders = mergeRecords provided.headers headersRec :: Record headers
195+ let url = buildUrl baseUrl (Proxy :: _ segments) pathParamsRec queryParamsRec
196+ let hdrs = toHeaders (Proxy :: _ headersRL) fullHeaders
197+ let ct = encodingContentType (Proxy :: _ encoding)
198+ fetchResp <- makeRequest (Proxy :: _ method) url hdrs ct (encodeBody @encoding bodyVal) # toOm # widenRoute
199+ variant <- parseResponse fetchResp # widenRoute :: Om { | ctx } errRow (Variant successRow)
200+ variantOrValue (Proxy :: _ successRL) variant # pure
201+ where
202+ widenExtra :: Om { | ctx } extraErr ~> Om { | ctx } errRow
203+ widenExtra = unsafeCoerce
204+
205+ widenRoute :: Om (Record ()) routeErrors ~> Om { | ctx } errRow
206+ widenRoute = unsafeCoerce
207+
208+class DeriveClient :: Row Type -> Row Type -> Row Type -> Row Type -> Constraint
209+class DeriveClient ctx extraErr routesRow clientsRow | routesRow ctx extraErr -> clientsRow where
108 deriveClientImpl :: String -> Proxy (Record routesRow) -> Record clientsRow
210 deriveClientImpl :: String -> Proxy (Record routesRow) -> Record clientsRow
109
211
110−-- | Derive API client functions from route definitions using VTA
212+-- | Derive API client functions from route definitions using VTA.
213+-- | Generated fields use ordinary function application. Path parameters are
214+-- | plain records; optional query parameters are explicit `Maybe` fields.
111-- |
215-- |
112-- | ```purescript
216-- | ```purescript
113-- | type UserAPI = { getUser :: Route ... }
217-- | type UserAPI = { getUser :: Route ... }
114-- | api = client @UserAPI "https://api.example.com"
218-- | api = client @UserAPI "https://api.example.com"
219+-- | user <- api.getUser { id: 42 }
220+-- | users <- api.listUsers { limit: Just 10, offset: Nothing }
221+-- | health <- api.health
115-- | ```
222-- | ```
116−client :: forall @routes routesRow clientsRow polyClientsRow. RecordRow routes routesRow => DeriveClient routesRow clientsRow => String -> Record polyClientsRow
223+client :: forall @routes routesRow ctx extraErr clientsRow. RecordRow routes routesRow => DeriveClient ctx extraErr routesRow clientsRow => String -> Record clientsRow
117−client baseUrl = polymorphic (deriveClientImpl baseUrl (Proxy :: _ { | routesRow }) :: Record clientsRow)
224+client baseUrl = deriveClientImpl @ctx @extraErr baseUrl (Proxy :: _ { | routesRow })
118
225
119-- | Deprecated: Use `client` with VTA instead
226-- | Deprecated: Use `client` with VTA instead
120-- |
227-- |
121-- | ```purescript
228-- | ```purescript
122-- | api = deriveClient @UserAPI "https://api.example.com"
229-- | api = deriveClient @UserAPI "https://api.example.com"
123-- | ```
230-- | ```
124−deriveClient :: forall @routesRow clientsRow polyClientsRow. DeriveClient routesRow clientsRow => String -> Record polyClientsRow
231+deriveClient :: forall @routesRow ctx extraErr clientsRow. DeriveClient ctx extraErr routesRow clientsRow => String -> Record clientsRow
125−deriveClient baseUrl = polymorphic (deriveClientImpl baseUrl (Proxy :: _ { | routesRow }) :: Record clientsRow)
232+deriveClient baseUrl = deriveClientImpl @ctx @extraErr baseUrl (Proxy :: _ { | routesRow })
233+
234+clientWith
235+ :: forall @routes @providedHeaders @providedQuery routesRow ctx extraErr clientsRow
236+ . RecordRow routes routesRow
237+ => DeriveClientWith providedHeaders providedQuery ctx extraErr routesRow clientsRow
238+ => ClientWithConfig ctx extraErr providedHeaders providedQuery
239+ -> Record clientsRow
240+clientWith config = deriveClientWithImpl @providedHeaders @providedQuery @ctx @extraErr config (Proxy :: _ { | routesRow })
126
241
127−plainText :: PlainText -> String
242+instance
128−plainText = unsafeCoerce
243+ ( RowToList routesRow rl
244+ , DeriveClientRL ctx extraErr rl () clientsRow
245+ ) =>
246+ DeriveClient ctx extraErr routesRow clientsRow where
247+ deriveClientImpl baseUrl _ = deriveClientRL @ctx @extraErr baseUrl (Proxy :: _ rl) {}
129
248
130−polymorphic :: forall a b. a -> b
249+class DeriveClientWith :: Row Type -> Row Type -> Row Type -> Row Type -> Row Type -> Row Type -> Constraint
131−polymorphic = unsafeCoerce
250+class DeriveClientWith providedHeaders providedQuery ctx extraErr routesRow clientsRow | providedHeaders providedQuery routesRow ctx extraErr -> clientsRow where
251+ deriveClientWithImpl :: ClientWithConfig ctx extraErr providedHeaders providedQuery -> Proxy (Record routesRow) -> Record clientsRow
132
252
133instance
253instance
134 ( RowToList routesRow rl
254 ( RowToList routesRow rl
135− , DeriveClientRL rl () clientsRow
255+ , DeriveClientWithRL providedHeaders providedQuery ctx extraErr rl () clientsRow
256+ ) =>
257+ DeriveClientWith providedHeaders providedQuery ctx extraErr routesRow clientsRow where
258+ deriveClientWithImpl config _ = deriveClientWithRL @providedHeaders @providedQuery @ctx @extraErr config (Proxy :: _ rl) {}
259+
260+class DeriveClientWithRL :: Row Type -> Row Type -> Row Type -> Row Type -> RowList Type -> Row Type -> Row Type -> Constraint
261+class DeriveClientWithRL providedHeaders providedQuery ctx extraErr rl acc out | providedHeaders providedQuery ctx extraErr rl acc -> out where
262+ deriveClientWithRL :: ClientWithConfig ctx extraErr providedHeaders providedQuery -> Proxy rl -> Record acc -> Record out
263+
264+instance DeriveClientWithRL providedHeaders providedQuery ctx extraErr RL.Nil acc acc where
265+ deriveClientWithRL _ _ acc = acc
266+
267+instance
268+ ( IsSymbol label
269+ , DeriveClientFnWith method segments request response providedHeaders providedQuery ctx extraErr routeErrors result fn
270+ , DeriveClientWithRL providedHeaders providedQuery ctx extraErr tail acc1 acc2
271+ , Row.Cons label fn acc2 out
272+ , Row.Lacks label acc2
273+ , Row.Cons label (Route method segments request response) routeTail routeRow
136 ) =>
274 ) =>
137− DeriveClient routesRow clientsRow where
275+ DeriveClientWithRL providedHeaders providedQuery ctx extraErr (RL.Cons label (Route method segments request response) tail) acc1 out where
138− deriveClientImpl baseUrl _ = deriveClientRL baseUrl (Proxy :: _ rl) {}
276+ deriveClientWithRL config _ acc = Record.insert (Proxy :: _ label) clientFn rest
277+ where
278+ clientFn = deriveClientFnWith @_ @_ @_ @_ @providedHeaders @providedQuery @ctx @extraErr config (Proxy :: _ (Route method segments request response))
279+ rest = deriveClientWithRL @providedHeaders @providedQuery @ctx @extraErr config (Proxy :: _ tail) acc
139
280
140−class DeriveClientRL :: RowList Type -> Row Type -> Row Type -> Constraint
281+class DeriveClientRL :: Row Type -> Row Type -> RowList Type -> Row Type -> Row Type -> Constraint
141−class DeriveClientRL rl acc out | rl acc -> out where
282+class DeriveClientRL ctx extraErr rl acc out | ctx extraErr rl acc -> out where
142 deriveClientRL :: String -> Proxy rl -> Record acc -> Record out
283 deriveClientRL :: String -> Proxy rl -> Record acc -> Record out
143
284
144−instance DeriveClientRL RL.Nil acc acc where
285+instance DeriveClientRL ctx extraErr RL.Nil acc acc where
145 deriveClientRL _ _ acc = acc
286 deriveClientRL _ _ acc = acc
146
287
147instance
288instance
148 ( IsSymbol label
289 ( IsSymbol label
149− , DeriveClientFn method segments request response routeErrors successRow result fn
290+ , DeriveClientFn method segments request response ctx extraErr routeErrors result fn
150− , DeriveClientRL tail acc1 acc2
291+ , DeriveClientRL ctx extraErr tail acc1 acc2
151 , Row.Cons label fn acc2 out
292 , Row.Cons label fn acc2 out
152 , Row.Lacks label acc2
293 , Row.Lacks label acc2
153 , Row.Cons label (Route method segments request response) routeTail routeRow
294 , Row.Cons label (Route method segments request response) routeTail routeRow
154 ) =>
295 ) =>
155− DeriveClientRL (RL.Cons label (Route method segments request response) tail) acc1 out where
296+ DeriveClientRL ctx extraErr (RL.Cons label (Route method segments request response) tail) acc1 out where
156 deriveClientRL baseUrl _ acc = Record.insert (Proxy :: _ label) clientFn rest
297 deriveClientRL baseUrl _ acc = Record.insert (Proxy :: _ label) clientFn rest
157 where
298 where
158− clientFn = deriveClientFn baseUrl (Proxy :: _ (Route method segments request response))
299+ clientFn = deriveClientFn @_ @_ @_ @_ @ctx @extraErr baseUrl (Proxy :: _ (Route method segments request response))
159− rest = deriveClientRL baseUrl (Proxy :: _ tail) acc
300+ rest = deriveClientRL @ctx @extraErr baseUrl (Proxy :: _ tail) acc
src/Yoga/Fetch/Om/BuildUrl.js+86−2
@@ -1,3 +1,87 @@
1−export function encodeURIComponent_(s) {
1+export function encodeURIComponent_(value) {
2− return encodeURIComponent(s);
2+ try {
3+ return encodeURIComponent(value);
4+ } catch (error) {
5+ if (!(error instanceof URIError)) throw error;
6+ return encodeURIComponent(toWellFormed(value));
7+ }
8+}
9+
10+function toWellFormed(value) {
11+ if (typeof value.toWellFormed === "function") return value.toWellFormed();
12+
13+ let result = "";
14+ let sliceStart = 0;
15+ for (let index = 0; index < value.length; index += 1) {
16+ const codeUnit = value.charCodeAt(index);
17+ const previous = index === 0 ? 0 : value.charCodeAt(index - 1);
18+ const next =
19+ index + 1 === value.length ? 0 : value.charCodeAt(index + 1);
20+ const loneHigh =
21+ codeUnit >= 0xd800 &&
22+ codeUnit <= 0xdbff &&
23+ (next < 0xdc00 || next > 0xdfff);
24+ const loneLow =
25+ codeUnit >= 0xdc00 &&
26+ codeUnit <= 0xdfff &&
27+ (previous < 0xd800 || previous > 0xdbff);
28+
29+ if (!loneHigh && !loneLow) continue;
30+ result += value.slice(sliceStart, index) + "\ufffd";
31+ sliceStart = index + 1;
32+ }
33+
34+ return sliceStart === 0 ? value : result + value.slice(sliceStart);
35+}
36+
37+function urlSuffixIndex(url) {
38+ const queryIndex = url.indexOf("?");
39+ const fragmentIndex = url.indexOf("#");
40+ return Math.min(
41+ queryIndex === -1 ? url.length : queryIndex,
42+ fragmentIndex === -1 ? url.length : fragmentIndex,
43+ );
44+}
45+
46+export function appendPath_(base) {
47+ return function (path) {
48+ const suffixIndex = urlSuffixIndex(base);
49+ const prefix = base.slice(0, suffixIndex).replace(/\/+$/, "");
50+ return prefix + path + base.slice(suffixIndex);
51+ };
52+}
53+
54+
55+export function substitutePathParam_(name) {
56+ const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
57+ const segment = new RegExp(`(^|/):${escapedName}(?=/|[?#]|$)`, "g");
58+ return function (value) {
59+ const encodedValue = encodeURIComponent_(value);
60+ return function (url) {
61+ const suffixIndex = urlSuffixIndex(url);
62+ const path = url.slice(0, suffixIndex);
63+ return (
64+ path.replace(segment, (_, prefix) => prefix + encodedValue) +
65+ url.slice(suffixIndex)
66+ );
67+ };
68+ };
69+}
70+
71+export function appendQueryString_(url) {
72+ return function (queryString) {
73+ if (queryString === "") return url;
74+
75+ const fragmentIndex = url.indexOf("#");
76+ const beforeFragment =
77+ fragmentIndex === -1 ? url : url.slice(0, fragmentIndex);
78+ const fragment = fragmentIndex === -1 ? "" : url.slice(fragmentIndex);
79+ const separator = beforeFragment.includes("?")
80+ ? beforeFragment.endsWith("?") || beforeFragment.endsWith("&")
81+ ? ""
82+ : "&"
83+ : "?";
84+
85+ return beforeFragment + separator + queryString + fragment;
86+ };
3}
87}
src/Yoga/Fetch/Om/BuildUrl.purs+43−13
@@ -19,7 +19,6 @@ import Prelude
19
19
20import Data.Array as Array
20import Data.Array as Array
21import Data.Maybe (Maybe(..))
21import Data.Maybe (Maybe(..))
22−import Data.String (Pattern(..), Replacement(..))
23import Data.String as String
22import Data.String as String
24import Data.Symbol (class IsSymbol, reflectSymbol)
23import Data.Symbol (class IsSymbol, reflectSymbol)
25import Prim.Row as Row
24import Prim.Row as Row
@@ -28,8 +27,13 @@ import Prim.RowList as RL
28import Record as Record
27import Record as Record
29import Type.Proxy (Proxy(..))
28import Type.Proxy (Proxy(..))
30import Yoga.HTTP.API.Path (class PathPattern, pathPattern)
29import Yoga.HTTP.API.Path (class PathPattern, pathPattern)
30+import Yoga.Fetch.Om.ReadOptional (readOptional)
31
31
32foreign import encodeURIComponent_ :: String -> String
32foreign import encodeURIComponent_ :: String -> String
33+foreign import appendPath_ :: String -> String -> String
34+foreign import substitutePathParam_ :: String -> String -> String -> String
35+
36+foreign import appendQueryString_ :: String -> String -> String
33
37
34class BuildUrl :: forall k. k -> Row Type -> Row Type -> Constraint
38class BuildUrl :: forall k. k -> Row Type -> Row Type -> Constraint
35class BuildUrl segments pathParams queryParams | segments -> pathParams queryParams where
39class BuildUrl segments pathParams queryParams | segments -> pathParams queryParams where
@@ -46,10 +50,7 @@ instance
46 pattern = pathPattern segmentsProxy
50 pattern = pathPattern segmentsProxy
47 withBase = case baseUrl of
51 withBase = case baseUrl of
48 "" -> pattern
52 "" -> pattern
49− base -> dropTrailingSlash base <> pattern
53+ base -> appendPath_ base pattern
50− dropTrailingSlash s = case String.stripSuffix (Pattern "/") s of
51− Just s' -> dropTrailingSlash s'
52− Nothing -> s
53 withPathParams = substitutePathParamsImpl (Proxy :: _ pathParams) pathParamsRec withBase
54 withPathParams = substitutePathParamsImpl (Proxy :: _ pathParams) pathParamsRec withBase
54 withQueryParams = appendQueryParamsImpl (Proxy :: _ queryParams) queryParamsRec withPathParams
55 withQueryParams = appendQueryParamsImpl (Proxy :: _ queryParams) queryParamsRec withPathParams
55
56
@@ -84,8 +85,8 @@ instance
84 substitutePathParamsRL _ rec url = substitutePathParamsRL (Proxy :: _ tail) rec replaced
85 substitutePathParamsRL _ rec url = substitutePathParamsRL (Proxy :: _ tail) rec replaced
85 where
86 where
86 value = Record.get (Proxy :: _ name) rec
87 value = Record.get (Proxy :: _ name) rec
87− pattern = Pattern (":" <> reflectSymbol (Proxy :: _ name))
88+ name = reflectSymbol (Proxy :: _ name)
88− replaced = String.replaceAll pattern (Replacement (serializeParam value)) url
89+ replaced = substitutePathParam_ name (serializeParam value) url
89
90
90class AppendQueryParams :: Row Type -> Constraint
91class AppendQueryParams :: Row Type -> Constraint
91class AppendQueryParams params where
92class AppendQueryParams params where
@@ -99,12 +100,11 @@ instance
99 , AppendQueryParamsRL rl params
100 , AppendQueryParamsRL rl params
100 ) =>
101 ) =>
101 AppendQueryParams params where
102 AppendQueryParams params where
102− appendQueryParamsImpl _ rec url = url <> queryString
103+ appendQueryParamsImpl _ rec url = case pairs of
104+ [] -> url
105+ _ -> appendQueryString_ url (String.joinWith "&" pairs)
103 where
106 where
104 pairs = appendQueryParamsRL (Proxy :: _ rl) rec []
107 pairs = appendQueryParamsRL (Proxy :: _ rl) rec []
105− queryString = case pairs of
106− [] -> ""
107− _ -> "?" <> String.joinWith "&" pairs
108
108
109class AppendQueryParamsRL :: RowList Type -> Row Type -> Constraint
109class AppendQueryParamsRL :: RowList Type -> Row Type -> Constraint
110class AppendQueryParamsRL rl r where
110class AppendQueryParamsRL rl r where
@@ -113,19 +113,49 @@ class AppendQueryParamsRL rl r where
113instance AppendQueryParamsRL RL.Nil r where
113instance AppendQueryParamsRL RL.Nil r where
114 appendQueryParamsRL _ _ acc = acc
114 appendQueryParamsRL _ _ acc = acc
115
115
116+-- Maybe (Array ty): optional repeated query param — missing/empty field → no pairs
116instance
117instance
117 ( IsSymbol name
118 ( IsSymbol name
118 , SerializeParam ty
119 , SerializeParam ty
119 , AppendQueryParamsRL tail r
120 , AppendQueryParamsRL tail r
120− , Row.Cons name (Maybe ty) tailRow r
121+ ) =>
122+ AppendQueryParamsRL (RL.Cons name (Maybe (Array ty)) tail) r where
123+ appendQueryParamsRL _ rec acc = appendQueryParamsRL (Proxy :: _ tail) rec acc'
124+ where
125+ encName = encodeURIComponent_ (reflectSymbol (Proxy :: _ name))
126+ acc' = case (readOptional @name rec :: Maybe (Array ty)) of
127+ Nothing -> acc
128+ Just values -> acc <> map (\v -> encName <> "=" <> encodeURIComponent_ (serializeParam v)) values
129+
130+-- Maybe ty: read with undefined-awareness — missing field → skip
131+else instance
132+ ( IsSymbol name
133+ , SerializeParam ty
134+ , AppendQueryParamsRL tail r
121 ) =>
135 ) =>
122 AppendQueryParamsRL (RL.Cons name (Maybe ty) tail) r where
136 AppendQueryParamsRL (RL.Cons name (Maybe ty) tail) r where
123 appendQueryParamsRL _ rec acc = appendQueryParamsRL (Proxy :: _ tail) rec acc'
137 appendQueryParamsRL _ rec acc = appendQueryParamsRL (Proxy :: _ tail) rec acc'
124 where
138 where
125− acc' = case Record.get (Proxy :: _ name) rec of
139+ acc' = case (readOptional @name rec :: Maybe ty) of
126 Nothing -> acc
140 Nothing -> acc
127 Just value -> Array.snoc acc (encodeURIComponent_ (reflectSymbol (Proxy :: _ name)) <> "=" <> encodeURIComponent_ (serializeParam value))
141 Just value -> Array.snoc acc (encodeURIComponent_ (reflectSymbol (Proxy :: _ name)) <> "=" <> encodeURIComponent_ (serializeParam value))
128
142
143+-- Array ty: emit one `name=value` pair per element (repeated keys)
144+else instance
145+ ( IsSymbol name
146+ , SerializeParam ty
147+ , AppendQueryParamsRL tail r
148+ , Row.Cons name (Array ty) tailRow r
149+ ) =>
150+ AppendQueryParamsRL (RL.Cons name (Array ty) tail) r where
151+ appendQueryParamsRL _ rec acc =
152+ appendQueryParamsRL (Proxy :: _ tail) rec (acc <> pairs)
153+ where
154+ encName = encodeURIComponent_ (reflectSymbol (Proxy :: _ name))
155+ values = Record.get (Proxy :: _ name) rec
156+ pairs = map (\v -> encName <> "=" <> encodeURIComponent_ (serializeParam v)) values
157+
158+-- bare ty (Required query param): always present
129else instance
159else instance
130 ( IsSymbol name
160 ( IsSymbol name
131 , SerializeParam ty
161 , SerializeParam ty
src/Yoga/Fetch/Om/ClientFunction.purs+37−20
@@ -22,17 +22,18 @@ instance CheckBodyIsUnit Unit IsUnit
22else instance CheckBodyIsUnit body IsNotUnit
22else instance CheckBodyIsUnit body IsNotUnit
23
23
24class BuildClientFn
24class BuildClientFn
25− :: RowList Type -> RowList Type -> Type -> Type -> Row Type -> Row Type -> Row Type -> Type -> Type -> Constraint
25+ :: RowList Type -> RowList Type -> Type -> Type -> Row Type -> Row Type -> Type -> Type -> Row Type -> Type -> Type -> Constraint
26class
26class
27− BuildClientFn pathQueryRL headersRL bodyFlag body pathQuery headers errorRow result fn
27+ BuildClientFn pathQueryRL headersRL bodyFlag body pathQuery headers arg ctx errorRow result fn
28 | pathQueryRL -> pathQuery
28 | pathQueryRL -> pathQuery
29 , headersRL -> headers
29 , headersRL -> headers
30− , pathQueryRL headersRL bodyFlag body errorRow result -> fn where
30+ , pathQueryRL headersRL bodyFlag body arg ctx errorRow result -> fn where
31 buildClientFn
31 buildClientFn
32 :: Proxy pathQueryRL
32 :: Proxy pathQueryRL
33 -> Proxy headersRL
33 -> Proxy headersRL
34 -> Proxy bodyFlag
34 -> Proxy bodyFlag
35− -> (Record pathQuery -> Record headers -> body -> Om (Record ()) errorRow result)
35+ -> (arg -> Record pathQuery)
36+ -> (Record pathQuery -> Record headers -> body -> Om ctx errorRow result)
36 -> fn
37 -> fn
37
38
38-- No path/query, no headers, no body
39-- No path/query, no headers, no body
@@ -43,10 +44,12 @@ instance
43 Unit
44 Unit
44 ()
45 ()
45 ()
46 ()
47+ arg
48+ ctx
46 errorRow
49 errorRow
47 result
50 result
48− (Om (Record ()) errorRow result) where
51+ (Om ctx errorRow result) where
49− buildClientFn _ _ _ f = f {} {} unit
52+ buildClientFn _ _ _ _ f = f {} {} unit
50
53
51-- No path/query, no headers, with body
54-- No path/query, no headers, with body
52instance
55instance
@@ -56,10 +59,12 @@ instance
56 body
59 body
57 ()
60 ()
58 ()
61 ()
62+ arg
63+ ctx
59 errorRow
64 errorRow
60 result
65 result
61− (body -> Om (Record ()) errorRow result) where
66+ (body -> Om ctx errorRow result) where
62− buildClientFn _ _ _ f b = f {} {} b
67+ buildClientFn _ _ _ _ f b = f {} {} b
63
68
64-- No path/query, with headers, no body
69-- No path/query, with headers, no body
65instance
70instance
@@ -69,10 +74,12 @@ instance
69 Unit
74 Unit
70 ()
75 ()
71 h
76 h
77+ arg
78+ ctx
72 errorRow
79 errorRow
73 result
80 result
74− (Record h -> Om (Record ()) errorRow result) where
81+ (Record h -> Om ctx errorRow result) where
75− buildClientFn _ _ _ f hdrs = f {} hdrs unit
82+ buildClientFn _ _ _ _ f hdrs = f {} hdrs unit
76
83
77-- No path/query, with headers, with body
84-- No path/query, with headers, with body
78instance
85instance
@@ -82,10 +89,12 @@ instance
82 body
89 body
83 ()
90 ()
84 h
91 h
92+ arg
93+ ctx
85 errorRow
94 errorRow
86 result
95 result
87− (Record h -> body -> Om (Record ()) errorRow result) where
96+ (Record h -> body -> Om ctx errorRow result) where
88− buildClientFn _ _ _ f hdrs b = f {} hdrs b
97+ buildClientFn _ _ _ _ f hdrs b = f {} hdrs b
89
98
90-- With path/query, no headers, no body
99-- With path/query, no headers, no body
91instance
100instance
@@ -95,10 +104,12 @@ instance
95 Unit
104 Unit
96 pq
105 pq
97 ()
106 ()
107+ arg
108+ ctx
98 errorRow
109 errorRow
99 result
110 result
100− (Record pq -> Om (Record ()) errorRow result) where
111+ (arg -> Om ctx errorRow result) where
101− buildClientFn _ _ _ f pqr = f pqr {} unit
112+ buildClientFn _ _ _ convert f pqr = f (convert pqr) {} unit
102
113
103-- With path/query, no headers, with body
114-- With path/query, no headers, with body
104instance
115instance
@@ -108,10 +119,12 @@ instance
108 body
119 body
109 pq
120 pq
110 ()
121 ()
122+ arg
123+ ctx
111 errorRow
124 errorRow
112 result
125 result
113− (Record pq -> body -> Om (Record ()) errorRow result) where
126+ (arg -> body -> Om ctx errorRow result) where
114− buildClientFn _ _ _ f pqr b = f pqr {} b
127+ buildClientFn _ _ _ convert f pqr b = f (convert pqr) {} b
115
128
116-- With path/query, with headers, no body
129-- With path/query, with headers, no body
117instance
130instance
@@ -121,10 +134,12 @@ instance
121 Unit
134 Unit
122 pq
135 pq
123 h
136 h
137+ arg
138+ ctx
124 errorRow
139 errorRow
125 result
140 result
126− (Record pq -> Record h -> Om (Record ()) errorRow result) where
141+ (arg -> Record h -> Om ctx errorRow result) where
127− buildClientFn _ _ _ f pqr hdrs = f pqr hdrs unit
142+ buildClientFn _ _ _ convert f pqr hdrs = f (convert pqr) hdrs unit
128
143
129-- With path/query, with headers, with body
144-- With path/query, with headers, with body
130instance
145instance
@@ -134,7 +149,9 @@ instance
134 body
149 body
135 pq
150 pq
136 h
151 h
152+ arg
153+ ctx
137 errorRow
154 errorRow
138 result
155 result
139− (Record pq -> Record h -> body -> Om (Record ()) errorRow result) where
156+ (arg -> Record h -> body -> Om ctx errorRow result) where
140− buildClientFn _ _ _ f = f
157+ buildClientFn _ _ _ convert f pqr hdrs b = f (convert pqr) hdrs b
src/Yoga/Fetch/Om/ExtractParams.purs+13
@@ -1,6 +1,7 @@
1module Yoga.Fetch.Om.ExtractParams
1module Yoga.Fetch.Om.ExtractParams
2 ( class ExtractRequestHeaders
2 ( class ExtractRequestHeaders
3 , class ExtractRequestBody
3 , class ExtractRequestBody
4+ , class ExtractBodyEncoding
4 , class FindBodyType
5 , class FindBodyType
5 , class UnwrapEncoding
6 , class UnwrapEncoding
6 , class FindHeaders
7 , class FindHeaders
@@ -25,6 +26,18 @@ else instance
25 ExtractRequestBody (Record row) body =>
26 ExtractRequestBody (Record row) body =>
26 ExtractRequestBody (Request (Record row)) body
27 ExtractRequestBody (Request (Record row)) body
27
28
29+class ExtractBodyEncoding :: Type -> Type -> Constraint
30+class ExtractBodyEncoding request encoding | request -> encoding
31+
32+instance
33+ ( RowToList row rl
34+ , FindBodyType rl encoding
35+ ) =>
36+ ExtractBodyEncoding (Record row) encoding
37+else instance
38+ ExtractBodyEncoding (Record row) encoding =>
39+ ExtractBodyEncoding (Request (Record row)) encoding
40+
28class ExtractRequestHeaders :: Type -> Row Type -> Constraint
41class ExtractRequestHeaders :: Type -> Row Type -> Constraint
29class ExtractRequestHeaders request headers | request -> headers
42class ExtractRequestHeaders request headers | request -> headers
30
43
src/Yoga/Fetch/Om/MakeRequest.jsnew file+1
@@ -0,0 +1 @@
1+export const toUrlEncoded = (obj) => new URLSearchParams(obj).toString();
src/Yoga/Fetch/Om/MakeRequest.purs+31−27
@@ -2,10 +2,9 @@ module Yoga.Fetch.Om.MakeRequest
2 ( class MakeRequest
2 ( class MakeRequest
3 , httpMethod
3 , httpMethod
4 , makeRequest
4 , makeRequest
5− , class SerializeBody
5+ , class BodyEncoding
6− , serializeBody
6+ , encodingContentType
7− , class ContentType
7+ , encodeBody
8− , contentType
9 ) where
8 ) where
10
9
11import Prelude
10import Prelude
@@ -32,6 +31,7 @@ import JS.Fetch.Duplex as Duplex
32import JS.Fetch.Response (Response) as FetchResponse
31import JS.Fetch.Response (Response) as FetchResponse
33import Promise.Aff as Promise
32import Promise.Aff as Promise
34import Type.Proxy (Proxy)
33import Type.Proxy (Proxy)
34+import Yoga.HTTP.API.Route.Encoding (JSON, FormData, PlainText, NoBody)
35import Yoga.HTTP.API.Route.Method as Method
35import Yoga.HTTP.API.Route.Method as Method
36import Yoga.JSON (class WriteForeign, writeJSON)
36import Yoga.JSON (class WriteForeign, writeJSON)
37
37
@@ -54,6 +54,9 @@ instance MakeRequest Method.DELETE where
54instance MakeRequest Method.PATCH where
54instance MakeRequest Method.PATCH where
55 httpMethod _ = PATCH
55 httpMethod _ = PATCH
56
56
57+instance MakeRequest Method.QUERY where
58+ httpMethod _ = QUERY
59+
57makeRequest
60makeRequest
58 :: forall method
61 :: forall method
59 . MakeRequest method
62 . MakeRequest method
@@ -63,7 +66,7 @@ makeRequest
63 -> String
66 -> String
64 -> Maybe String
67 -> Maybe String
65 -> Aff FetchResponse.Response
68 -> Aff FetchResponse.Response
66−makeRequest proxy url customHeaders defaultContentType maybeBody = do
69+makeRequest proxy url customHeaders bodyContentType maybeBody = do
67 request <- Request.new url options # liftEffect
70 request <- Request.new url options # liftEffect
68 Promise.toAffE $ Fetch.fetch request
71 Promise.toAffE $ Fetch.fetch request
69 where
72 where
@@ -73,7 +76,7 @@ makeRequest proxy url customHeaders defaultContentType maybeBody = do
73 contentTypeArr = case maybeBody of
76 contentTypeArr = case maybeBody of
74 Nothing -> []
77 Nothing -> []
75 Just _ | hasContentType -> []
78 Just _ | hasContentType -> []
76− Just _ -> [ "Content-Type" /\ defaultContentType ]
79+ Just _ -> [ "Content-Type" /\ bodyContentType ]
77 allHeaders = Headers.fromFoldable (contentTypeArr <> customArr)
80 allHeaders = Headers.fromFoldable (contentTypeArr <> customArr)
78 body = case maybeBody of
81 body = case maybeBody of
79 Nothing -> Body.empty
82 Nothing -> Body.empty
@@ -91,24 +94,25 @@ makeRequest proxy url customHeaders defaultContentType maybeBody = do
91 , cache: Cache.Default
94 , cache: Cache.Default
92 }
95 }
93
96
94−class ContentType :: Type -> Constraint
97+class BodyEncoding :: Type -> Type -> Constraint
95−class ContentType body where
98+class BodyEncoding encoding body | encoding -> body where
96− contentType :: Proxy body -> String
99+ encodingContentType :: Proxy encoding -> String
97−
100+ encodeBody :: body -> Maybe String
98−instance ContentType String where
101+
99− contentType _ = "text/plain"
102+instance WriteForeign ty => BodyEncoding (JSON ty) ty where
100−else instance ContentType Unit where
103+ encodingContentType _ = "application/json"
101− contentType _ = "application/json"
104+ encodeBody b = Just (writeJSON b)
102−else instance ContentType body where
105+
103− contentType _ = "application/json"
106+else instance BodyEncoding PlainText String where
104−
107+ encodingContentType _ = "text/plain"
105−class SerializeBody :: Type -> Constraint
108+ encodeBody = Just
106−class SerializeBody body where
109+
107− serializeBody :: body -> Maybe String
110+else instance BodyEncoding (FormData ty) ty where
108−
111+ encodingContentType _ = "application/x-www-form-urlencoded"
109−instance SerializeBody String where
112+ encodeBody b = Just (toUrlEncoded b)
110− serializeBody s = Just s
113+
111−else instance SerializeBody Unit where
114+else instance BodyEncoding NoBody Unit where
112− serializeBody _ = Nothing
115+ encodingContentType _ = ""
113−else instance WriteForeign body => SerializeBody body where
116+ encodeBody _ = Nothing
114− serializeBody b = Just (writeJSON b)
117+
118+foreign import toUrlEncoded :: forall a. a -> String
src/Yoga/Fetch/Om/ParseResponse.purs+33−29
@@ -5,6 +5,8 @@ module Yoga.Fetch.Om.ParseResponse
5 , parseSuccessRL
5 , parseSuccessRL
6 , class ParseErrorRL
6 , class ParseErrorRL
7 , parseErrorRL
7 , parseErrorRL
8+ , class ParseResponseBody
9+ , parseResponseBody
8 ) where
10 ) where
9
11
10import Prelude
12import Prelude
@@ -27,15 +29,23 @@ import Promise.Aff as Promise
27import Type.Proxy (Proxy(..))
29import Type.Proxy (Proxy(..))
28import Unsafe.Coerce (unsafeCoerce)
30import Unsafe.Coerce (unsafeCoerce)
29import Yoga.Fetch.Om.StreamDecode (class StreamDecode, decodeStream)
31import Yoga.Fetch.Om.StreamDecode (class StreamDecode, decodeStream)
30−import Yoga.HTTP.API.Route.Encoding (PlainText, Streaming)
31import Yoga.HTTP.API.Route.StatusCode (class StatusCodeMap, statusCodeFor, StatusCode(..))
32import Yoga.HTTP.API.Route.StatusCode (class StatusCodeMap, statusCodeFor, StatusCode(..))
32import Yoga.JSON (class ReadForeign, readJSON)
33import Yoga.JSON (class ReadForeign, readJSON)
33import Yoga.JSON.Error (withStringErrors)
34import Yoga.JSON.Error (withStringErrors)
34−import Yoga.Om (class ToOm, Om, toOm)
35+import Yoga.Om (Om, toOm)
35import Yoga.Om.Error (Exception)
36import Yoga.Om.Error (Exception)
36import Yoga.Om.Strom (Strom)
37import Yoga.Om.Strom (Strom)
37import Yoga.Om.Strom.WebStream as WebStream
38import Yoga.Om.Strom.WebStream as WebStream
38
39
40+class ParseResponseBody (body :: Type) where
41+ parseResponseBody :: String -> Either String body
42+
43+instance ParseResponseBody String where
44+ parseResponseBody = Right
45+
46+else instance ReadForeign body => ParseResponseBody body where
47+ parseResponseBody = withStringErrors <<< readJSON
48+
39class ParseResponse (errorRow :: Row Type) (successRow :: Row Type) where
49class ParseResponse (errorRow :: Row Type) (successRow :: Row Type) where
40 parseResponse :: FetchResponse.Response -> Om {} errorRow (Variant successRow)
50 parseResponse :: FetchResponse.Response -> Om {} errorRow (Variant successRow)
41
51
@@ -50,11 +60,9 @@ instance
50 let status = Fetch.status fetchResp
60 let status = Fetch.status fetchResp
51 if status >= 200 && status < 300 then
61 if status >= 200 && status < 300 then
52 parseSuccessRL (Proxy :: _ successRL) status fetchResp # toOm
62 parseSuccessRL (Proxy :: _ successRL) status fetchResp # toOm
53− else if status >= 400 then do
63+ else do
54 errorText <- Promise.toAffE (Fetch.text fetchResp) # toOm
64 errorText <- Promise.toAffE (Fetch.text fetchResp) # toOm
55 parseErrorRL (Proxy :: _ errorRL) (Proxy :: _ errorRow) status errorText
65 parseErrorRL (Proxy :: _ errorRL) (Proxy :: _ errorRow) status errorText
56− else
57− throwError (Variant.inj (Proxy :: _ "exception") (Exception.error ("Unexpected HTTP status code: " <> show status)))
58
66
59class ParseSuccessRL (rl :: RowList Type) (successRow :: Row Type) | rl -> successRow where
67class ParseSuccessRL (rl :: RowList Type) (successRow :: Row Type) | rl -> successRow where
60 parseSuccessRL :: Proxy rl -> Int -> FetchResponse.Response -> Aff (Variant successRow)
68 parseSuccessRL :: Proxy rl -> Int -> FetchResponse.Response -> Aff (Variant successRow)
@@ -66,41 +74,39 @@ instance ParseSuccessRL RL.Nil successRow where
66else instance
74else instance
67 ( IsSymbol label
75 ( IsSymbol label
68 , StatusCodeMap label
76 , StatusCodeMap label
69− , Row.Cons label PlainText tailRow successRow
77+ , StreamDecode a
78+ , Row.Cons label (Strom streamContext streamError a) tailRow successRow
70 , Row.Lacks label tailRow
79 , Row.Lacks label tailRow
71 , ParseSuccessRL tailRL successRow
80 , ParseSuccessRL tailRL successRow
72 ) =>
81 ) =>
73− ParseSuccessRL (RL.Cons label PlainText tailRL) successRow where
82+ ParseSuccessRL (RL.Cons label (Strom streamContext streamError a) tailRL) successRow where
74 parseSuccessRL _ actualStatus fetchResp = do
83 parseSuccessRL _ actualStatus fetchResp = do
75 let StatusCode expected = statusCodeFor (Proxy :: _ label)
84 let StatusCode expected = statusCodeFor (Proxy :: _ label)
76 if actualStatus == expected then do
85 if actualStatus == expected then do
77− text <- liftEffect (Fetch.text fetchResp) >>= Promise.toAff
86+ webStream <- liftEffect (Fetch.body fetchResp)
78− pure (Variant.inj (Proxy :: _ label) (unsafeCoerce text))
87+ let strom = decodeStream (WebStream.fromReadableStream (unsafeCoerce webStream)) :: Strom {} () a
88+ pure (Variant.inj (Proxy :: _ label) (unsafeCoerce strom))
79 else
89 else
80 parseSuccessRL (Proxy :: _ tailRL) actualStatus fetchResp
90 parseSuccessRL (Proxy :: _ tailRL) actualStatus fetchResp
81
91
82else instance
92else instance
83 ( IsSymbol label
93 ( IsSymbol label
84 , StatusCodeMap label
94 , StatusCodeMap label
85− , StreamDecode a
95+ , Row.Cons label Unit tailRow successRow
86− , Row.Cons label (Streaming a) tailRow successRow
87 , Row.Lacks label tailRow
96 , Row.Lacks label tailRow
88 , ParseSuccessRL tailRL successRow
97 , ParseSuccessRL tailRL successRow
89 ) =>
98 ) =>
90− ParseSuccessRL (RL.Cons label (Streaming a) tailRL) successRow where
99+ ParseSuccessRL (RL.Cons label Unit tailRL) successRow where
91 parseSuccessRL _ actualStatus fetchResp = do
100 parseSuccessRL _ actualStatus fetchResp = do
92 let StatusCode expected = statusCodeFor (Proxy :: _ label)
101 let StatusCode expected = statusCodeFor (Proxy :: _ label)
93− if actualStatus == expected then do
102+ if actualStatus == expected then
94− webStream <- liftEffect (Fetch.body fetchResp)
103+ pure (Variant.inj (Proxy :: _ label) unit)
95− let strom = decodeStream (WebStream.fromReadableStream (unsafeCoerce webStream)) :: Strom {} () a
96− pure (Variant.inj (Proxy :: _ label) (unsafeCoerce strom))
97 else
104 else
98 parseSuccessRL (Proxy :: _ tailRL) actualStatus fetchResp
105 parseSuccessRL (Proxy :: _ tailRL) actualStatus fetchResp
99−
100else instance
106else instance
101 ( IsSymbol label
107 ( IsSymbol label
102 , StatusCodeMap label
108 , StatusCodeMap label
103− , ReadForeign body
109+ , ParseResponseBody body
104 , Row.Cons label body tailRow successRow
110 , Row.Cons label body tailRow successRow
105 , Row.Lacks label tailRow
111 , Row.Lacks label tailRow
106 , ParseSuccessRL tailRL successRow
112 , ParseSuccessRL tailRL successRow
@@ -110,7 +116,7 @@ else instance
110 let StatusCode expected = statusCodeFor (Proxy :: _ label)
116 let StatusCode expected = statusCodeFor (Proxy :: _ label)
111 if actualStatus == expected then do
117 if actualStatus == expected then do
112 jsonText <- liftEffect (Fetch.text fetchResp) >>= Promise.toAff
118 jsonText <- liftEffect (Fetch.text fetchResp) >>= Promise.toAff
113− case withStringErrors (readJSON jsonText) of
119+ case parseResponseBody jsonText of
114 Left errs -> Aff.throwError (Exception.error ("Failed to parse response (status " <> show actualStatus <> "):\n" <> errs))
120 Left errs -> Aff.throwError (Exception.error ("Failed to parse response (status " <> show actualStatus <> "):\n" <> errs))
115 Right parsed -> pure (Variant.inj (Proxy :: _ label) parsed)
121 Right parsed -> pure (Variant.inj (Proxy :: _ label) parsed)
116 else
122 else
@@ -132,23 +138,21 @@ instance ParseErrorRL RL.Nil errorRow where
132else instance
138else instance
133 ( IsSymbol label
139 ( IsSymbol label
134 , StatusCodeMap label
140 , StatusCodeMap label
135− , Row.Cons label PlainText tailRow errorRow
141+ , Row.Cons label Unit tailRow errorRow
136 , Row.Lacks label tailRow
142 , Row.Lacks label tailRow
137− , Row.Cons label PlainText tailExc (Exception errorRow)
143+ , Row.Cons label Unit tailExc (Exception errorRow)
138 , ParseErrorRL tailRL errorRow
144 , ParseErrorRL tailRL errorRow
139 ) =>
145 ) =>
140− ParseErrorRL (RL.Cons label PlainText tailRL) errorRow where
146+ ParseErrorRL (RL.Cons label Unit tailRL) errorRow where
141− parseErrorRL _ errorProxy actualStatus text = do
147+ parseErrorRL _ errorProxy actualStatus jsonText = do
142 let StatusCode expected = statusCodeFor (Proxy :: _ label)
148 let StatusCode expected = statusCodeFor (Proxy :: _ label)
143− if actualStatus == expected then
149+ if actualStatus == expected then throwError (Variant.inj (Proxy :: _ label) unit)
144− throwError (Variant.inj (Proxy :: _ label) (unsafeCoerce text))
150+ else parseErrorRL (Proxy :: _ tailRL) errorProxy actualStatus jsonText
145− else
146− parseErrorRL (Proxy :: _ tailRL) errorProxy actualStatus text
147
151
148else instance
152else instance
149 ( IsSymbol label
153 ( IsSymbol label
150 , StatusCodeMap label
154 , StatusCodeMap label
151− , ReadForeign body
155+ , ParseResponseBody body
152 , Row.Cons label body tailRow errorRow
156 , Row.Cons label body tailRow errorRow
153 , Row.Lacks label tailRow
157 , Row.Lacks label tailRow
154 , Row.Cons label body tailExc (Exception errorRow)
158 , Row.Cons label body tailExc (Exception errorRow)
@@ -157,7 +161,7 @@ else instance
157 ParseErrorRL (RL.Cons label body tailRL) errorRow where
161 ParseErrorRL (RL.Cons label body tailRL) errorRow where
158 parseErrorRL _ errorProxy actualStatus jsonText = do
162 parseErrorRL _ errorProxy actualStatus jsonText = do
159 let StatusCode expected = statusCodeFor (Proxy :: _ label)
163 let StatusCode expected = statusCodeFor (Proxy :: _ label)
160− if actualStatus == expected then case withStringErrors (readJSON jsonText) of
164+ if actualStatus == expected then case parseResponseBody jsonText of
161 Left errs -> throwError (Variant.inj (Proxy :: _ "exception") (Exception.error ("Failed to parse error response (status " <> show actualStatus <> "):\n" <> errs)))
165 Left errs -> throwError (Variant.inj (Proxy :: _ "exception") (Exception.error ("Failed to parse error response (status " <> show actualStatus <> "):\n" <> errs)))
162 Right parsed -> throwError (Variant.inj (Proxy :: _ label) parsed)
166 Right parsed -> throwError (Variant.inj (Proxy :: _ label) parsed)
163 else
167 else
src/Yoga/Fetch/Om/ReadOptional.jsnew file+18
@@ -0,0 +1,18 @@
1+import * as Maybe from "../Data.Maybe/index.js";
2+
3+export function readOptionalImpl(key) {
4+ return function (obj) {
5+ const val = obj[key];
6+ if (val === undefined || val instanceof Maybe.Nothing) {
7+ return Maybe.Nothing.value;
8+ }
9+ if (val instanceof Maybe.Just) return val;
10+ return Maybe.Just.create(val);
11+ };
12+}
13+
14+export function readRequiredField(key) {
15+ return function (obj) {
16+ return obj[key];
17+ };
18+}
src/Yoga/Fetch/Om/ReadOptional.pursnew file+56
@@ -0,0 +1,56 @@
1+module Yoga.Fetch.Om.ReadOptional
2+ ( readOptional
3+ , class ReadPartialQuery
4+ , readPartialQuery
5+ ) where
6+
7+import Data.Maybe (Maybe)
8+import Data.Symbol (class IsSymbol, reflectSymbol)
9+import Prim.Row as Row
10+import Prim.RowList (RowList)
11+import Prim.RowList as RL
12+import Record as Record
13+import Type.Proxy (Proxy(..))
14+
15+foreign import readOptionalImpl :: forall a r. String -> Record r -> Maybe a
16+
17+-- | Accept explicit `Maybe` fields as well as undefined-aware partial records.
18+readOptional :: forall @name ty r. IsSymbol name => Record r -> Maybe ty
19+readOptional rec = readOptionalImpl (reflectSymbol (Proxy :: _ name)) rec
20+
21+-- | Read query params from a potentially-partial record.
22+-- | Walks the query params RowList:
23+-- | Maybe ty → read with undefined-awareness (present → Just, absent → Nothing)
24+-- | bare ty → read directly (required, always present)
25+class ReadPartialQuery (rl :: RowList Type) (queryParams :: Row Type) | rl -> queryParams where
26+ readPartialQuery :: forall r. Record r -> Record queryParams
27+
28+instance ReadPartialQuery RL.Nil () where
29+ readPartialQuery _ = {}
30+
31+-- Maybe ty: optional field, may be undefined at runtime
32+instance
33+ ( IsSymbol name
34+ , ReadPartialQuery tail tailQuery
35+ , Row.Cons name (Maybe ty) tailQuery queryParams
36+ , Row.Lacks name tailQuery
37+ ) =>
38+ ReadPartialQuery (RL.Cons name (Maybe ty) tail) queryParams where
39+ readPartialQuery rec = Record.insert (Proxy :: _ name) (readOptional @name rec) rest
40+ where
41+ rest = readPartialQuery @tail rec
42+
43+-- bare ty: required field (from Required query params), always present
44+else instance
45+ ( IsSymbol name
46+ , ReadPartialQuery tail tailQuery
47+ , Row.Cons name ty tailQuery queryParams
48+ , Row.Lacks name tailQuery
49+ ) =>
50+ ReadPartialQuery (RL.Cons name ty tail) queryParams where
51+ readPartialQuery rec = Record.insert (Proxy :: _ name) val rest
52+ where
53+ val = readRequiredField (reflectSymbol (Proxy :: _ name)) rec
54+ rest = readPartialQuery @tail rec
55+
56+foreign import readRequiredField :: forall a r. String -> Record r -> a
src/Yoga/Fetch/Om/Simple.purs+6−21
@@ -32,21 +32,14 @@ import JS.Fetch as Fetch
32import JS.Fetch.Duplex as Duplex
32import JS.Fetch.Duplex as Duplex
33import JS.Fetch.Headers (Headers)
33import JS.Fetch.Headers (Headers)
34import JS.Fetch.Headers as Headers
34import JS.Fetch.Headers as Headers
35−import JS.Fetch.Integrity (Integrity(..))
36−import JS.Fetch.Referrer as Referrer
37−import JS.Fetch.ReferrerPolicy as ReferrerPolicy
38import JS.Fetch.Request as Request
35import JS.Fetch.Request as Request
39import JS.Fetch.RequestBody as Body
36import JS.Fetch.RequestBody as Body
40−import JS.Fetch.RequestCache as Cache
41−import JS.Fetch.RequestCredentials as Credentials
42−import JS.Fetch.RequestMode as Mode
43import JS.Fetch.Response as Resp
37import JS.Fetch.Response as Resp
44import Promise.Aff as Promise
38import Promise.Aff as Promise
45import Type.Row.Homogeneous (class Homogeneous)
39import Type.Row.Homogeneous (class Homogeneous)
46−-- PlainText removed, using local phantom type
47import Yoga.JSON (class ReadForeign, class WriteForeign, readJSON, writeJSON)
40import Yoga.JSON (class ReadForeign, class WriteForeign, readJSON, writeJSON)
48import Yoga.JSON.Error (withStringErrors)
41import Yoga.JSON.Error (withStringErrors)
49−import Yoga.Om (class ToOm, Om, toOm, throw)
42+import Yoga.Om (Om, toOm, throw)
50
43
51type FetchError = { status :: Int, body :: String }
44type FetchError = { status :: Int, body :: String }
52
45
@@ -56,9 +49,7 @@ class DecodeResponse :: forall k. k -> Type -> Constraint
56class DecodeResponse a result | a -> result where
49class DecodeResponse a result | a -> result where
57 decodeResponse :: String -> Either String result
50 decodeResponse :: String -> Either String result
58
51
59−data PlainTextResponse
52+instance DecodeResponse String String where
60−
61−instance DecodeResponse PlainTextResponse String where
62 decodeResponse = Right
53 decodeResponse = Right
63
54
64else instance ReadForeign a => DecodeResponse a a where
55else instance ReadForeign a => DecodeResponse a a where
@@ -102,13 +93,7 @@ simpleFetch method headers url maybeBody = do
102 { method
93 { method
103 , headers: allHeaders
94 , headers: allHeaders
104 , body: reqBody
95 , body: reqBody
105− , credentials: Credentials.SameOrigin
106− , mode: Mode.Cors
107− , referrer: Referrer.ReferrerNone
108− , referrerPolicy: ReferrerPolicy.NoReferrer
109− , integrity: Integrity ""
110 , duplex: Duplex.Half
96 , duplex: Duplex.Half
111− , cache: Cache.Default
112 }
97 }
113
98
114get
99get
@@ -153,7 +138,7 @@ delete_
153 => String
138 => String
154 -> Record headers
139 -> Record headers
155 -> Om ctx (fetchError :: FetchError | err) Unit
140 -> Om ctx (fetchError :: FetchError | err) Unit
156−delete_ url headers = void $ simpleFetch @PlainTextResponse DELETE headers url Nothing
141+delete_ url headers = void $ simpleFetch @String DELETE headers url Nothing
157
142
158post
143post
159 :: forall @a result headers body ctx err
144 :: forall @a result headers body ctx err
@@ -185,7 +170,7 @@ post_
185 -> Record headers
170 -> Record headers
186 -> body
171 -> body
187 -> Om ctx (fetchError :: FetchError | err) Unit
172 -> Om ctx (fetchError :: FetchError | err) Unit
188−post_ url headers body = void $ simpleFetch @PlainTextResponse POST headers url (Just (writeJSON body))
173+post_ url headers body = void $ simpleFetch @String POST headers url (Just (writeJSON body))
189
174
190put
175put
191 :: forall @a result headers body ctx err
176 :: forall @a result headers body ctx err
@@ -217,7 +202,7 @@ put_
217 -> Record headers
202 -> Record headers
218 -> body
203 -> body
219 -> Om ctx (fetchError :: FetchError | err) Unit
204 -> Om ctx (fetchError :: FetchError | err) Unit
220−put_ url headers body = void $ simpleFetch @PlainTextResponse PUT headers url (Just (writeJSON body))
205+put_ url headers body = void $ simpleFetch @String PUT headers url (Just (writeJSON body))
221
206
222patch
207patch
223 :: forall @a result headers body ctx err
208 :: forall @a result headers body ctx err
@@ -249,4 +234,4 @@ patch_
249 -> Record headers
234 -> Record headers
250 -> body
235 -> body
251 -> Om ctx (fetchError :: FetchError | err) Unit
236 -> Om ctx (fetchError :: FetchError | err) Unit
252−patch_ url headers body = void $ simpleFetch @PlainTextResponse PATCH headers url (Just (writeJSON body))
237+patch_ url headers body = void $ simpleFetch @String PATCH headers url (Just (writeJSON body))
src/Yoga/Fetch/Om/SplitResponses.purs+24−2
@@ -1,6 +1,8 @@
1module Yoga.Fetch.Om.SplitResponses
1module Yoga.Fetch.Om.SplitResponses
2 ( class IsSuccessStatus
2 ( class IsSuccessStatus
3+ , class ExtractBodyRL
3 , class ExtractBody
4 , class ExtractBody
5+ , class ClientResponseBody
4 , class SplitResponses
6 , class SplitResponses
5 , class SplitResponsesRL
7 , class SplitResponsesRL
6 , class DispatchResponse
8 , class DispatchResponse
@@ -10,7 +12,10 @@ import Prim.Boolean (True, False)
10import Prim.Row as Row
12import Prim.Row as Row
11import Prim.RowList (RowList)
13import Prim.RowList (RowList)
12import Prim.RowList as RL
14import Prim.RowList as RL
15+import Data.Unit (Unit)
13import Yoga.HTTP.API.Route (Response)
16import Yoga.HTTP.API.Route (Response)
17+import Yoga.HTTP.API.Route.Encoding (PlainText, Streaming)
18+import Yoga.Om.Strom (Strom)
14
19
15class IsSuccessStatus (label :: Symbol) (isSuccess :: Boolean) | label -> isSuccess
20class IsSuccessStatus (label :: Symbol) (isSuccess :: Boolean) | label -> isSuccess
16
21
@@ -26,12 +31,29 @@ else instance IsSuccessStatus "alreadyReported" True
26else instance IsSuccessStatus "imUsed" True
31else instance IsSuccessStatus "imUsed" True
27else instance IsSuccessStatus label False
32else instance IsSuccessStatus label False
28
33
34+-- Traverse a RowList to find the "body" field; fall back to Unit if absent.
35+class ExtractBodyRL (rl :: RowList Type) (body :: Type) | rl -> body
36+
37+instance ExtractBodyRL RL.Nil Unit
38+
39+instance ExtractBodyRL (RL.Cons "body" body tail) body
40+
41+else instance ExtractBodyRL tail body => ExtractBodyRL (RL.Cons label ty tail) body
42+
43+class ClientResponseBody (encoded :: Type) (decoded :: Type) | encoded -> decoded
44+
45+instance ClientResponseBody PlainText String
46+else instance ClientResponseBody (Streaming a) (Strom {} () a)
47+else instance ClientResponseBody body body
48+
29class ExtractBody (responseType :: Type) (bodyType :: Type) | responseType -> bodyType
49class ExtractBody (responseType :: Type) (bodyType :: Type) | responseType -> bodyType
30
50
31−instance ExtractBody (Response headers body) body
51+instance ClientResponseBody encoded body => ExtractBody (Response headers encoded) body
32
52
33else instance
53else instance
34− ( Row.Cons "body" body rest row
54+ ( RL.RowToList row rl
55+ , ExtractBodyRL rl encoded
56+ , ClientResponseBody encoded body
35 ) =>
57 ) =>
36 ExtractBody (Record row) body
58 ExtractBody (Record row) body
37
59
src/Yoga/Fetch/Om/StreamDecode.js+12−1
@@ -1 +1,12 @@
1−export const decodeUtf8 = (uint8array) => new TextDecoder().decode(uint8array);
1+export const newUtf8Decoder = () => new TextDecoder();
2+
3+export const decodeUtf8Chunks = (decoder) => (chunks) => () => {
4+ const decoded = [];
5+ for (const bytes of chunks) {
6+ const text = decoder.decode(bytes, { stream: true });
7+ if (text !== "") decoded.push(text);
8+ }
9+ return decoded;
10+};
11+
12+export const flushUtf8Decoder = (decoder) => () => decoder.decode();
src/Yoga/Fetch/Om/StreamDecode.purs+43−2
@@ -4,7 +4,15 @@ module Yoga.Fetch.Om.StreamDecode
4 ) where
4 ) where
5
5
6import Prelude
6import Prelude
7+
8+import Control.Monad.Rec.Class (Step(..))
9+import Data.Array as Array
7import Data.ArrayBuffer.Types (Uint8Array)
10import Data.ArrayBuffer.Types (Uint8Array)
11+import Data.Maybe (Maybe(..))
12+import Data.Tuple.Nested ((/\))
13+import Effect (Effect)
14+import Effect.Class (liftEffect)
15+import Yoga.Om (Om)
8import Yoga.Om.Strom (Strom)
16import Yoga.Om.Strom (Strom)
9import Yoga.Om.Strom as Strom
17import Yoga.Om.Strom as Strom
10
18
@@ -15,6 +23,39 @@ instance StreamDecode Uint8Array where
15 decodeStream = identity
23 decodeStream = identity
16
24
17else instance StreamDecode String where
25else instance StreamDecode String where
18− decodeStream = Strom.mapStrom decodeUtf8
26+ decodeStream stream =
27+ Strom.fromOm (liftEffect newUtf8Decoder) >>= \decoder ->
28+ decodeUtf8Stream decoder stream
29+
30+data Utf8Decoder
31+
32+foreign import newUtf8Decoder :: Effect Utf8Decoder
33+
34+foreign import decodeUtf8Chunks :: Utf8Decoder -> Array Uint8Array -> Effect (Array String)
35+
36+foreign import flushUtf8Decoder :: Utf8Decoder -> Effect String
37+
38+decodeUtf8Stream :: Utf8Decoder -> Strom {} () Uint8Array -> Strom {} () String
39+decodeUtf8Stream decoder stream = Strom.mkStrom do
40+ step <- Strom.runStrom stream
41+ case step of
42+ Done maybeChunk -> do
43+ decoded <- decodeChunk decoder maybeChunk
44+ trailing <- liftEffect $ flushUtf8Decoder decoder
45+ let
46+ finalChunk =
47+ if trailing == "" then decoded
48+ else Array.snoc decoded trailing
49+ pure $ Done (nonEmpty finalChunk)
50+ Loop (maybeChunk /\ next) -> do
51+ decoded <- decodeChunk decoder maybeChunk
52+ pure $ Loop (nonEmpty decoded /\ decodeUtf8Stream decoder next)
53+
54+decodeChunk :: Utf8Decoder -> Maybe (Array Uint8Array) -> Om {} () (Array String)
55+decodeChunk _ Nothing = pure []
56+decodeChunk decoder (Just chunk) = liftEffect $ decodeUtf8Chunks decoder chunk
19
57
20−foreign import decodeUtf8 :: Uint8Array -> String
58+nonEmpty :: forall a. Array a -> Maybe (Array a)
59+nonEmpty values
60+ | Array.null values = Nothing
61+ | otherwise = Just values
test-compile-fail/cases/ClientBogusSignature.pursnew file+9
@@ -0,0 +1,9 @@
1+module Test.CompileFail.ClientBogusSignature where
2+
3+import Yoga.Fetch.Om (GET, Route, type (/), type (:), client)
4+
5+type GetUserRoute = Route GET ("users" / "id" : Int) {} (ok :: { body :: { id :: Int, name :: String } })
6+type TestAPI = { getUser :: GetUserRoute }
7+
8+wrong :: { getUser :: String -> Int }
9+wrong = client @TestAPI "http://localhost:3000"
test-compile-fail/cases/ClientExtraField.pursnew file+12
@@ -0,0 +1,12 @@
1+module Test.CompileFail.ClientExtraField where
2+
3+import Yoga.Fetch.Om (GET, Route, type (/), type (:), client)
4+import Yoga.Om (Om)
5+
6+type GetUserRoute = Route GET ("users" / "id" : Int) {} (ok :: { body :: { id :: Int, name :: String } })
7+type TestAPI = { getUser :: GetUserRoute }
8+
9+api = client @TestAPI "http://localhost:3000"
10+
11+wrong :: forall ctx err. Om ctx err { id :: Int, name :: String }
12+wrong = api.getUser { id: 42, extra: "oops" }
test-compile-fail/cases/ClientMissingField.pursnew file+12
@@ -0,0 +1,12 @@
1+module Test.CompileFail.ClientMissingField where
2+
3+import Yoga.Fetch.Om (GET, Route, type (/), type (:), client)
4+import Yoga.Om (Om)
5+
6+type GetUserRoute = Route GET ("users" / "id" : Int) {} (ok :: { body :: { id :: Int, name :: String } })
7+type TestAPI = { getUser :: GetUserRoute }
8+
9+api = client @TestAPI "http://localhost:3000"
10+
11+wrong :: forall ctx err. Om ctx err { id :: Int, name :: String }
12+wrong = api.getUser {}
test-compile-fail/cases/ClientNoArgsPassedArg.pursnew file+12
@@ -0,0 +1,12 @@
1+module Test.CompileFail.ClientNoArgsPassedArg where
2+
3+import Yoga.Fetch.Om (GET, Route, client)
4+import Yoga.Om (Om)
5+
6+type HealthRoute = Route GET "health" {} (ok :: { body :: String })
7+type TestAPI = { health :: HealthRoute }
8+
9+api = client @TestAPI "http://localhost:3000"
10+
11+wrong :: forall ctx err. Om ctx err String
12+wrong = api.health "should not accept this"
test-compile-fail/cases/ClientWrongFieldName.pursnew file+12
@@ -0,0 +1,12 @@
1+module Test.CompileFail.ClientWrongFieldName where
2+
3+import Yoga.Fetch.Om (GET, Route, type (/), type (:), client)
4+import Yoga.Om (Om)
5+
6+type GetUserRoute = Route GET ("users" / "id" : Int) {} (ok :: { body :: { id :: Int, name :: String } })
7+type TestAPI = { getUser :: GetUserRoute }
8+
9+api = client @TestAPI "http://localhost:3000"
10+
11+wrong :: forall ctx err. Om ctx err { id :: Int, name :: String }
12+wrong = api.getUser { userId: 42 }
test-compile-fail/cases/ClientWrongFieldType.pursnew file+12
@@ -0,0 +1,12 @@
1+module Test.CompileFail.ClientWrongFieldType where
2+
3+import Yoga.Fetch.Om (GET, Route, type (/), type (:), client)
4+import Yoga.Om (Om)
5+
6+type GetUserRoute = Route GET ("users" / "id" : Int) {} (ok :: { body :: { id :: Int, name :: String } })
7+type TestAPI = { getUser :: GetUserRoute }
8+
9+api = client @TestAPI "http://localhost:3000"
10+
11+wrong :: forall ctx err. Om ctx err { id :: Int, name :: String }
12+wrong = api.getUser { id: "not-an-int" }
test-compile-fail/run.shnew file+26
@@ -0,0 +1,26 @@
1+#!/usr/bin/env bash
2+set -euo pipefail
3+
4+# Compile-fail tests for client derivation type safety.
5+# Each .purs file in cases/ must FAIL to compile.
6+
7+SOURCES=$(bunx spago sources 2>/dev/null | grep -v 'test/')
8+OUTPUT_DIR="output-compile-fail"
9+CASES_DIR="test-compile-fail/cases"
10+PASS=0
11+FAIL=0
12+
13+for f in "$CASES_DIR"/*.purs; do
14+ name=$(basename "$f" .purs)
15+ if bunx purs compile --output "$OUTPUT_DIR" $SOURCES "$f" >/dev/null 2>&1; then
16+ echo "FAIL: $name compiled but should not have"
17+ FAIL=$((FAIL + 1))
18+ else
19+ echo " ok: $name correctly rejected"
20+ PASS=$((PASS + 1))
21+ fi
22+done
23+
24+echo ""
25+echo "$PASS passed, $FAIL failed"
26+[ "$FAIL" -eq 0 ]
test/BodylessResponse.Example.pursnew file+27
@@ -0,0 +1,27 @@
1+-- Compile-time test: bodyless responses (e.g. 304, 401) can use {} without
2+-- wrapping in { body :: {} }.
3+module BodylessResponse.Example where
4+
5+import Prelude
6+
7+import Yoga.Fetch.Om (GET, Route, type (/), client)
8+import Yoga.Om (Om)
9+
10+type Resource = { id :: Int, name :: String }
11+
12+type ResourceAPI =
13+ { getResource ::
14+ Route GET
15+ ("resources" / "id")
16+ {}
17+ ( ok :: { body :: Resource }
18+ , notModified :: {}
19+ , unauthorized :: {}
20+ )
21+ }
22+
23+-- This must typecheck: the derived client exposes notModified/unauthorized as Unit errors.
24+api
25+ :: forall ctx err
26+ . { getResource :: Om (Record ctx) (notModified :: Unit, unauthorized :: Unit | err) Resource }
27+api = client @ResourceAPI "https://api.example.com"
test/BodylessResponse.Spec.pursnew file+125
@@ -0,0 +1,125 @@
1+module BodylessResponse.Spec where
2+
3+import Prelude
4+
5+import Effect.Ref (Ref)
6+import Effect.Ref as Ref
7+import Effect.Aff (Aff, bracket)
8+import Effect.Aff.Class (liftAff)
9+import Effect.Class (liftEffect)
10+import Foreign (unsafeToForeign)
11+import Test.Spec (Spec, around, describe, it)
12+import Test.Spec.Assertions (shouldEqual)
13+import Yoga.Fastify.Fastify as F
14+import Yoga.Fastify.Fastify (Port(..), Host(..), RouteURL(..), StatusCode(..))
15+import Yoga.Fastify.Om (createOmFastify, deleteOm, getOm)
16+import Yoga.Fetch.Om (DELETE, GET, Route, type (/), type (:), client)
17+import Yoga.Om (runOm)
18+
19+type Resource = { id :: Int, name :: String }
20+
21+type ResourceAPI =
22+ { getResource ::
23+ Route GET
24+ ("bodyless-test" / "resource")
25+ {}
26+ ( ok :: { body :: Resource }
27+ , notModified :: {}
28+ , unauthorized :: {}
29+ )
30+ , deleteUser ::
31+ Route DELETE
32+ ("bodyless-test" / "users" / "id" : Int)
33+ {}
34+ ( noContent :: {}
35+ , notFound :: { body :: { error :: String } }
36+ )
37+ }
38+
39+api = client @ResourceAPI "http://localhost:44932"
40+
41+spec :: Spec Unit
42+spec = around withServer $ describe "bodyless responses (notModified / unauthorized)" do
43+ it "304 Not Modified triggers the notModified handler" \serverMode -> do
44+ liftEffect $ Ref.write "notModified" serverMode
45+ triggered <- liftEffect $ Ref.new false
46+ runOm {}
47+ { exception: \_ -> pure unit
48+ , notModified: \_ -> liftEffect $ Ref.write true triggered
49+ , unauthorized: \_ -> pure unit
50+ }
51+ (void api.getResource)
52+ result <- liftEffect $ Ref.read triggered
53+ liftAff $ result `shouldEqual` true
54+
55+ it "401 Unauthorized triggers the unauthorized handler" \serverMode -> do
56+ liftEffect $ Ref.write "unauthorized" serverMode
57+ triggered <- liftEffect $ Ref.new false
58+ runOm {}
59+ { exception: \_ -> pure unit
60+ , notModified: \_ -> pure unit
61+ , unauthorized: \_ -> liftEffect $ Ref.write true triggered
62+ }
63+ (void api.getResource)
64+ result <- liftEffect $ Ref.read triggered
65+ liftAff $ result `shouldEqual` true
66+
67+ it "200 OK returns the resource body" \serverMode -> do
68+ liftEffect $ Ref.write "ok" serverMode
69+ resource <- runOm {}
70+ { exception: \_ -> pure { id: -1, name: "" }
71+ , notModified: \_ -> pure { id: -1, name: "" }
72+ , unauthorized: \_ -> pure { id: -1, name: "" }
73+ }
74+ api.getResource
75+ liftAff $ resource `shouldEqual` { id: 1, name: "test" }
76+
77+ it "204 No Content returns Unit for noContent shorthand" \serverMode -> do
78+ liftEffect $ Ref.write "deleted" serverMode
79+ result <- runOm {}
80+ { exception: \_ -> pure false
81+ , notFound: \_ -> pure false
82+ }
83+ (api.deleteUser { id: 1 } $> true)
84+ liftAff $ result `shouldEqual` true
85+
86+withServer :: forall a. (Ref String -> Aff a) -> Aff a
87+withServer test = bracket acquire release (\{ serverMode } -> test serverMode)
88+ where
89+ acquire = do
90+ serverMode <- liftEffect $ Ref.new "ok"
91+ fastify <- liftEffect do
92+ f <- F.fastify {}
93+ omApp <- createOmFastify {} f
94+ getOm (RouteURL "/bodyless-test/resource") (handler serverMode) omApp
95+ deleteOm (RouteURL "/bodyless-test/users/:id") (deleteHandler serverMode) omApp
96+ pure f
97+ void $ F.listen { port: Port 44932, host: Host "0.0.0.0" } fastify
98+ pure { fastify, serverMode }
99+
100+ release { fastify } = F.close fastify
101+
102+ handler serverMode reply = do
103+ mode <- liftEffect $ Ref.read serverMode
104+ case mode of
105+ "notModified" -> do
106+ void $ F.status (StatusCode 304) reply # liftEffect
107+ F.send (unsafeToForeign "") reply # liftAff
108+ "unauthorized" -> do
109+ void $ F.status (StatusCode 401) reply # liftEffect
110+ F.send (unsafeToForeign "") reply # liftAff
111+ _ -> do
112+ void $ F.status (StatusCode 200) reply # liftEffect
113+ void $ F.header "content-type" "application/json" reply # liftEffect
114+ F.sendJson (unsafeToForeign { id: 1, name: "test" }) reply # liftAff
115+
116+ deleteHandler serverMode reply = do
117+ mode <- liftEffect $ Ref.read serverMode
118+ case mode of
119+ "deleted" -> do
120+ void $ F.status (StatusCode 204) reply # liftEffect
121+ F.send (unsafeToForeign "") reply # liftAff
122+ _ -> do
123+ void $ F.status (StatusCode 404) reply # liftEffect
124+ void $ F.header "content-type" "application/json" reply # liftEffect
125+ F.sendJson (unsafeToForeign { error: "Missing user" }) reply # liftAff
test/BuildUrl.Spec.purs+74−6
@@ -6,6 +6,7 @@ import Data.Maybe (Maybe(..))
6import Test.Spec (Spec, describe, it)
6import Test.Spec (Spec, describe, it)
7import Test.Spec.Assertions (shouldEqual)
7import Test.Spec.Assertions (shouldEqual)
8import Type.Proxy (Proxy(..))
8import Type.Proxy (Proxy(..))
9+import Unsafe.Coerce (unsafeCoerce)
9import Yoga.Fetch.Om.BuildUrl (buildUrl, substitutePathParams, appendQueryParams)
10import Yoga.Fetch.Om.BuildUrl (buildUrl, substitutePathParams, appendQueryParams)
10import Yoga.HTTP.API.Path (Path, type (/), type (:))
11import Yoga.HTTP.API.Path (Path, type (/), type (:))
11
12
@@ -33,6 +34,19 @@ spec = do
33 { slug: "hello-world" }
34 { slug: "hello-world" }
34 "/posts/:slug"
35 "/posts/:slug"
35 result `shouldEqual` "/posts/hello-world"
36 result `shouldEqual` "/posts/hello-world"
37+ it "URL-encodes reserved characters in path params" do
38+ let
39+ result = substitutePathParams @(slug :: String)
40+ { slug: "a/b c?d#e" }
41+ "/users/:slug"
42+ result `shouldEqual` "/users/a%2Fb%20c%3Fd%23e"
43+
44+ it "distinguishes path param names with shared prefixes" do
45+ let
46+ result = substitutePathParams @(id :: Int, id2 :: Int)
47+ { id: 1, id2: 2 }
48+ "/pairs/:id/:id2"
49+ result `shouldEqual` "/pairs/1/2"
36
50
37 it "handles empty params" do
51 it "handles empty params" do
38 let result = substitutePathParams @() {} "/users"
52 let result = substitutePathParams @() {} "/users"
@@ -50,24 +64,32 @@ spec = do
50 "/users"
64 "/users"
51 result `shouldEqual` "/users?limit=10&offset=20"
65 result `shouldEqual` "/users?limit=10&offset=20"
52
66
53− it "handles Maybe params - Just" do
67+ it "handles optional params - provided via partial record" do
54 let
68 let
55 result = appendQueryParams @(limit :: Maybe Int)
69 result = appendQueryParams @(limit :: Maybe Int)
56− { limit: Just 10 }
70+ (unsafeCoerce { limit: 10 } :: Record (limit :: Maybe Int))
57 "/users"
71 "/users"
58 result `shouldEqual` "/users?limit=10"
72 result `shouldEqual` "/users?limit=10"
59
73
60− it "handles Maybe params - Nothing" do
74+ it "serializes a present explicit Maybe query param" do
75+ let result = appendQueryParams @(id :: Maybe Int) { id: Just 42 } "/users"
76+ result `shouldEqual` "/users?id=42"
77+
78+ it "omits an explicit Nothing query param" do
79+ let result = appendQueryParams @(id :: Maybe Int) { id: Nothing } "/users"
80+ result `shouldEqual` "/users"
81+
82+ it "handles optional params - omitted via partial record" do
61 let
83 let
62 result = appendQueryParams @(limit :: Maybe Int)
84 result = appendQueryParams @(limit :: Maybe Int)
63− { limit: Nothing }
85+ (unsafeCoerce {} :: Record (limit :: Maybe Int))
64 "/users"
86 "/users"
65 result `shouldEqual` "/users"
87 result `shouldEqual` "/users"
66
88
67− it "handles mixed Maybe and required params" do
89+ it "handles mixed optional and required params" do
68 let
90 let
69 result = appendQueryParams @(limit :: Maybe Int, offset :: Int)
91 result = appendQueryParams @(limit :: Maybe Int, offset :: Int)
70− { limit: Nothing, offset: 20 }
92+ (unsafeCoerce { offset: 20 } :: Record (limit :: Maybe Int, offset :: Int))
71 "/users"
93 "/users"
72 result `shouldEqual` "/users?offset=20"
94 result `shouldEqual` "/users?offset=20"
73
95
@@ -78,6 +100,34 @@ spec = do
78 it "URL-encodes special characters in values" do
100 it "URL-encodes special characters in values" do
79 let result = appendQueryParams @(search :: String) { search: "hello world&more=yes" } "/users"
101 let result = appendQueryParams @(search :: String) { search: "hello world&more=yes" } "/users"
80 result `shouldEqual` "/users?search=hello%20world%26more%3Dyes"
102 result `shouldEqual` "/users?search=hello%20world%26more%3Dyes"
103+ it "appends query params to an existing query string" do
104+ let result = appendQueryParams @(search :: String) { search: "new value" } "/users?token=old"
105+ result `shouldEqual` "/users?token=old&search=new%20value"
106+
107+ it "inserts query params before a URL fragment" do
108+ let result = appendQueryParams @(search :: String) { search: "new value" } "/users#details"
109+ result `shouldEqual` "/users?search=new%20value#details"
110+
111+ it "repeats Array query params one pair per element" do
112+ let
113+ result = appendQueryParams @(categories :: Array Int)
114+ { categories: [ 3030, 103130 ] }
115+ "/users"
116+ result `shouldEqual` "/users?categories=3030&categories=103130"
117+
118+ it "omits empty Array query params" do
119+ let
120+ result = appendQueryParams @(categories :: Array Int)
121+ { categories: [] }
122+ "/users"
123+ result `shouldEqual` "/users"
124+
125+ it "mixes Array and bare query params" do
126+ let
127+ result = appendQueryParams @(query :: String, categories :: Array Int)
128+ { query: "foo", categories: [ 1, 2 ] }
129+ "/users"
130+ result `shouldEqual` "/users?categories=1&categories=2&query=foo"
81
131
82 describe "buildUrl" do
132 describe "buildUrl" do
83 it "builds URL with path params only" do
133 it "builds URL with path params only" do
@@ -97,3 +147,21 @@ spec = do
97 {}
147 {}
98 { limit: 10, offset: 20 }
148 { limit: 10, offset: 20 }
99 result `shouldEqual` "https://api.example.com/users?limit=10&offset=20"
149 result `shouldEqual` "https://api.example.com/users?limit=10&offset=20"
150+
151+ it "appends route paths before base URL query strings and fragments" do
152+ let
153+ result = buildUrl
154+ "https://api.example.com/base/?token=old#details"
155+ (Proxy :: _ (Path "users"))
156+ {}
157+ { search: "new value" }
158+ result `shouldEqual` "https://api.example.com/base/users?token=old&search=new%20value#details"
159+
160+ it "does not substitute path captures inside a base URL query string" do
161+ let
162+ result = buildUrl
163+ "https://api.example.com?redirect=/:id#details"
164+ (Proxy :: _ (Path ("users" / "id" : Int)))
165+ { id: 42 }
166+ {}
167+ result `shouldEqual` "https://api.example.com/users/42?redirect=/:id#details"
test/BuildUrlProperty.Spec.pursnew file+256
@@ -0,0 +1,256 @@
1+module BuildUrlProperty.Spec where
2+
3+import Prelude
4+
5+import Data.Array as Array
6+import Data.Array.NonEmpty as NEA
7+import Data.Enum (toEnum)
8+import Data.Foldable (all)
9+import Data.Maybe (Maybe(..), fromJust, isJust)
10+import Data.String as String
11+import Data.String.CodeUnits as CodeUnits
12+import Data.String.Gen (genAsciiString)
13+import Data.String.CodePoints (CodePoint, fromCodePointArray)
14+import Data.String.Pattern (Pattern(..))
15+import JSURI (decodeURIComponent)
16+import Test.QuickCheck ((<?>), (===))
17+import Test.QuickCheck.Arbitrary (arbitrary)
18+import Test.QuickCheck.Gen (Gen, arrayOf1, chooseInt)
19+import Test.Spec (Spec, describe, it)
20+import Test.Spec.Assertions (shouldEqual)
21+import Test.Spec.QuickCheck (quickCheck)
22+import Partial.Unsafe (unsafePartial)
23+import Unsafe.Coerce (unsafeCoerce)
24+import Yoga.Fetch.Om.BuildUrl (appendQueryParams, substitutePathParams)
25+
26+spec :: Spec Unit
27+spec = describe "URL properties" do
28+ it "never substitutes path captures in the query or fragment" $ quickCheck do
29+ value <- (genAsciiString :: Gen String)
30+ let
31+ suffix = "?next=/:slug#/:slug"
32+ result = substitutePathParams @(slug :: String)
33+ { slug: value }
34+ ("/items/:slug" <> suffix)
35+ property = case String.stripSuffix (Pattern suffix) result of
36+ Nothing -> false
37+ Just path -> not $ String.contains (Pattern ":slug") path
38+ pure $ property <?> "unexpected path substitution result: " <> show result
39+
40+ it "round-trips percent-encoded path and query values" $ quickCheck do
41+ value <- (genAsciiString :: Gen String)
42+ let
43+ pathResult = substitutePathParams @(value :: String)
44+ { value }
45+ "/items/:value"
46+ queryResult = appendQueryParams @(value :: String)
47+ { value }
48+ "/items"
49+ property = case
50+ String.stripPrefix (Pattern "/items/") pathResult,
51+ String.stripPrefix (Pattern "/items?value=") queryResult
52+ of
53+ Just encodedPath, Just encodedQuery ->
54+ decodeURIComponent encodedPath == Just value
55+ && decodeURIComponent encodedQuery == Just value
56+ _, _ -> false
57+ pure $ property <?> "failed to round-trip value " <> show value
58+
59+ it "preserves existing query values and fragments" $ quickCheck do
60+ existing <- (genAsciiString :: Gen String)
61+ added <- (genAsciiString :: Gen String)
62+ let
63+ base = appendQueryParams @(token :: String)
64+ { token: existing }
65+ "/items#details"
66+ result = appendQueryParams @(search :: String)
67+ { search: added }
68+ base
69+ property = do
70+ withoutFragment <- String.stripSuffix (Pattern "#details") result
71+ query <- String.stripPrefix (Pattern "/items?token=") withoutFragment
72+ case String.split (Pattern "&search=") query of
73+ [ encodedExisting, encodedAdded ] ->
74+ pure
75+ $ decodeURIComponent encodedExisting == Just existing
76+ && decodeURIComponent encodedAdded == Just added
77+ _ -> Nothing
78+ pure
79+ $ (property == Just true)
80+ <?> "query or fragment changed unexpectedly: " <> show result
81+
82+ it "preserves repeated query parameter order and multiplicity" $ quickCheck do
83+ values <- arbitrary
84+ let
85+ result = appendQueryParams @(tag :: Array Int) { tag: values } "/items"
86+ expected = case values of
87+ [] -> "/items"
88+ _ -> "/items?" <> String.joinWith "&" (map (\value -> "tag=" <> show value) values)
89+ pure $ result === expected
90+
91+ it "normalizes absent, Nothing, and Just optional fields" $ quickCheck do
92+ missing <- arbitrary
93+ value <- arbitrary
94+ let
95+ params :: Record (id :: Maybe Int)
96+ params = if missing then unsafeCoerce {} else { id: value }
97+ result = appendQueryParams @(id :: Maybe Int) params "/items"
98+ expected = case missing, value of
99+ true, _ -> "/items"
100+ false, Nothing -> "/items"
101+ false, Just id -> "/items?id=" <> show id
102+ pure $ result === expected
103+
104+ it "never introduces malformed query separators" $ quickCheck do
105+ value <- arbitrary
106+ let
107+ bases =
108+ [ "/items"
109+ , "/items?existing=1"
110+ , "/items?"
111+ , "/items?existing=1&"
112+ , "/items#details"
113+ , "/items?existing=1#details"
114+ , "/items?#details"
115+ , "/items?existing=1&#details"
116+ ]
117+ results = map (appendQueryParams @(id :: Int) { id: value }) bases
118+ pure
119+ $ all isWellFormed results
120+ <?> "malformed URL generated from " <> show results
121+
122+ it "preserves repeated existing query keys" $ quickCheck do
123+ first <- (arbitrary :: Gen Int)
124+ second <- (arbitrary :: Gen Int)
125+ page <- (arbitrary :: Gen Int)
126+ let
127+ base = "/items?id=" <> show first <> "&id=" <> show second <> "#details"
128+ result = appendQueryParams @(page :: Int) { page } base
129+ expected =
130+ "/items?id=" <> show first <> "&id=" <> show second
131+ <> "&page="
132+ <> show page
133+ <> "#details"
134+ pure $ result === expected
135+
136+ it "appends duplicate query values without coalescing existing ones" $ quickCheck do
137+ first <- (arbitrary :: Gen Int)
138+ second <- (arbitrary :: Gen Int)
139+ added <- (arbitrary :: Gen (Array Int))
140+ let
141+ base = "/items?id=" <> show first <> "&id=" <> show second
142+ result = appendQueryParams @(id :: Array Int) { id: added } base
143+ expected = case added of
144+ [] -> base
145+ _ -> base <> "&" <> String.joinWith "&" (map (\value -> "id=" <> show value) added)
146+ pure $ result === expected
147+
148+ it "ignores query-looking text inside fragments" $ quickCheck do
149+ value <- (arbitrary :: Gen Int)
150+ let
151+ rendered = show (value :: Int)
152+ cases =
153+ [ { base: "/items#section?fake=1", expected: "/items?id=" <> rendered <> "#section?fake=1" }
154+ , { base: "/items?real=1#section?fake=1", expected: "/items?real=1&id=" <> rendered <> "#section?fake=1" }
155+ , { base: "/items#?fake=1&other=2", expected: "/items?id=" <> rendered <> "#?fake=1&other=2" }
156+ , { base: "/items#first#second?fake=1", expected: "/items?id=" <> rendered <> "#first#second?fake=1" }
157+ ]
158+ property = all
159+ (\entry -> appendQueryParams @(id :: Int) { id: value } entry.base == entry.expected)
160+ cases
161+ pure $ property <?> "fragment handling failed for id " <> rendered
162+
163+ it "encodes every query delimiter inside values" $ quickCheck do
164+ prefix <- (genAsciiString :: Gen String)
165+ suffix <- (genAsciiString :: Gen String)
166+ let
167+ value = prefix <> "?#&=%+ /" <> suffix
168+ result = appendQueryParams @(value :: String) { value } "/items"
169+ property = case String.stripPrefix (Pattern "/items?value=") result of
170+ Nothing -> false
171+ Just encoded ->
172+ decodeURIComponent encoded == Just value
173+ && all
174+ (\delimiter -> not $ String.contains (Pattern delimiter) encoded)
175+ [ "?", "#", "&", "=", "+", "/" ]
176+ && String.contains (Pattern "%25") encoded
177+ pure $ property <?> "delimiter encoding failed: " <> show result
178+
179+ it "substitutes repeated captures without matching overlapping names" $ quickCheck do
180+ id <- (arbitrary :: Gen Int)
181+ id2 <- (arbitrary :: Gen Int)
182+ let
183+ result = substitutePathParams @(id :: Int, id2 :: Int)
184+ { id, id2 }
185+ "/:id/:id/:id2/:id20?next=/:id#/:id2"
186+ expected =
187+ "/" <> show id <> "/" <> show id <> "/" <> show id2
188+ <> "/:id20?next=/:id#/:id2"
189+ pure $ result === expected
190+
191+ it "normalizes lone UTF-16 surrogates before percent-encoding" do
192+ let
193+ value = codeUnit 0xD800 <> "x" <> codeUnit 0xDFFF
194+ result = appendQueryParams @(value :: String) { value } "/items"
195+ result `shouldEqual` "/items?value=%EF%BF%BDx%EF%BF%BD"
196+
197+ it "percent-encodes arbitrary UTF-16 strings without throwing" $ quickCheck do
198+ value <- (arbitrary :: Gen String)
199+ let
200+ pathResult = substitutePathParams @(value :: String) { value } "/items/:value"
201+ queryResult = appendQueryParams @(value :: String) { value } "/items"
202+ property =
203+ isJust (String.stripPrefix (Pattern "/items/") pathResult)
204+ && isJust (String.stripPrefix (Pattern "/items?value=") queryResult)
205+ pure $ property <?> "encoding failed for UTF-16 input " <> show value
206+
207+ it "round-trips valid non-ASCII scalar values" $ quickCheck do
208+ value <- unicodeScalarString
209+ let
210+ pathResult = substitutePathParams @(value :: String) { value } "/items/:value"
211+ queryResult = appendQueryParams @(value :: String) { value } "/items"
212+ property = case
213+ String.stripPrefix (Pattern "/items/") pathResult,
214+ String.stripPrefix (Pattern "/items?value=") queryResult
215+ of
216+ Just encodedPath, Just encodedQuery ->
217+ decodeURIComponent encodedPath == Just value
218+ && decodeURIComponent encodedQuery == Just value
219+ _, _ -> false
220+ pure $ property <?> "Unicode round-trip failed for " <> show value
221+
222+isWellFormed :: String -> Boolean
223+isWellFormed url =
224+ occurrences "?" url == 1
225+ && occurrences "#" url <= 1
226+ && not (String.contains (Pattern "??") url)
227+ && not (String.contains (Pattern "&&") url)
228+ && not (String.contains (Pattern "?#") url)
229+ && not (String.contains (Pattern "&#") url)
230+ && queryPrecedesFragment url
231+
232+queryPrecedesFragment :: String -> Boolean
233+queryPrecedesFragment url = case String.indexOf (Pattern "#") url of
234+ Nothing -> true
235+ Just fragmentIndex -> case String.indexOf (Pattern "?") url of
236+ Nothing -> false
237+ Just queryIndex -> queryIndex < fragmentIndex
238+
239+occurrences :: String -> String -> Int
240+occurrences needle = (_ - 1) <<< Array.length <<< String.split (Pattern needle)
241+
242+unicodeScalarString :: Gen String
243+unicodeScalarString =
244+ fromCodePointArray <<< NEA.toArray <$> arrayOf1 unicodeScalar
245+
246+unicodeScalar :: Gen CodePoint
247+unicodeScalar = do
248+ useBasicMultilingualPlane <- arbitrary
249+ value <- if useBasicMultilingualPlane then
250+ chooseInt 0x80 0xD7FF
251+ else
252+ chooseInt 0xE000 0x10FFFF
253+ pure $ unsafePartial $ fromJust $ toEnum value
254+
255+codeUnit :: Int -> String
256+codeUnit value = CodeUnits.singleton $ unsafePartial $ fromJust $ toEnum value
test/Complete.Example.purs+17−31
@@ -3,9 +3,10 @@ module Complete.Example where
3import Prelude
3import Prelude
4
4
5import Data.Array (length)
5import Data.Array (length)
6−import Data.Maybe (Maybe(..))
6+import Justifill (justifill)
7import Effect.Class.Console (log)
7import Effect.Class.Console (log)
8−import Yoga.Fetch.Om (GET, POST, PUT, DELETE, Route, JSON, Path, type (/), type (:), type (:?), client)
8+import Yoga.Fetch.Om (GET, POST, PUT, DELETE, Route, JSON, type (/), type (:), type (:?), client)
9+import Yoga.HTTP.API.Route (BearerToken(..))
9import Yoga.Om (Om, handleErrors)
10import Yoga.Om (Om, handleErrors)
10
11
11type User =
12type User =
@@ -30,59 +31,43 @@ type ErrorMessage =
30
31
31type UserAPI =
32type UserAPI =
32 { getUser ::
33 { getUser ::
33− Route GET
34+ Route GET ("users" / "id" : Int)
34− (Path ("users" / "id" : Int))
35 {}
35 {}
36 ( ok :: { body :: User }
36 ( ok :: { body :: User }
37 , notFound :: { body :: ErrorMessage }
37 , notFound :: { body :: ErrorMessage }
38 )
38 )
39 , listUsers ::
39 , listUsers ::
40− Route GET
40+ Route GET ("users" :? { limit :: Int, offset :: Int })
41− (Path "users" :? { limit :: Int, offset :: Int })
42 {}
41 {}
43 ( ok :: { body :: Array User }
42 ( ok :: { body :: Array User }
44 )
43 )
45 , createUser ::
44 , createUser ::
46− Route POST
45+ Route POST "users"
47− (Path "users")
48 { body :: JSON CreateUserRequest }
46 { body :: JSON CreateUserRequest }
49 ( created :: { body :: User }
47 ( created :: { body :: User }
50 , badRequest :: { body :: ErrorMessage }
48 , badRequest :: { body :: ErrorMessage }
51 )
49 )
52 , updateUser ::
50 , updateUser ::
53− Route PUT
51+ Route PUT ("users" / "id" : Int)
54− (Path ("users" / "id" : Int))
55 { body :: JSON UpdateUserRequest }
52 { body :: JSON UpdateUserRequest }
56 ( ok :: { body :: User }
53 ( ok :: { body :: User }
57 , notFound :: { body :: ErrorMessage }
54 , notFound :: { body :: ErrorMessage }
58 , badRequest :: { body :: ErrorMessage }
55 , badRequest :: { body :: ErrorMessage }
59 )
56 )
60 , deleteUser ::
57 , deleteUser ::
61− Route DELETE
58+ Route DELETE ("users" / "id" : Int)
62− (Path ("users" / "id" : Int))
63 {}
59 {}
64− ( noContent :: { body :: {} }
60+ ( noContent :: {}
65 , notFound :: { body :: ErrorMessage }
61 , notFound :: { body :: ErrorMessage }
66 )
62 )
67 , createUserAuth ::
63 , createUserAuth ::
68− Route POST
64+ Route POST "users"
69− (Path "users")
65+ { headers :: Record (authorization :: BearerToken), body :: JSON CreateUserRequest }
70− { headers :: Record (authorization :: String), body :: JSON CreateUserRequest }
71 ( created :: { body :: User }
66 ( created :: { body :: User }
72 , badRequest :: { body :: ErrorMessage }
67 , badRequest :: { body :: ErrorMessage }
73 )
68 )
74 }
69 }
75
70
76−-- Generated client with polymorphic type annotation
77−api
78− :: forall ctx err
79− . { createUser :: CreateUserRequest -> Om ctx (badRequest :: ErrorMessage | err) User
80− , createUserAuth :: { authorization :: String } -> CreateUserRequest -> Om ctx (badRequest :: ErrorMessage | err) User
81− , deleteUser :: { id :: Int } -> Om ctx (notFound :: ErrorMessage | err) {}
82− , getUser :: { id :: Int } -> Om ctx (notFound :: ErrorMessage | err) User
83− , listUsers :: { limit :: Maybe Int, offset :: Maybe Int } -> Om ctx err (Array User)
84− , updateUser :: { id :: Int } -> UpdateUserRequest -> Om ctx (badRequest :: ErrorMessage, notFound :: ErrorMessage | err) User
85− }
86api = client @UserAPI "https://api.example.com"
71api = client @UserAPI "https://api.example.com"
87
72
88exampleGetUser :: Om {} (notFound :: ErrorMessage) Unit
73exampleGetUser :: Om {} (notFound :: ErrorMessage) Unit
@@ -94,15 +79,15 @@ exampleGetUserHandled :: Om {} () Unit
94exampleGetUserHandled = do
79exampleGetUserHandled = do
95 user <- api.getUser { id: 42 }
80 user <- api.getUser { id: 42 }
96 # handleErrors
81 # handleErrors
97− { notFound: \err -> do
82+ { notFound: \err -> ado
98 log $ "User not found: " <> err.error
83 log $ "User not found: " <> err.error
99− pure { id: 0, name: "unknown", email: "" }
84+ in { id: 0, name: "unknown", email: "" }
100 }
85 }
101 log $ "Found user: " <> user.name
86 log $ "Found user: " <> user.name
102
87
103exampleListUsers :: Om {} () Unit
88exampleListUsers :: Om {} () Unit
104exampleListUsers = do
89exampleListUsers = do
105− users <- api.listUsers { limit: Just 10, offset: Just 0 }
90+ users <- api.listUsers (justifill { limit: 10, offset: 0 })
106 log $ "Found " <> show (length users) <> " users"
91 log $ "Found " <> show (length users) <> " users"
107
92
108exampleCreateUser :: Om {} (badRequest :: ErrorMessage) Unit
93exampleCreateUser :: Om {} (badRequest :: ErrorMessage) Unit
@@ -115,7 +100,8 @@ exampleCreateUser = do
115
100
116exampleUpdateUser :: Om {} (notFound :: ErrorMessage, badRequest :: ErrorMessage) Unit
101exampleUpdateUser :: Om {} (notFound :: ErrorMessage, badRequest :: ErrorMessage) Unit
117exampleUpdateUser = do
102exampleUpdateUser = do
118− user <- api.updateUser { id: 42 }
103+ user <- api.updateUser
104+ { id: 42 }
119 { name: "Alice Updated"
105 { name: "Alice Updated"
120 , email: "alice.new@example.com"
106 , email: "alice.new@example.com"
121 }
107 }
@@ -128,7 +114,7 @@ exampleDeleteUser = do
128
114
129exampleCreateUserAuth :: Om {} (badRequest :: ErrorMessage) Unit
115exampleCreateUserAuth :: Om {} (badRequest :: ErrorMessage) Unit
130exampleCreateUserAuth = do
116exampleCreateUserAuth = do
131− user <- api.createUserAuth { authorization: "Bearer abc123" }
117+ user <- api.createUserAuth { authorization: BearerToken "abc123" }
132 { name: "Alice"
118 { name: "Alice"
133 , email: "alice@example.com"
119 , email: "alice@example.com"
134 }
120 }
test/Example.purs+15−10
@@ -1,45 +1,50 @@
1module Example where
1module Example where
2
2
3−import Yoga.HTTP.API.Route (GET, POST, DELETE, Route)
3+import Yoga.HTTP.API.Route (GET, POST, DELETE, Route, BearerToken)
4import Yoga.HTTP.API.Route.Encoding (JSON)
4import Yoga.HTTP.API.Route.Encoding (JSON)
5import Yoga.HTTP.API.Path (Path, type (/), type (:), type (:?))
5import Yoga.HTTP.API.Path (Path, type (/), type (:), type (:?))
6
6
7−type User = { id :: Int, name :: String, email :: String }
7+type User = { id :: UserId, name :: UserName, email :: UserMail }
8−type CreateUserRequest = { name :: String, email :: String }
8+type CreateUserRequest = { name :: String, email :: UserMail }
9type ErrorMessage = { error :: String }
9type ErrorMessage = { error :: String }
10+newtype UserId = UserId Int
11+newtype UserName = UserName String
12+newtype UserMail = UserMail String
13+newtype Limit = Limit Int
14+newtype Offset = Offset Int
10
15
11type UserAPI =
16type UserAPI =
12 { getUser ::
17 { getUser ::
13 Route GET
18 Route GET
14− (Path ("users" / "id" : Int))
19+ ("users" / "id" : UserId)
15 {}
20 {}
16 ( ok :: { body :: User }
21 ( ok :: { body :: User }
17 , notFound :: { body :: ErrorMessage }
22 , notFound :: { body :: ErrorMessage }
18 )
23 )
19 , listUsers ::
24 , listUsers ::
20 Route GET
25 Route GET
21− (Path "users" :? { limit :: Int, offset :: Int })
26+ ("users" :? { limit :: Limit, offset :: Offset })
22 {}
27 {}
23 ( ok :: { body :: Array User }
28 ( ok :: { body :: Array User }
24 )
29 )
25 , createUser ::
30 , createUser ::
26 Route POST
31 Route POST
27− (Path "users")
32+ "users"
28 { body :: JSON CreateUserRequest }
33 { body :: JSON CreateUserRequest }
29 ( created :: { body :: User }
34 ( created :: { body :: User }
30 , badRequest :: { body :: ErrorMessage }
35 , badRequest :: { body :: ErrorMessage }
31 )
36 )
32 , deleteUser ::
37 , deleteUser ::
33 Route DELETE
38 Route DELETE
34− (Path ("users" / "id" : Int))
39+ ("users" / "id" : UserId)
35 {}
40 {}
36− ( noContent :: { body :: {} }
41+ ( noContent :: {}
37 , notFound :: { body :: ErrorMessage }
42 , notFound :: { body :: ErrorMessage }
38 )
43 )
39 , createUserAuth ::
44 , createUserAuth ::
40 Route POST
45 Route POST
41− (Path "users")
46+ "users"
42− { headers :: Record (authorization :: String), body :: JSON CreateUserRequest }
47+ { headers :: Record (authorization :: BearerToken), body :: JSON CreateUserRequest }
43 ( created :: { body :: User }
48 ( created :: { body :: User }
44 , badRequest :: { body :: ErrorMessage }
49 , badRequest :: { body :: ErrorMessage }
45 )
50 )
test/MakeRequest.Spec.purs+42−19
@@ -2,30 +2,53 @@ module MakeRequest.Spec where
2
2
3import Prelude
3import Prelude
4
4
5+import Data.HTTP.Method as HTTP
6+import Data.Maybe (Maybe(..))
5import Data.Tuple.Nested ((/\))
7import Data.Tuple.Nested ((/\))
6import JS.Fetch.Headers as Headers
8import JS.Fetch.Headers as Headers
7import Prim.RowList as RL
9import Prim.RowList as RL
8import Test.Spec (Spec, describe, it)
10import Test.Spec (Spec, describe, it)
9import Test.Spec.Assertions (shouldEqual, shouldSatisfy)
11import Test.Spec.Assertions (shouldEqual, shouldSatisfy)
10import Type.Proxy (Proxy(..))
12import Type.Proxy (Proxy(..))
11−import Yoga.Fetch.Om (toHeaders)
13+import Yoga.Fetch.Om (FormData, PlainText, QUERY, toHeaders)
14+import Yoga.Fetch.Om.MakeRequest (encodeBody, encodingContentType, httpMethod)
15+import Yoga.HTTP.API.Route (BearerToken(..))
12
16
13spec :: Spec Unit
17spec :: Spec Unit
14−spec = describe "toHeaders" do
18+spec = do
15− it "empty headers produces no entries" do
19+ describe "MakeRequest" do
16− let hdrs = toHeaders (Proxy :: _ RL.Nil) {}
20+ it "maps a QUERY route method imported from the public module" do
17− Headers.toArray hdrs `shouldEqual` []
21+ httpMethod (Proxy :: Proxy QUERY) `shouldEqual` HTTP.QUERY
18−
22+
19− it "single header is included" do
23+ describe "BodyEncoding" do
20− let hdrs = toHeaders (Proxy :: _ (RL.Cons "authorization" String RL.Nil)) { authorization: "Bearer abc123" }
24+ it "sends PlainText request bodies without JSON quoting" do
21− Headers.toArray hdrs `shouldEqual` [ "authorization" /\ "Bearer abc123" ]
25+ encodingContentType (Proxy :: Proxy PlainText) `shouldEqual` "text/plain"
22−
26+ encodeBody @PlainText "hello" `shouldEqual` Just "hello"
23− it "multiple headers are included" do
27+
24− let
28+ it "URL-encodes FormData request bodies" do
25− hdrs = toHeaders
29+ encodingContentType (Proxy :: Proxy (FormData { username :: String })) `shouldEqual` "application/x-www-form-urlencoded"
26− (Proxy :: _ (RL.Cons "authorization" String (RL.Cons "x-custom" String RL.Nil)))
30+ encodeBody @(FormData { username :: String }) { username: "Ada Lovelace" }
27− { authorization: "Bearer abc123", "x-custom": "value" }
31+ `shouldEqual` Just "username=Ada+Lovelace"
28− arr = Headers.toArray hdrs
32+
29− arr `shouldSatisfy` \a ->
33+ describe "toHeaders" do
30− a == [ "authorization" /\ "Bearer abc123", "x-custom" /\ "value" ]
34+ it "empty headers produces no entries" do
31− || a == [ "x-custom" /\ "value", "authorization" /\ "Bearer abc123" ]
35+ let hdrs = toHeaders (Proxy :: _ RL.Nil) {}
36+ Headers.toArray hdrs `shouldEqual` []
37+
38+ it "single header is included" do
39+ let hdrs = toHeaders (Proxy :: _ (RL.Cons "authorization" String RL.Nil)) { authorization: "Bearer abc123" }
40+ Headers.toArray hdrs `shouldEqual` [ "authorization" /\ "Bearer abc123" ]
41+
42+ it "multiple headers are included" do
43+ let
44+ hdrs = toHeaders
45+ (Proxy :: _ (RL.Cons "authorization" String (RL.Cons "x-custom" String RL.Nil)))
46+ { authorization: "Bearer abc123", "x-custom": "value" }
47+ arr = Headers.toArray hdrs
48+ arr `shouldSatisfy` \a ->
49+ a == [ "authorization" /\ "Bearer abc123", "x-custom" /\ "value" ]
50+ || a == [ "x-custom" /\ "value", "authorization" /\ "Bearer abc123" ]
51+
52+ it "typed header values are rendered with HeaderValue" do
53+ let hdrs = toHeaders (Proxy :: _ (RL.Cons "authorization" BearerToken RL.Nil)) { authorization: BearerToken "abc123" }
54+ Headers.toArray hdrs `shouldEqual` [ "authorization" /\ "Bearer abc123" ]
test/PlainTextResponse.Spec.pursnew file+122
@@ -0,0 +1,122 @@
1+module PlainTextResponse.Spec where
2+
3+import Prelude
4+import Data.String as String
5+
6+import Effect.Aff (Aff, bracket)
7+import Effect.Aff.Class (liftAff)
8+import Effect.Class (liftEffect)
9+import Effect.Ref (Ref)
10+import Effect.Exception as Exn
11+import Effect.Ref as Ref
12+import Foreign (unsafeToForeign)
13+import Test.Spec (Spec, around, describe, it)
14+import Test.Spec.Assertions (shouldEqual)
15+import Yoga.Fastify.Fastify as F
16+import Yoga.Fastify.Fastify (Port(..), Host(..), RouteURL(..), StatusCode(..))
17+import Yoga.Fastify.Om (createOmFastify, getOm, postOm)
18+import Yoga.Fetch.Om (GET, POST, Route, type (/), JSON, PlainText, Streaming, client)
19+import Yoga.Fetch.Om.Simple as Simple
20+import Yoga.Om (Om, runOm)
21+import Yoga.Om.Strom (Strom)
22+import Yoga.Om.Strom as Strom
23+
24+type Payload = { value :: Int }
25+type Result = { doubled :: Int }
26+
27+type TestAPI =
28+ { double ::
29+ Route POST
30+ ("plain-text-test" / "double")
31+ { body :: JSON Payload }
32+ ( ok :: { body :: Result }
33+ , badRequest :: { body :: PlainText }
34+ )
35+ , health :: Route GET ("plain-text-test" / "health") {} (ok :: { body :: PlainText })
36+ , stream :: Route GET ("plain-text-test" / "stream") {} (ok :: { body :: Streaming String })
37+ }
38+
39+api
40+ :: forall ctx err
41+ . { double :: Payload -> Om (Record ctx) (badRequest :: String | err) Result
42+ , health :: Om (Record ctx) err String
43+ , stream :: Om (Record ctx) err (Strom {} () String)
44+ }
45+api = client @TestAPI "http://localhost:44933"
46+
47+spec :: Spec Unit
48+spec = around withServer $ describe "String body on error responses" do
49+ it "200 OK decodes the JSON response body" \_ -> do
50+ result <- runOm {}
51+ { exception: \_ -> pure { doubled: -1 }
52+ , badRequest: \_ -> pure { doubled: -1 }
53+ }
54+ (api.double { value: 21 })
55+ liftAff $ result `shouldEqual` { doubled: 42 }
56+
57+ it "400 badRequest delivers the raw text body as a String" \serverMode -> do
58+ liftEffect $ Ref.write "badRequest" serverMode
59+ captured <- liftEffect $ Ref.new ""
60+ runOm {}
61+ { exception: \_ -> pure unit
62+ , badRequest: \b -> liftEffect $ Ref.write b captured
63+ }
64+ (void $ api.double { value: 0 })
65+ body <- liftEffect $ Ref.read captured
66+ liftAff $ body `shouldEqual` "invalid value"
67+
68+ it "Simple.get returns plain text for String responses" \_ -> do
69+ result <- runOm {}
70+ { exception: \e -> pure $ "exception: " <> Exn.message e
71+ , fetchError: \e -> pure $ "fetch error: " <> e.body
72+ }
73+ (Simple.get @String "http://localhost:44933/plain-text-test/health" {})
74+ liftAff $ result `shouldEqual` "healthy"
75+
76+ it "derived PlainText responses decode to String" \_ -> do
77+ result <- runOm {}
78+ { exception: \e -> pure $ "exception: " <> Exn.message e }
79+ api.health
80+ liftAff $ result `shouldEqual` "healthy"
81+
82+ it "derived Streaming responses decode to a usable Strom" \_ -> do
83+ chunks <- runOm {}
84+ { exception: \e -> pure [ "exception: " <> Exn.message e ] }
85+ do
86+ stream <- api.stream
87+ Strom.runCollect stream
88+ liftAff $ String.joinWith "" chunks `shouldEqual` "stream €"
89+
90+withServer :: forall a. (Ref String -> Aff a) -> Aff a
91+withServer test = bracket acquire release (\{ serverMode } -> test serverMode)
92+ where
93+ acquire = do
94+ serverMode <- liftEffect $ Ref.new "ok"
95+ fastify <- liftEffect do
96+ f <- F.fastify {}
97+ omApp <- createOmFastify {} f
98+ postOm (RouteURL "/plain-text-test/double") (handler serverMode) omApp
99+ getOm (RouteURL "/plain-text-test/health") (plainTextHandler "healthy") omApp
100+ getOm (RouteURL "/plain-text-test/stream") (plainTextHandler "stream €") omApp
101+ pure f
102+ void $ F.listen { port: Port 44933, host: Host "0.0.0.0" } fastify
103+ pure { fastify, serverMode }
104+
105+ release { fastify } = F.close fastify
106+
107+ plainTextHandler text reply = do
108+ void $ F.status (StatusCode 200) reply # liftEffect
109+ void $ F.header "content-type" "text/plain" reply # liftEffect
110+ F.send (unsafeToForeign text) reply # liftAff
111+
112+ handler serverMode reply = do
113+ mode <- liftEffect $ Ref.read serverMode
114+ case mode of
115+ "badRequest" -> do
116+ void $ F.status (StatusCode 400) reply # liftEffect
117+ void $ F.header "content-type" "text/plain" reply # liftEffect
118+ F.send (unsafeToForeign "invalid value") reply # liftAff
119+ _ -> do
120+ void $ F.status (StatusCode 200) reply # liftEffect
121+ void $ F.header "content-type" "application/json" reply # liftEffect
122+ F.sendJson (unsafeToForeign { doubled: 42 }) reply # liftAff
test/Polymorphic.Spec.purs+21−19
@@ -12,7 +12,8 @@ import Yoga.Fastify.Fastify (Port(..), Host(..))
12import Yoga.Fastify.Om.API (registerAPI)
12import Yoga.Fastify.Om.API (registerAPI)
13import Yoga.Fastify.Om.Route (Handler, handle, respond)
13import Yoga.Fastify.Om.Route (Handler, handle, respond)
14import Yoga.Fetch.Om (GET, Route, type (/), type (:), client)
14import Yoga.Fetch.Om (GET, Route, type (/), type (:), client)
15−import Yoga.Om (Om, ask, runOm)
15+import Yoga.Om (ask, runOm)
16+import Control.Monad.Error.Class (throwError)
16
17
17type User = { id :: Int, name :: String }
18type User = { id :: Int, name :: String }
18
19
@@ -22,32 +23,33 @@ type TestAPI =
22 { getUser :: GetUserRoute
23 { getUser :: GetUserRoute
23 }
24 }
24
25
25−api :: forall ctx err. { getUser :: { id :: Int } -> Om ctx err User }
26api = client @TestAPI "http://localhost:44931"
26api = client @TestAPI "http://localhost:44931"
27
27
28spec :: Spec Unit
28spec :: Spec Unit
29spec = around withServer $ describe "polymorphic client" do
29spec = around withServer $ describe "polymorphic client" do
30 it "fetches user with { token :: String } context" \_ ->
30 it "fetches user with { token :: String } context" \_ ->
31− runOm { token: "secret123" } { exception: \_ -> pure unit } do
31+ runOm { token: "secret123" } { exception: throwError } do
32− ctx <- ask
32+ { token } <- ask
33− user <- api.getUser { id: 42 }
33+ { name } <- api.getUser { id: 42 }
34− liftAff $ (ctx.token <> ":" <> user.name) `shouldEqual` "secret123:User 42"
34+ liftAff $ (token <> ":" <> name) `shouldEqual` "secret123:User 42"
35
35
36 it "fetches user with { apiKey :: String, userId :: Int } context" \_ ->
36 it "fetches user with { apiKey :: String, userId :: Int } context" \_ ->
37− runOm { apiKey: "mykey", userId: 7 } { exception: \_ -> pure unit } do
37+ runOm { apiKey: "mykey", userId: 7 } { exception: throwError } do
38− ctx <- ask
38+ { apiKey, userId } <- ask
39− user <- api.getUser { id: ctx.userId }
39+ { name } <- api.getUser { id: userId }
40− liftAff $ (ctx.apiKey <> ":" <> user.name) `shouldEqual` "mykey:User 7"
40+ liftAff $ (apiKey <> ":" <> name) `shouldEqual` "mykey:User 7"
41
41
42 it "same api.getUser works in two different contexts" \_ -> do
42 it "same api.getUser works in two different contexts" \_ -> do
43− runOm { token: "tok1" } { exception: \_ -> pure unit } do
43+
44− ctx <- ask
44+ runOm { token: "tok1" } { exception: throwError } do
45− user <- api.getUser { id: 1 }
45+ { token } <- ask
46− liftAff $ (ctx.token <> ":" <> user.name) `shouldEqual` "tok1:User 1"
46+ { name } <- api.getUser { id: 1 }
47− runOm { endpoint: "prod", region: "eu" } { exception: \_ -> pure unit } do
47+ liftAff $ (token <> ":" <> name) `shouldEqual` "tok1:User 1"
48− ctx <- ask
48+
49− user <- api.getUser { id: 2 }
49+ runOm { endpoint: "prod", region: "eu" } { exception: throwError } do
50− liftAff $ (ctx.endpoint <> "-" <> ctx.region <> ":" <> user.name) `shouldEqual` "prod-eu:User 2"
50+ { endpoint, region } <- ask
51+ { name } <- api.getUser { id: 2 }
52+ liftAff $ (endpoint <> "-" <> region <> ":" <> name) `shouldEqual` "prod-eu:User 2"
51
53
52withServer :: forall a. (Unit -> _ a) -> _ a
54withServer :: forall a. (Unit -> _ a) -> _ a
53withServer test = bracket acquire release (\_ -> test unit)
55withServer test = bracket acquire release (\_ -> test unit)
@@ -55,7 +57,7 @@ withServer test = bracket acquire release (\_ -> test unit)
55 acquire = do
57 acquire = do
56 fastify <- liftEffect do
58 fastify <- liftEffect do
57 f <- F.fastify {}
59 f <- F.fastify {}
58− registerAPI { getUser: getUserHandler } f
60+ registerAPI @TestAPI { getUser: getUserHandler } f
59 pure f
61 pure f
60 void $ F.listen { port: Port 44931, host: Host "0.0.0.0" } fastify
62 void $ F.listen { port: Port 44931, host: Host "0.0.0.0" } fastify
61 pure fastify
63 pure fastify
test/Roundtrip.Spec.pursnew file+380
@@ -0,0 +1,380 @@
1+module Roundtrip.Spec where
2+
3+import Prelude
4+
5+import Data.Maybe (Maybe(..))
6+import Effect.Aff (bracket)
7+import Effect.Aff.Class (liftAff)
8+import Effect.Class (liftEffect)
9+import Effect.Ref as Ref
10+import Effect.Exception as Exn
11+import Justifill (justifill)
12+import Test.Spec (Spec, around, describe, it)
13+import Test.Spec.Assertions (shouldEqual)
14+import Yoga.Fastify.Fastify as F
15+import Yoga.Fastify.Fastify (Port(..), Host(..))
16+import Yoga.Fastify.Om.API (registerAPI)
17+import Yoga.Fastify.Om.Route (Handler, handle, respond, reject, BearerToken(..))
18+import Yoga.Fetch.Om (GET, POST, PUT, DELETE, Required, Route, JSON, type (/), type (:), type (:?), client, clientWith)
19+import Yoga.Om (ask, handleErrors, runOm)
20+
21+-- Types
22+
23+type User = { id :: Int, name :: String, email :: String }
24+type CreateUserReq = { name :: String, email :: String }
25+type ErrorMsg = { error :: String }
26+
27+-- Route definitions shared by server and client
28+
29+type GetUserRoute = Route GET
30+ ("users" / "id" : Int)
31+ {}
32+ ( ok :: { body :: User }
33+ , notFound :: { body :: ErrorMsg }
34+ )
35+
36+type ListUsersRoute = Route GET
37+ ("users" :? { limit :: Int, offset :: Int })
38+ {}
39+ (ok :: { body :: Array User })
40+
41+type CreateUserRoute = Route POST
42+ "users"
43+ { body :: JSON CreateUserReq }
44+ ( created :: { body :: User }
45+ , badRequest :: { body :: ErrorMsg }
46+ )
47+
48+type UpdateUserRoute = Route PUT
49+ ("users" / "id" : Int)
50+ { body :: JSON CreateUserReq }
51+ ( ok :: { body :: User }
52+ , notFound :: { body :: ErrorMsg }
53+ )
54+
55+type DeleteUserRoute = Route DELETE
56+ ("users" / "id" : Int)
57+ {}
58+ ( ok :: { body :: {} }
59+ , notFound :: { body :: ErrorMsg }
60+ )
61+
62+type AuthRoute = Route GET
63+ "me"
64+ { headers :: { authorization :: BearerToken } }
65+ ( ok :: { body :: User }
66+ , unauthorized :: { body :: ErrorMsg }
67+ )
68+
69+type SearchRoute = Route GET
70+ ("search" :? { active :: Boolean, minScore :: Number })
71+ {}
72+ (ok :: { body :: { active :: Boolean, minScore :: Number } })
73+
74+type FindByQueryRoute = Route GET
75+ ("find-by-query" :? { id :: Int })
76+ {}
77+ (ok :: { body :: { id :: Int } })
78+
79+type InjectedTenantRoute = Route GET
80+ ("tenant-users" / "id" : Int :? { tenant :: Required String })
81+ { headers :: { authorization :: BearerToken, requestid :: String } }
82+ ( ok :: { body :: User }
83+ , unauthorized :: { body :: ErrorMsg }
84+ )
85+
86+type InjectedAPI =
87+ { getTenantUser :: InjectedTenantRoute
88+ }
89+
90+injectedApi tokenRef =
91+ clientWith @InjectedAPI
92+ { baseUrl: pure "http://localhost:44932"
93+ , provide: do
94+ ctx <- ask
95+ token <- liftEffect $ Ref.read tokenRef
96+ pure
97+ { headers: { authorization: BearerToken token, requestid: ctx.requestid }
98+ , query: { tenant: ctx.tenant }
99+ }
100+ }
101+
102+type API =
103+ { getUser :: GetUserRoute
104+ , listUsers :: ListUsersRoute
105+ , createUser :: CreateUserRoute
106+ , updateUser :: UpdateUserRoute
107+ , deleteUser :: DeleteUserRoute
108+ , me :: AuthRoute
109+ , search :: SearchRoute
110+ , findByQuery :: FindByQueryRoute
111+ }
112+
113+api = client @API "http://localhost:44932"
114+
115+-- Handlers
116+
117+getUserHandler :: Handler GetUserRoute ()
118+getUserHandler = handle do
119+ { path } <- ask
120+ if path.id == 42 then respond @"ok" { id: 42, name: "Alice", email: "alice@test.com" }
121+ else reject @"notFound" { error: "User " <> show path.id <> " not found" }
122+
123+listUsersHandler :: Handler ListUsersRoute ()
124+listUsersHandler = handle do
125+ { query } <- ask
126+ let
127+ users =
128+ [ { id: 1, name: "Alice", email: "a@t.com" }
129+ , { id: 2, name: "Bob", email: "b@t.com" }
130+ , { id: 3, name: "Charlie", email: "c@t.com" }
131+ ]
132+ let
133+ limited = case query.limit of
134+ Just l -> take l users
135+ Nothing -> users
136+ respond @"ok" limited
137+ where
138+ take n xs =
139+ if n <= 0 then []
140+ else case xs of
141+ [] -> []
142+ [ a ] -> [ a ]
143+ [ a, _ ] | n == 1 -> [ a ]
144+ [ a, b ] -> [ a, b ]
145+ _ -> xs
146+
147+createUserHandler :: Handler CreateUserRoute ()
148+createUserHandler = handle do
149+ { body } <- ask
150+ if body.name == "" then reject @"badRequest" { error: "Name required" }
151+ else respond @"created" { id: 99, name: body.name, email: body.email }
152+
153+updateUserHandler :: Handler UpdateUserRoute ()
154+updateUserHandler = handle do
155+ { path, body } <- ask
156+ if path.id /= 42 then reject @"notFound" { error: "Not found" }
157+ else respond @"ok" { id: path.id, name: body.name, email: body.email }
158+
159+deleteUserHandler :: Handler DeleteUserRoute ()
160+deleteUserHandler = handle do
161+ { path } <- ask
162+ if path.id /= 42 then reject @"notFound" { error: "Not found" }
163+ else respond @"ok" {}
164+
165+meHandler :: Handler AuthRoute ()
166+meHandler = handle do
167+ { headers } <- ask
168+ case headers.authorization of
169+ BearerToken "secret" -> respond @"ok" { id: 1, name: "Admin", email: "admin@test.com" }
170+ _ -> reject @"unauthorized" { error: "Invalid token" }
171+
172+searchHandler :: Handler SearchRoute ()
173+searchHandler = handle do
174+ { query } <- ask
175+ let
176+ active = case query.active of
177+ Just a -> a
178+ Nothing -> false
179+ let
180+ minScore = case query.minScore of
181+ Just s -> s
182+ Nothing -> 0.0
183+ respond @"ok" { active, minScore }
184+
185+findByQueryHandler :: Handler FindByQueryRoute ()
186+findByQueryHandler = handle do
187+ { query } <- ask
188+ let
189+ id = case query.id of
190+ Just value -> value
191+ Nothing -> -1
192+ respond @"ok" { id }
193+
194+tenantUserHandler :: Handler InjectedTenantRoute ()
195+tenantUserHandler = handle do
196+ { path, query, headers } <- ask
197+ case headers.authorization of
198+ BearerToken "secret" -> respond @"ok" { id: path.id, name: query.tenant <> ":" <> headers.requestid, email: "tenant@test.com" }
199+ _ -> reject @"unauthorized" { error: "Invalid token" }
200+
201+-- Test suite
202+
203+spec :: Spec Unit
204+spec = around withServer $ describe "server ↔ client roundtrip" do
205+
206+ describe "GET with path params" do
207+ it "returns user for valid id" \_ ->
208+ runOm {} { exception: \_ -> pure unit } do
209+ user <- api.getUser { id: 42 }
210+ # handleErrors { notFound: \e -> pure { id: 0, name: e.error, email: "" } }
211+ liftAff $ user.name `shouldEqual` "Alice"
212+
213+ it "returns notFound for invalid id" \_ ->
214+ runOm {} { exception: \_ -> pure unit } do
215+ user <- api.getUser { id: 999 }
216+ # handleErrors { notFound: \e -> pure { id: 0, name: e.error, email: "" } }
217+ liftAff $ user.name `shouldEqual` "User 999 not found"
218+
219+ describe "GET with query params" do
220+ it "passes query params correctly" \_ ->
221+ runOm {} { exception: \_ -> pure unit } do
222+ users <- api.listUsers (justifill { limit: 1 })
223+ liftAff $ (map _.name users) `shouldEqual` [ "Alice" ]
224+
225+ it "serializes a single explicit Maybe query through the derived client" \_ ->
226+ runOm {} { exception: \_ -> pure unit } do
227+ result <- api.findByQuery { id: Just 42 }
228+ liftAff $ result.id `shouldEqual` 42
229+
230+ it "handles no query params" \_ ->
231+ runOm {} { exception: \_ -> pure unit } do
232+ users <- api.listUsers (justifill {})
233+ liftAff $ (map _.name users) `shouldEqual` [ "Alice", "Bob", "Charlie" ]
234+
235+ describe "POST with JSON body" do
236+ it "sends and receives JSON body" \_ ->
237+ runOm {} { exception: \_ -> pure unit } do
238+ user <- api.createUser { name: "Dave", email: "d@t.com" }
239+ # handleErrors { badRequest: \e -> pure { id: 0, name: e.error, email: "" } }
240+ liftAff do
241+ user.name `shouldEqual` "Dave"
242+ user.email `shouldEqual` "d@t.com"
243+ user.id `shouldEqual` 99
244+
245+ it "rejects with badRequest for empty name" \_ ->
246+ runOm {} { exception: \_ -> pure unit } do
247+ user <- api.createUser { name: "", email: "e@t.com" }
248+ # handleErrors { badRequest: \e -> pure { id: 0, name: e.error, email: "" } }
249+ liftAff $ user.name `shouldEqual` "Name required"
250+
251+ describe "PUT with path params and JSON body" do
252+ it "sends path params and body together" \_ ->
253+ runOm {} { exception: \_ -> pure unit } do
254+ user <-
255+ api.updateUser
256+ { id: 42 }
257+ { name: "Updated", email: "u@t.com" }
258+ # handleErrors { notFound: \e -> pure { id: 0, name: e.error, email: "" } }
259+ liftAff do
260+ user.id `shouldEqual` 42
261+ user.name `shouldEqual` "Updated"
262+
263+ it "supports partial application before the body argument" \_ ->
264+ runOm {} { exception: \_ -> pure unit } do
265+ let update42 = api.updateUser { id: 42 }
266+ user <- update42 { name: "Curried", email: "curried@t.com" }
267+ # handleErrors { notFound: \e -> pure { id: 0, name: e.error, email: "" } }
268+ liftAff do
269+ user.id `shouldEqual` 42
270+ user.name `shouldEqual` "Curried"
271+
272+ describe "DELETE with path params" do
273+ it "deletes successfully" \_ ->
274+ runOm {} { exception: \_ -> pure unit } do
275+ result <- api.deleteUser { id: 42 }
276+ # handleErrors { notFound: \_ -> pure {} }
277+ liftAff $ result `shouldEqual` {}
278+
279+ it "returns notFound for wrong id" \_ ->
280+ runOm {} { exception: \_ -> pure unit } do
281+ result <- api.deleteUser { id: 1 }
282+ # handleErrors { notFound: \_ -> pure {} }
283+ liftAff $ result `shouldEqual` {}
284+
285+ describe "GET with authorization header" do
286+ it "passes bearer token in header" \_ ->
287+ runOm {} { exception: \_ -> pure unit } do
288+ user <- api.me { authorization: BearerToken "secret" }
289+ # handleErrors { unauthorized: \e -> pure { id: 0, name: e.error, email: "" } }
290+ liftAff $ user.name `shouldEqual` "Admin"
291+
292+ it "rejects unauthorized" \_ ->
293+ runOm {} { exception: \_ -> pure unit } do
294+ user <- api.me { authorization: BearerToken "wrong" }
295+ # handleErrors { unauthorized: \e -> pure { id: 0, name: e.error, email: "" } }
296+ liftAff $ user.name `shouldEqual` "Invalid token"
297+
298+ describe "GET with Boolean and Number query params" do
299+ it "passes Boolean and Number query params" \_ ->
300+ runOm {} { exception: \_ -> pure unit } do
301+ result <- api.search (justifill { active: true, minScore: 3.14 })
302+ liftAff do
303+ result.active `shouldEqual` true
304+ result.minScore `shouldEqual` 3.14
305+
306+ it "handles missing optional query params" \_ ->
307+ runOm {} { exception: \_ -> pure unit } do
308+ result <- api.search (justifill {})
309+ liftAff do
310+ result.active `shouldEqual` false
311+ result.minScore `shouldEqual` 0.0
312+
313+ describe "optional query params" do
314+ it "accepts a selected optional query parameter" \_ ->
315+ runOm {} { exception: \_ -> pure unit } do
316+ users <- api.listUsers (justifill { limit: 1 })
317+ liftAff $ (map _.name users) `shouldEqual` [ "Alice" ]
318+
319+ it "accepts all optional query parameters" \_ ->
320+ runOm {} { exception: \_ -> pure unit } do
321+ users <- api.listUsers (justifill { limit: 2, offset: 0 })
322+ liftAff $ (map _.name users) `shouldEqual` [ "Alice", "Bob" ]
323+
324+ it "fills omitted optional query parameters with Nothing" \_ ->
325+ runOm {} { exception: \_ -> pure unit } do
326+ users <- api.listUsers (justifill {})
327+ liftAff $ (map _.name users) `shouldEqual` [ "Alice", "Bob", "Charlie" ]
328+
329+ it "passes selected Boolean query param" \_ ->
330+ runOm {} { exception: \_ -> pure unit } do
331+ result <- api.search (justifill { active: true })
332+ liftAff do
333+ result.active `shouldEqual` true
334+ result.minScore `shouldEqual` 0.0
335+
336+ describe "clientWith injected inputs" do
337+ it "reads provided headers and query params from Om context for each call" \_ -> do
338+ tokenRef <- liftEffect $ Ref.new "secret"
339+ let injected = injectedApi tokenRef
340+ user <- runOm { tenant: "acme", requestid: "req-1" }
341+ { exception: \e -> pure { id: -1, name: Exn.message e, email: "" }
342+ , unauthorized: \e -> pure { id: -2, name: e.error, email: "" }
343+ }
344+ (injected.getTenantUser { id: 7 })
345+ liftAff do
346+ user.id `shouldEqual` 7
347+ user.name `shouldEqual` "acme:req-1"
348+ liftEffect $ Ref.write "wrong" tokenRef
349+ rejected <- runOm { tenant: "acme", requestid: "req-2" }
350+ { exception: \e -> pure { id: -1, name: Exn.message e, email: "" }
351+ , unauthorized: \e -> pure { id: -2, name: e.error, email: "" }
352+ }
353+ (injected.getTenantUser { id: 8 })
354+ liftAff $ rejected.name `shouldEqual` "Invalid token"
355+
356+-- Server setup
357+
358+withServer :: forall a. (Unit -> _ a) -> _ a
359+withServer test = bracket acquire release (\_ -> test unit)
360+ where
361+ acquire = do
362+ fastify <- liftEffect do
363+ f <- F.fastify {}
364+ registerAPI @API
365+ { getUser: getUserHandler
366+ , listUsers: listUsersHandler
367+ , createUser: createUserHandler
368+ , updateUser: updateUserHandler
369+ , deleteUser: deleteUserHandler
370+ , me: meHandler
371+ , search: searchHandler
372+ , findByQuery: findByQueryHandler
373+ }
374+ f
375+ registerAPI @InjectedAPI { getTenantUser: tenantUserHandler } f
376+ pure f
377+ void $ F.listen { port: Port 44932, host: Host "0.0.0.0" } fastify
378+ pure fastify
379+
380+ release = F.close
test/StreamDecode.Spec.jsnew file+1
@@ -0,0 +1 @@
1+export const uint8Array = (values) => new Uint8Array(values);
test/StreamDecode.Spec.pursnew file+32
@@ -0,0 +1,32 @@
1+module StreamDecode.Spec where
2+
3+import Prelude
4+
5+import Data.ArrayBuffer.Types (Uint8Array)
6+import Data.String as String
7+import Effect.Aff (Aff)
8+import Effect.Class (liftEffect)
9+import Effect.Exception (throwException)
10+import Test.Spec (Spec, describe, it)
11+import Test.Spec.Assertions (shouldEqual)
12+import Yoga.Fetch.Om.StreamDecode (decodeStream)
13+import Yoga.Om (Om)
14+import Yoga.Om as Om
15+import Yoga.Om.Strom as Strom
16+
17+foreign import uint8Array :: Array Int -> Uint8Array
18+
19+runOm :: forall a. Om {} () a -> Aff a
20+runOm om = Om.runOm {} { exception: \err -> liftEffect (throwException err) } om
21+
22+spec :: Spec Unit
23+spec = describe "StreamDecode" do
24+ it "preserves UTF-8 code points split across chunks" do
25+ chunks <- runOm $
26+ Strom.fromArray
27+ [ uint8Array [ 0xe2 ]
28+ , uint8Array [ 0x82, 0xac ]
29+ ]
30+ # decodeStream @String
31+ # Strom.runCollect
32+ String.joinWith "" chunks `shouldEqual` "€"