@sugardarius/anzen 0.1.2 โ†’ 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,5 +1,3 @@
1
- ## [Unreleased yet]
2
-
3
1
  A flexible, framework validation agnostic, type-safe factory for creating Next.JS App Router route handlers.
4
2
 
5
3
  - ๐Ÿ”ง Framework validation agnostic, use a validation library of your choice supporting [Standard Schema](https://standardschema.dev/).
@@ -7,6 +5,7 @@ A flexible, framework validation agnostic, type-safe factory for creating Next.J
7
5
  - ๐Ÿงน Clean and flexible API.
8
6
  - ๐Ÿ”’ Type-safe.
9
7
  - ๐ŸŒฑ Dependency free.
8
+ - ๐Ÿชถ Less than 100kB unpacked.
10
9
 
11
10
  ## Install
12
11
 
@@ -17,10 +16,11 @@ npm i @sugardarius/anzen
17
16
  ## Usage
18
17
 
19
18
  ```tsx
19
+ import { object, string, number } from 'decoders'
20
20
  import { createSafeRouteHandler } from '@sugardarius/anzen'
21
21
  import { auth } from '~/lib/auth'
22
22
 
23
- export const GET = createSafeRouteHandler(
23
+ export const POST = createSafeRouteHandler(
24
24
  {
25
25
  authorize: async ({ req }) => {
26
26
  const session = await auth.getSession(req)
@@ -30,9 +30,13 @@ export const GET = createSafeRouteHandler(
30
30
 
31
31
  return { user: session.user }
32
32
  },
33
+ body: object({
34
+ foo: string,
35
+ bar: number,
36
+ }),
33
37
  },
34
- async ({ auth }, req): Promise<Response> => {
35
- return Response.json({ user: auth.user }, { status: 200 })
38
+ async ({ auth, body }, req): Promise<Response> => {
39
+ return Response.json({ user: auth.user, body }, { status: 200 })
36
40
  }
37
41
  )
38
42
  ```
@@ -44,6 +48,7 @@ The example above shows how to use the factory to authorize your requests.
44
48
  By design the factory is framework validation agnostic ๐ŸŒŸ. When doing your validations you can use whatever you want as framework validation as long as it implements the [Standard Schema](https://github.com/standard-schema/standard-schema) common interface. You can use your favorite validation library like [Zod](https://zod.dev/) or [decoders](https://decoders.cc/).
45
49
 
46
50
  ```tsx
51
+ // (POST) /app/api/races/[id]/route.ts
47
52
  import { z } from 'zod'
48
53
  import { object, string, number } from 'decoders'
49
54
 
@@ -57,8 +62,8 @@ export const POST = createSafeRouteHandler(
57
62
  name: string,
58
63
  }),
59
64
  },
60
- async ({ body }) => {
61
- return Response.json({ body })
65
+ async ({ segments, body }) => {
66
+ return Response.json({ segments, body })
62
67
  }
63
68
  )
64
69
  ```
@@ -73,6 +78,284 @@ If you define an async validation then the route handler will throw an error.
73
78
 
74
79
  Check the API and the available options to configure the factory as you wish.
75
80
 
81
+ ### Base options
82
+
83
+ When creating a safe route handler you can use a bunch of options for helping you achieve different tasks ๐Ÿ‘‡๐Ÿป
84
+
85
+ #### `id?: string`
86
+
87
+ Used for logging in development or when the `debug` option is enabled. You can also use it to add extra logging or monitoring.
88
+ By default the id is set to `[unknown:route:handler]`
89
+
90
+ ```tsx
91
+ export const POST = createSafeRouteHandler(
92
+ {
93
+ id: 'my-safe-route-handler',
94
+ },
95
+ async ({ id }) => {
96
+ return Response.json({ id })
97
+ }
98
+ )
99
+ ```
100
+
101
+ #### `authorize?: AuthFunction<AC>`
102
+
103
+ Function to use to authorize the request. By default it always authorize the request.
104
+
105
+ When returning a response, it will be used as the response for the request. Return a response when the request is not authorized.
106
+
107
+ ```tsx
108
+ import { createSafeRouteHandler } from '@sugardarius/anzen'
109
+ import { auth } from '~/lib/auth'
110
+
111
+ export const GET = createSafeRouteHandler(
112
+ {
113
+ authorize: async ({ req, url }) => {
114
+ console.log('url', url)
115
+ const session = await auth.getSession(req)
116
+ if (!session) {
117
+ return new Response(null, { status: 401 })
118
+ }
119
+
120
+ return { user: session.user }
121
+ },
122
+ },
123
+ async ({ auth, body }, req): Promise<Response> => {
124
+ return Response.json({ user: auth.user }, { status: 200 })
125
+ }
126
+ )
127
+ ```
128
+
129
+ #### `onErrorResponse?: (err: unknown) => Awaitable<Response>`
130
+
131
+ Callback triggered when the request fails.
132
+ By default it returns a simple `500` response and the error is logged into the console.
133
+
134
+ Use it if your handler use custom errors and you want to manage them properly by returning a proper response.
135
+
136
+ You can read more about it under the [Error handling](#error-handling) section.
137
+
138
+ #### `debug?: boolean`
139
+
140
+ Use this options to enable debug mode. It will add logs in the handler to help you debug the request.
141
+
142
+ By default it's set to `false` for production builds.
143
+ In development builds, it will be `true` if `NODE_ENV` is not set to `production`.
144
+
145
+ ```tsx
146
+ import { createSafeRouteHandler } from '@sugardarius/anzen'
147
+
148
+ export const GET = createSafeRouteHandler({ debug: true }, async () => {
149
+ return new Response(null, { status: 200 })
150
+ })
151
+ ```
152
+
153
+ ### Route handler options
154
+
155
+ You can configure route handler options to validation using a validation library dynamic route segments, URL query parameters, request json body or request form data body ๐Ÿ‘‡๐Ÿป
156
+
157
+ #### `segments?: TSegments`
158
+
159
+ [Dynamic route segments](https://nextjs.org/docs/app/building-your-application/routing/route-handlers#dynamic-route-segments) used for the route handler path. By design it will handle if the segments are a `Promise` or not.
160
+
161
+ Please note the expected input is a `StandardSchemaDictionary`.
162
+
163
+ ```tsx
164
+ import { z } from 'zod'
165
+ import { createSafeRouteHandler } from '@sugardarius/anzen'
166
+
167
+ export const GET = createSafeRouteHandler(
168
+ {
169
+ segments: {
170
+ accountId: z.string(),
171
+ projectId: z.string().optional(),
172
+ },
173
+ },
174
+ async ({ segments }) => {
175
+ return Response.json({ segments })
176
+ }
177
+ )
178
+ ```
179
+
180
+ #### `onSegmentsValidationErrorResponse?: OnValidationErrorResponse`
181
+
182
+ Callback triggered when dynamic segments validations returned issues. By default it returns a simple `400` response and issues are logged into the console.
183
+
184
+ ```tsx
185
+ import { z } from 'zod'
186
+ import { createSafeRouteHandler } from '@sugardarius/anzen'
187
+
188
+ export const GET = createSafeRouteHandler(
189
+ {
190
+ segments: {
191
+ accountId: z.string(),
192
+ projectId: z.string().optional(),
193
+ },
194
+ onSegmentsValidationErrorResponse: (issues) => {
195
+ return Response.json({ issues }, { status: 400 })
196
+ },
197
+ },
198
+ async ({ segments }) => {
199
+ return Response.json({ segments })
200
+ }
201
+ )
202
+ ```
203
+
204
+ #### `searchParams?: TSearchParams`
205
+
206
+ Search params used in the route.
207
+
208
+ Please note the expected input is a `StandardSchemaDictionary`.
209
+
210
+ ```tsx
211
+ import { string, numeric, optional } from 'decoders'
212
+ import { createSafeRouteHandler } from '@sugardarius/anzen'
213
+
214
+ export const GET = createSafeRouteHandler(
215
+ {
216
+ searchParams: {
217
+ query: string,
218
+ page: optional(numeric),
219
+ },
220
+ },
221
+ async ({ searchParams }) => {
222
+ return Response.json({ searchParams })
223
+ }
224
+ )
225
+ ```
226
+
227
+ #### `onSearchParamsValidationErrorResponse?: OnValidationErrorResponse`
228
+
229
+ Callback triggered when search params validations returned issues. By default it returns a simple `400` response and issues are logged into the console.
230
+
231
+ ```tsx
232
+ import { string, numeric, optional } from 'decoders'
233
+ import { createSafeRouteHandler } from '@sugardarius/anzen'
234
+
235
+ export const GET = createSafeRouteHandler(
236
+ {
237
+ searchParams: {
238
+ query: string,
239
+ page: optional(numeric),
240
+ },
241
+ onSearchParamsValidationErrorResponse: (issues) => {
242
+ return Response.json({ issues }, { status: 400 })
243
+ },
244
+ },
245
+ async ({ searchParams }) => {
246
+ return Response.json({ searchParams })
247
+ }
248
+ )
249
+ ```
250
+
251
+ #### `body?: TBody`
252
+
253
+ Request body.
254
+
255
+ Returns a `405` response if the request method is not `POST`, 'PUT' or 'PATCH'.
256
+
257
+ Returns a `415`response if the request does not explicitly set the `Content-Type` to `application/json`.
258
+
259
+ Please note the body is parsed as JSON, so it must be a valid JSON object. Body shouldn't be used with `formData` at the same time. They are **exclusive**.
260
+
261
+ Why making the distinction? `formData` is used as a `StandardSchemaDictionary` whereas `body` is used as a `StandardSchemaV1`.
262
+
263
+ ```tsx
264
+ import { z } from 'zod'
265
+ import { createSafeRouteHandler } from '@sugardarius/anzen'
266
+
267
+ export const POST = createSafeRouteHandler(
268
+ {
269
+ body: z.object({
270
+ name: z.string(),
271
+ model: z.string(),
272
+ apiKey: z.string(),
273
+ }),
274
+ },
275
+ async ({ body }) => {
276
+ return Response.json({ body })
277
+ }
278
+ )
279
+ ```
280
+
281
+ #### `onBodyValidationErrorResponse?: OnValidationErrorResponse`
282
+
283
+ Callback triggered when body validation returned issues. By default it returns a simple `400` response and issues are logged into the console.
284
+
285
+ ```tsx
286
+ import { z } from 'zod'
287
+ import { createSafeRouteHandler } from '@sugardarius/anzen'
288
+
289
+ export const POST = createSafeRouteHandler(
290
+ {
291
+ body: z.object({
292
+ name: z.string(),
293
+ model: z.string(),
294
+ apiKey: z.string(),
295
+ }),
296
+ onBodyValidationErrorResponse: (issues) => {
297
+ return Response.json({ issues }, { status: 400 })
298
+ },
299
+ },
300
+ async ({ body }) => {
301
+ return Response.json({ body })
302
+ }
303
+ )
304
+ ```
305
+
306
+ #### `formData?: TFormData`
307
+
308
+ Request form data.
309
+
310
+ Returns a `405` response if the request method is not `POST`, 'PUT' or 'PATCH'.
311
+
312
+ Returns a `415`response if the request does not explicitly set the `Content-Type` to `multipart/form-data` or to `application/x-www-form-urlencoded`.
313
+
314
+ Please note formData shouldn't be used with `body` at the same time. They are **exclusive**.
315
+
316
+ Why making the distinction? `formData` is used as a `StandardSchemaDictionary` whereas `body` is used as a `StandardSchemaV1`.
317
+
318
+ ```tsx
319
+ import { z } from 'zod'
320
+ import { createSafeRouteHandler } from '@sugardarius/anzen'
321
+
322
+ export const POST = createSafeRouteHandler(
323
+ {
324
+ formData: {
325
+ id: z.string(),
326
+ message: z.string(),
327
+ },
328
+ },
329
+ async ({ formData }) => {
330
+ return Response.json({ formData })
331
+ }
332
+ )
333
+ ```
334
+
335
+ #### `onFormDataValidationErrorResponse?: OnValidationErrorResponse`
336
+
337
+ Callback triggered when form data validation returned issues. By default it returns a simple `400` response and issues are logged into the console.
338
+
339
+ ```tsx
340
+ import { z } from 'zod'
341
+ import { createSafeRouteHandler } from '@sugardarius/anzen'
342
+
343
+ export const POST = createSafeRouteHandler(
344
+ {
345
+ formData: {
346
+ id: z.string(),
347
+ message: z.string(),
348
+ },
349
+ onFormDataValidationErrorResponse: (issues) => {
350
+ return Response.json({ issues }, { status: 400 })
351
+ },
352
+ },
353
+ async ({ formData }) => {
354
+ return Response.json({ formData })
355
+ }
356
+ )
357
+ ```
358
+
76
359
  ### Error handling
77
360
 
78
361
  By design the factory will catch any error thrown in the route handler will return a simple response with `500` status.
@@ -80,6 +363,7 @@ By design the factory will catch any error thrown in the route handler will retu
80
363
  You can customize the error response if you want to fine tune error response management.
81
364
 
82
365
  ```tsx
366
+ import { createSafeRouteHandler } from '@sugardarius/anzen'
83
367
  import { HttpError, DbUnknownError } from '~/lib/errors'
84
368
  import { db } from '~/lib/db'
85
369
 
@@ -111,6 +395,19 @@ export const GET = createSafeRouteHandler(
111
395
  )
112
396
  ```
113
397
 
398
+ ### Using the request in the route handler
399
+
400
+ The original `request` is cascaded in the route handler function if you need to access to it.
401
+
402
+ ```tsx
403
+ import { createSafeRouteHandler } from '@sugardarius/anzen'
404
+
405
+ export const GET = createSafeRouteHandler({}, async (ctx, req) => {
406
+ console.log('integrity', req.integrity)
407
+ return new Response(null, { status: 200 })
408
+ })
409
+ ```
410
+
114
411
  ## Fair use note
115
412
 
116
413
  Please note that if you're not using any of the proposed options in `createSafeRouteHandler` it means you're surely don't need it.
@@ -131,6 +428,10 @@ export function GET() {
131
428
 
132
429
  Feel free to open an issue or a PR if you think a relevant option could be added into the factory ๐Ÿ™‚
133
430
 
431
+ ## Requirements
432
+
433
+ The factory `createSafeRouteHandler` requires Next.js `v14` or `v15` and typescript `v5` as peer dependencies.
434
+
134
435
  ## Contributing
135
436
 
136
437
  All contributions are welcome! ๐Ÿ™‚ Feel free to open an issue if you find a bug or create a pull request if you have a feature request.
package/dist/index.d.cts CHANGED
@@ -88,8 +88,7 @@ type BaseOptions<AC extends AuthContext | undefined> = {
88
88
  * ID for the route handler.
89
89
  * Used when logging in development or when `debug` is enabled.
90
90
  *
91
- * You can also use it in the route handler definition to add extra logging
92
- * or monitoring.
91
+ * You can also use it to add extra logging or monitoring.
93
92
  */
94
93
  id?: string;
95
94
  /**
@@ -112,7 +111,7 @@ type BaseOptions<AC extends AuthContext | undefined> = {
112
111
  * Use this options to enable debug mode.
113
112
  * It will add logs in the handler to help you debug the request.
114
113
  *
115
- * By default it's `false` for production builds.
114
+ * By default it's set to `false` for production builds.
116
115
  * In development builds, it will be `true` if `NODE_ENV` is not set to `production`.
117
116
  */
118
117
  debug?: boolean;
@@ -120,7 +119,10 @@ type BaseOptions<AC extends AuthContext | undefined> = {
120
119
  type OnValidationErrorResponse = (issues: readonly StandardSchemaV1.Issue[]) => Awaitable<Response>;
121
120
  type CreateSafeRouteHandlerOptions<AC extends AuthContext | undefined, TSegments extends TSegmentsDict | undefined, TSearchParams extends TSearchParamsDict | undefined, TBody extends TBodySchema | undefined, TFormData extends TFormDataDict | undefined> = {
122
121
  /**
123
- * Dynamic route segments used in the route handler path.
122
+ * Dynamic route segments used for the route handler path.
123
+ * By design it will handler if the segments are a `Promise` or not.
124
+ *
125
+ * Please note the expected input is a `StandardSchemaDictionary`.
124
126
  */
125
127
  segments?: TSegments;
126
128
  /**
@@ -130,6 +132,8 @@ type CreateSafeRouteHandlerOptions<AC extends AuthContext | undefined, TSegments
130
132
  onSegmentsValidationErrorResponse?: OnValidationErrorResponse;
131
133
  /**
132
134
  * Search params used in the route.
135
+ *
136
+ * Please note the expected input is a `StandardSchemaDictionary`.
133
137
  */
134
138
  searchParams?: TSearchParams;
135
139
  /**
@@ -144,7 +148,7 @@ type CreateSafeRouteHandlerOptions<AC extends AuthContext | undefined, TSegments
144
148
  * Returns a `415`response if the request does not explicitly set the `Content-Type` to `application/json`.
145
149
  *
146
150
  * IMPORTANT: The body is parsed as JSON, so it must be a valid JSON object!
147
- * IMPORTANT: body shouldn't be used with `formData` at the same time. They are exclusive.
151
+ * IMPORTANT: Body shouldn't be used with `formData` at the same time. They are exclusive.
148
152
  * Why making the distinction? `formData` is used as a `StandardSchemaDictionary` whereas `body` is used as a `StandardSchemaV1`.
149
153
  */
150
154
  body?: TBody;
@@ -195,14 +199,29 @@ type SafeRouteHandlerContext<AC extends AuthContext | undefined, TSegments exten
195
199
  */
196
200
  readonly url: URL;
197
201
  } & (AC extends AuthContext ? {
202
+ /**
203
+ * Auth context
204
+ */
198
205
  readonly auth: AC;
199
206
  } : EmptyObjectType) & (TSegments extends TSegmentsDict ? {
207
+ /**
208
+ * Validated route dynamic segments
209
+ */
200
210
  readonly segments: UnwrapReadonlyObject<StandardSchemaDictionary.InferOutput<TSegments>>;
201
211
  } : EmptyObjectType) & (TSearchParams extends TSearchParamsDict ? {
212
+ /**
213
+ * Validated search params
214
+ */
202
215
  readonly searchParams: UnwrapReadonlyObject<StandardSchemaDictionary.InferOutput<TSearchParams>>;
203
216
  } : EmptyObjectType) & (TBody extends TBodySchema ? {
217
+ /**
218
+ * Validated request body
219
+ */
204
220
  readonly body: StandardSchemaV1.InferOutput<TBody>;
205
221
  } : EmptyObjectType) & (TFormData extends TFormDataDict ? {
222
+ /**
223
+ * Validated form data
224
+ */
206
225
  readonly formData: UnwrapReadonlyObject<StandardSchemaDictionary.InferOutput<TFormData>>;
207
226
  } : EmptyObjectType);
208
227
  type SafeRouteHandler<AC extends AuthContext | undefined, TSegments extends TSegmentsDict | undefined, TSearchParams extends TSearchParamsDict | undefined, TBody extends TBodySchema | undefined, TFormData extends TFormDataDict | undefined> = (
package/dist/index.d.ts CHANGED
@@ -88,8 +88,7 @@ type BaseOptions<AC extends AuthContext | undefined> = {
88
88
  * ID for the route handler.
89
89
  * Used when logging in development or when `debug` is enabled.
90
90
  *
91
- * You can also use it in the route handler definition to add extra logging
92
- * or monitoring.
91
+ * You can also use it to add extra logging or monitoring.
93
92
  */
94
93
  id?: string;
95
94
  /**
@@ -112,7 +111,7 @@ type BaseOptions<AC extends AuthContext | undefined> = {
112
111
  * Use this options to enable debug mode.
113
112
  * It will add logs in the handler to help you debug the request.
114
113
  *
115
- * By default it's `false` for production builds.
114
+ * By default it's set to `false` for production builds.
116
115
  * In development builds, it will be `true` if `NODE_ENV` is not set to `production`.
117
116
  */
118
117
  debug?: boolean;
@@ -120,7 +119,10 @@ type BaseOptions<AC extends AuthContext | undefined> = {
120
119
  type OnValidationErrorResponse = (issues: readonly StandardSchemaV1.Issue[]) => Awaitable<Response>;
121
120
  type CreateSafeRouteHandlerOptions<AC extends AuthContext | undefined, TSegments extends TSegmentsDict | undefined, TSearchParams extends TSearchParamsDict | undefined, TBody extends TBodySchema | undefined, TFormData extends TFormDataDict | undefined> = {
122
121
  /**
123
- * Dynamic route segments used in the route handler path.
122
+ * Dynamic route segments used for the route handler path.
123
+ * By design it will handler if the segments are a `Promise` or not.
124
+ *
125
+ * Please note the expected input is a `StandardSchemaDictionary`.
124
126
  */
125
127
  segments?: TSegments;
126
128
  /**
@@ -130,6 +132,8 @@ type CreateSafeRouteHandlerOptions<AC extends AuthContext | undefined, TSegments
130
132
  onSegmentsValidationErrorResponse?: OnValidationErrorResponse;
131
133
  /**
132
134
  * Search params used in the route.
135
+ *
136
+ * Please note the expected input is a `StandardSchemaDictionary`.
133
137
  */
134
138
  searchParams?: TSearchParams;
135
139
  /**
@@ -144,7 +148,7 @@ type CreateSafeRouteHandlerOptions<AC extends AuthContext | undefined, TSegments
144
148
  * Returns a `415`response if the request does not explicitly set the `Content-Type` to `application/json`.
145
149
  *
146
150
  * IMPORTANT: The body is parsed as JSON, so it must be a valid JSON object!
147
- * IMPORTANT: body shouldn't be used with `formData` at the same time. They are exclusive.
151
+ * IMPORTANT: Body shouldn't be used with `formData` at the same time. They are exclusive.
148
152
  * Why making the distinction? `formData` is used as a `StandardSchemaDictionary` whereas `body` is used as a `StandardSchemaV1`.
149
153
  */
150
154
  body?: TBody;
@@ -195,14 +199,29 @@ type SafeRouteHandlerContext<AC extends AuthContext | undefined, TSegments exten
195
199
  */
196
200
  readonly url: URL;
197
201
  } & (AC extends AuthContext ? {
202
+ /**
203
+ * Auth context
204
+ */
198
205
  readonly auth: AC;
199
206
  } : EmptyObjectType) & (TSegments extends TSegmentsDict ? {
207
+ /**
208
+ * Validated route dynamic segments
209
+ */
200
210
  readonly segments: UnwrapReadonlyObject<StandardSchemaDictionary.InferOutput<TSegments>>;
201
211
  } : EmptyObjectType) & (TSearchParams extends TSearchParamsDict ? {
212
+ /**
213
+ * Validated search params
214
+ */
202
215
  readonly searchParams: UnwrapReadonlyObject<StandardSchemaDictionary.InferOutput<TSearchParams>>;
203
216
  } : EmptyObjectType) & (TBody extends TBodySchema ? {
217
+ /**
218
+ * Validated request body
219
+ */
204
220
  readonly body: StandardSchemaV1.InferOutput<TBody>;
205
221
  } : EmptyObjectType) & (TFormData extends TFormDataDict ? {
222
+ /**
223
+ * Validated form data
224
+ */
206
225
  readonly formData: UnwrapReadonlyObject<StandardSchemaDictionary.InferOutput<TFormData>>;
207
226
  } : EmptyObjectType);
208
227
  type SafeRouteHandler<AC extends AuthContext | undefined, TSegments extends TSegmentsDict | undefined, TSearchParams extends TSearchParamsDict | undefined, TBody extends TBodySchema | undefined, TFormData extends TFormDataDict | undefined> = (
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sugardarius/anzen",
3
- "version": "0.1.2",
3
+ "version": "1.0.0",
4
4
  "description": "A fast, framework validation agnostic, type-safe factory for creating Next.JS App Router route handlers.",
5
5
  "license": "MIT",
6
6
  "packageManager": "npm@11.3.0",
@@ -67,18 +67,18 @@
67
67
  "typescript": "^5"
68
68
  },
69
69
  "devDependencies": {
70
- "@arethetypeswrong/cli": "^0.17.4",
71
- "@eslint/js": "^9.25.1",
70
+ "@arethetypeswrong/cli": "^0.18.0",
71
+ "@eslint/js": "^9.26.0",
72
72
  "@release-it/keep-a-changelog": "^7.0.0",
73
- "@types/node": "^22.15.3",
74
- "eslint": "^9.25.1",
73
+ "@types/node": "^22.15.17",
74
+ "eslint": "^9.26.0",
75
75
  "prettier": "^3.5.3",
76
76
  "publint": "^0.3.12",
77
- "release-it": "^19.0.1",
77
+ "release-it": "^19.0.2",
78
78
  "tsup": "^8.4.0",
79
- "turbo": "^2.5.2",
79
+ "turbo": "^2.5.3",
80
80
  "typescript": "^5.8.3",
81
- "typescript-eslint": "^8.31.1",
82
- "vitest": "^3.1.2"
81
+ "typescript-eslint": "^8.32.0",
82
+ "vitest": "^3.1.3"
83
83
  }
84
84
  }