hono-takibi 0.9.9991 → 0.9.9993

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/README.md +372 -105
  2. package/dist/config/index.d.ts +253 -245
  3. package/dist/config/index.js +61 -59
  4. package/dist/core/angular-query/index.d.ts +1 -1
  5. package/dist/core/angular-query/index.js +1 -1
  6. package/dist/core/docs/index.d.ts +1 -1
  7. package/dist/core/docs/index.js +1 -1
  8. package/dist/core/preact-query/index.d.ts +1 -1
  9. package/dist/core/preact-query/index.js +1 -1
  10. package/dist/core/rpc/index.d.ts +3 -2
  11. package/dist/core/rpc/index.js +26 -9
  12. package/dist/core/solid-query/index.d.ts +1 -1
  13. package/dist/core/solid-query/index.js +1 -1
  14. package/dist/core/svelte-query/index.d.ts +1 -1
  15. package/dist/core/svelte-query/index.js +1 -1
  16. package/dist/core/swr/index.d.ts +1 -1
  17. package/dist/core/swr/index.js +1 -1
  18. package/dist/core/tanstack-query/index.d.ts +1 -1
  19. package/dist/core/tanstack-query/index.js +1 -1
  20. package/dist/core/type/index.d.ts +1 -1
  21. package/dist/core/type/index.js +3 -2
  22. package/dist/core/vue-query/index.d.ts +1 -1
  23. package/dist/core/vue-query/index.js +2 -4
  24. package/dist/{docs-CSuOwViw.js → docs-nOKRf8eg.js} +1 -1
  25. package/dist/generator/zod-openapi-hono/openapi/index.d.ts +1 -1
  26. package/dist/generator/zod-openapi-hono/openapi/index.js +1 -1
  27. package/dist/{guard-CGdVjfki.js → guard-D6ntlNcR.js} +11 -1
  28. package/dist/{index-BDpZiPrC.d.ts → index-BOXAWTim.d.ts} +105 -8
  29. package/dist/index.js +36 -36
  30. package/dist/{openapi-wpzLwSa_.js → openapi-COY6p6RQ.js} +17 -23
  31. package/dist/{openapi-Bb4UFNO2.js → openapi-XWXCf9Ne.js} +903 -133
  32. package/dist/{query-74e6a3Ys.js → query-BdYoX_G6.js} +191 -203
  33. package/dist/{rpc-0ionzZZB.js → rpc-D48XeCBk.js} +1 -1
  34. package/dist/{utils-aOXRa2YU.js → utils-D2uh73oq.js} +15 -1
  35. package/dist/vite-plugin/index.js +9 -9
  36. package/package.json +9 -9
package/README.md CHANGED
@@ -102,70 +102,6 @@ export const getRoute = createRoute({
102
102
  })
103
103
  ```
104
104
 
105
- ## Custom Validation Error Messages
106
-
107
- Use `x-*` vendor extensions to customize Zod error messages:
108
-
109
- ```yaml
110
- name:
111
- type: string
112
- minLength: 1
113
- x-error-message: 'Name is required'
114
- x-minimum-message: 'Name cannot be empty'
115
- ```
116
-
117
- ```ts
118
- // Generated output
119
- z.string({ error: 'Name is required' }).min(1, { error: 'Name cannot be empty' })
120
- ```
121
-
122
- | Extension | Applies to |
123
- | ----------------------------- | ----------------------------------------------------------------- |
124
- | `x-error-message` | Schema constructor (`z.string()`, `z.number()`, `z.enum()`, etc.) |
125
- | `x-minimum-message` | `.min()`, `.gte()` |
126
- | `x-maximum-message` | `.max()`, `.lte()` |
127
- | `x-size-message` | `.length()` |
128
- | `x-pattern-message` | `.regex()` |
129
- | `x-multipleOf-message` | `.multipleOf()` |
130
- | `x-enum-error-messages` | Per-value enum messages (`{ "value": "message" }`) |
131
- | `x-anyOf-message` | `anyOf` |
132
- | `x-oneOf-message` | `oneOf` |
133
- | `x-not-message` | `not` |
134
- | `x-propertyNames-message` | `propertyNames` |
135
- | `x-dependentRequired-message` | `dependentRequired` |
136
-
137
- ## Branded Types
138
-
139
- Use the `x-brand` vendor extension to generate [Zod branded types](https://zod.dev/api?id=branded-types), creating nominal types that are structurally identical but semantically distinct:
140
-
141
- ```yaml
142
- components:
143
- schemas:
144
- Cat:
145
- type: object
146
- properties:
147
- name:
148
- type: string
149
- required:
150
- - name
151
- x-brand: Cat
152
- Dog:
153
- type: object
154
- properties:
155
- name:
156
- type: string
157
- required:
158
- - name
159
- x-brand: Dog
160
- ```
161
-
162
- ```ts
163
- // Generated output
164
- const CatSchema = z.object({ name: z.string() }).brand<'Cat'>().openapi('Cat')
165
-
166
- const DogSchema = z.object({ name: z.string() }).brand<'Dog'>().openapi('Dog')
167
- ```
168
-
169
105
  ## Vite Plugin
170
106
 
171
107
  Watches your OpenAPI spec and `hono-takibi.config.ts` for changes, then auto-regenerates code on save.
@@ -210,8 +146,6 @@ This generates:
210
146
 
211
147
  Re-running after updating your OpenAPI spec is safe — your hand-written handler logic and test customizations are preserved. Only new routes are added as stubs.
212
148
 
213
- > **Note:** If you remove a path from your OpenAPI spec and re-run, the corresponding handler and test files will be deleted. Make sure to back up or migrate any custom logic before removing API definitions.
214
-
215
149
  ### Handler Generation Modes
216
150
 
217
151
  #### `routeHandler: false` (default)
@@ -274,10 +208,6 @@ Supported: SWR, TanStack Query, Preact Query, Solid Query, Vue Query, Svelte Que
274
208
  ```ts
275
209
  export default defineConfig({
276
210
  input: 'openapi.yaml',
277
- 'zod-openapi': {
278
- output: './src/routes.ts',
279
- exportSchemas: true,
280
- },
281
211
  'tanstack-query': {
282
212
  output: './src/tanstack-query',
283
213
  import: '../client',
@@ -305,9 +235,6 @@ paths:
305
235
  ```ts
306
236
  export default defineConfig({
307
237
  input: 'openapi.yaml',
308
- 'zod-openapi': {
309
- output: './src/routes.ts',
310
- },
311
238
  test: {
312
239
  output: './src/test.ts',
313
240
  import: '../index',
@@ -321,10 +248,6 @@ export default defineConfig({
321
248
  ```ts
322
249
  export default defineConfig({
323
250
  input: 'openapi.yaml',
324
- 'zod-openapi': {
325
- output: './src/routes.ts',
326
- readonly: true,
327
- },
328
251
  mock: {
329
252
  output: './src/mock.ts',
330
253
  },
@@ -338,10 +261,6 @@ Generate API reference Markdown with [hono-cli](https://github.com/honojs/cli) `
338
261
  ```ts
339
262
  export default defineConfig({
340
263
  input: 'openapi.yaml',
341
- 'zod-openapi': {
342
- output: './src/routes.ts',
343
- readonly: true,
344
- },
345
264
  docs: {
346
265
  output: './docs/api.md',
347
266
  entry: 'src/index.ts',
@@ -354,10 +273,6 @@ To generate `curl` commands instead of `hono request`:
354
273
  ```ts
355
274
  export default defineConfig({
356
275
  input: 'openapi.yaml',
357
- 'zod-openapi': {
358
- output: './src/routes.ts',
359
- readonly: true,
360
- },
361
276
  docs: {
362
277
  output: './docs/api.md',
363
278
  curl: true,
@@ -368,10 +283,6 @@ export default defineConfig({
368
283
 
369
284
  ## Full Config Reference
370
285
 
371
- > `split: true` - `output` is a **directory** (many files + `index.ts`).
372
- > `split` omitted or `false` - `output` is a **single `.ts` file**.
373
- > `output` and `routes` are **mutually exclusive** in `zod-openapi`.
374
-
375
286
  ```ts
376
287
  // hono-takibi.config.ts
377
288
  import { defineConfig } from 'hono-takibi/config'
@@ -422,7 +333,14 @@ export default defineConfig({
422
333
  routes: {
423
334
  output: './src/routes',
424
335
  split: true,
425
- import: '@packages/routes', // Custom import path (monorepo support)
336
+ import: '@packages/routes',
337
+ },
338
+
339
+ // Split webhooks into separate files
340
+ webhooks: {
341
+ output: './src/webhooks',
342
+ split: true,
343
+ import: '@packages/webhooks',
426
344
  },
427
345
 
428
346
  // Split components into separate files
@@ -486,11 +404,6 @@ export default defineConfig({
486
404
  split: true,
487
405
  import: '../mediaTypes',
488
406
  },
489
- webhooks: {
490
- output: './src/webhooks',
491
- split: true,
492
- import: '../webhooks',
493
- },
494
407
  },
495
408
  },
496
409
 
@@ -575,22 +488,376 @@ export default defineConfig({
575
488
  })
576
489
  ```
577
490
 
578
- ## Projects Using Hono Takibi
491
+ ## Custom Validation Error Messages
579
492
 
580
- - **[resend-local](https://github.com/y-hiraoka/resend-local)** A local emulator for the Resend email API.
493
+ Use `x-*` vendor extensions to attach custom Zod error messages, with **one extension per JSON Schema keyword** (1:1 mapping). The extension name follows the pattern `x-<jsonSchemaKeyword>-message` (e.g. `x-minLength-message`, `x-pattern-message`), plus four generic forms: `x-error-message`, `x-required-message`, `x-const-message`, `x-enum-message`.
494
+
495
+ ```yaml
496
+ name:
497
+ type: string
498
+ minLength: 1
499
+ maxLength: 50
500
+ x-error-message: 'Name must be a string'
501
+ x-minLength-message: 'Name cannot be empty'
502
+ x-maxLength-message: 'Name must be at most 50 characters'
503
+ ```
581
504
 
582
- ## Limitations
505
+ ```ts
506
+ z.string({ error: 'Name must be a string' })
507
+ .min(1, { error: 'Name cannot be empty' })
508
+ .max(50, { error: 'Name must be at most 50 characters' })
509
+ ```
583
510
 
584
- **This package is in active development and may introduce breaking changes without prior notice.**
511
+ ### Extension Reference
512
+
513
+ All custom message extensions follow the `x-<keyword>-message` naming convention and map directly to Zod validator error messages.
514
+
515
+ #### Common (any schema type)
516
+
517
+ | Extension | Applies to |
518
+ | -------------------- | -------------------------------- |
519
+ | `x-error-message` | All schemas (top-level fallback) |
520
+ | `x-required-message` | Required properties |
521
+ | `x-const-message` | `const` |
522
+ | `x-enum-message` | `enum` |
523
+
524
+ #### Numeric (number / integer)
525
+
526
+ | Extension | Applies to |
527
+ | ---------------------------- | ------------------ |
528
+ | `x-minimum-message` | `minimum` |
529
+ | `x-maximum-message` | `maximum` |
530
+ | `x-exclusiveMinimum-message` | `exclusiveMinimum` |
531
+ | `x-exclusiveMaximum-message` | `exclusiveMaximum` |
532
+ | `x-multipleOf-message` | `multipleOf` |
533
+
534
+ #### String
535
+
536
+ | Extension | Applies to |
537
+ | --------------------- | ------------------------------------------ |
538
+ | `x-minLength-message` | `minLength` |
539
+ | `x-maxLength-message` | `maxLength` |
540
+ | `x-pattern-message` | `pattern` |
541
+ | `x-length-message` | Exact length (`minLength` === `maxLength`) |
542
+
543
+ #### Array
544
+
545
+ | Extension | Applies to |
546
+ | ----------------------- | ------------- |
547
+ | `x-minItems-message` | `minItems` |
548
+ | `x-maxItems-message` | `maxItems` |
549
+ | `x-uniqueItems-message` | `uniqueItems` |
550
+ | `x-contains-message` | `contains` |
551
+ | `x-minContains-message` | `minContains` |
552
+ | `x-maxContains-message` | `maxContains` |
553
+
554
+ #### Object
555
+
556
+ | Extension | Applies to |
557
+ | -------------------------------- | ---------------------- |
558
+ | `x-minProperties-message` | `minProperties` |
559
+ | `x-maxProperties-message` | `maxProperties` |
560
+ | `x-additionalProperties-message` | `additionalProperties` |
561
+ | `x-propertyNames-message` | `propertyNames` |
562
+ | `x-patternProperties-message` | `patternProperties` |
563
+ | `x-dependentRequired-message` | `dependentRequired` |
564
+ | `x-dependentSchemas-message` | `dependentSchemas` |
565
+
566
+ #### Combinators
567
+
568
+ | Extension | Applies to |
569
+ | ----------------- | ---------- |
570
+ | `x-allOf-message` | `allOf` |
571
+ | `x-anyOf-message` | `anyOf` |
572
+ | `x-oneOf-message` | `oneOf` |
573
+ | `x-not-message` | `not` |
574
+
575
+ #### Conditional
576
+
577
+ | Extension | Applies to |
578
+ | ---------------- | ---------- |
579
+ | `x-if-message` | `if` |
580
+ | `x-then-message` | `then` |
581
+ | `x-else-message` | `else` |
582
+
583
+ #### Typeless / Array Applicator
584
+
585
+ | Extension | Applies to |
586
+ | --------------------------------- | ------------------------------- |
587
+ | `x-properties-message` | `properties` (typeless schemas) |
588
+ | `x-prefixItems-message` | `prefixItems` |
589
+ | `x-items-message` | `items` |
590
+ | `x-unevaluatedProperties-message` | `unevaluatedProperties` |
591
+ | `x-unevaluatedItems-message` | `unevaluatedItems` |
592
+
593
+ ## Behavior Extensions
594
+
595
+ ### String Pre-validation Transforms
596
+
597
+ | Extension | Generated | Value |
598
+ | --------------- | ----------------------------- | --------------------------------------- |
599
+ | `x-trim` | `z.string().trim()` | `true` |
600
+ | `x-toLowerCase` | `z.string().toLowerCase()` | `true` |
601
+ | `x-toUpperCase` | `z.string().toUpperCase()` | `true` |
602
+ | `x-normalize` | `z.string().normalize('NFC')` | `'NFC'` / `'NFD'` / `'NFKC'` / `'NFKD'` |
585
603
 
586
- - Not all OpenAPI features are supported
587
- - Some OpenAPI validations may not be perfectly converted to Zod
604
+ ```yaml
605
+ homepage:
606
+ type: string
607
+ format: url
608
+ x-trim: true
609
+ ```
588
610
 
589
- We strongly recommend:
611
+ ```ts
612
+ z.string().trim().pipe(z.url())
613
+ ```
614
+
615
+ ### Preprocess (Input Normalization)
616
+
617
+ #### `x-preprocess`
618
+
619
+ ```yaml
620
+ username:
621
+ type: string
622
+ x-preprocess: 'z.preprocess((val) => typeof val === "string" ? val.trim() : val, z.string())'
623
+ ```
624
+
625
+ ```ts
626
+ z.preprocess((val) => (typeof val === 'string' ? val.trim() : val), z.string())
627
+ ```
628
+
629
+ ### Type Coercion
630
+
631
+ #### `x-coerce`
632
+
633
+ ```yaml
634
+ asNumber:
635
+ type: number
636
+ x-coerce: true
637
+ asDate:
638
+ type: string
639
+ format: date-time
640
+ x-coerce: true
641
+ ```
642
+
643
+ ```ts
644
+ z.coerce.number()
645
+ z.coerce.date()
646
+ ```
647
+
648
+ ### Codec (Bidirectional Transform)
649
+
650
+ #### `x-codec`
651
+
652
+ ```yaml
653
+ updatedAt:
654
+ type: string
655
+ format: date-time
656
+ x-codec: 'z.codec(z.iso.datetime(), z.date(), { decode: (val) => new Date(val), encode: (val) => val.toISOString() })'
657
+ ```
658
+
659
+ ```ts
660
+ z.codec(z.iso.datetime(), z.date(), {
661
+ decode: (val) => new Date(val),
662
+ encode: (val) => val.toISOString(),
663
+ })
664
+ ```
590
665
 
591
- - Pinning to exact versions in production
592
- - Testing thoroughly when updating versions
593
- - Reviewing generated code after updates
666
+ ### Custom Validation
667
+
668
+ #### `x-refine`
669
+
670
+ ```yaml
671
+ password:
672
+ type: string
673
+ x-refine: '.refine((val) => val.length >= 8, { message: "Password must be at least 8 characters" }).refine((val) => /[A-Z]/.test(val), { message: "Password must contain an uppercase letter" })'
674
+ ```
675
+
676
+ ```ts
677
+ z.string()
678
+ .refine((val) => val.length >= 8, { message: 'Password must be at least 8 characters' })
679
+ .refine((val) => /[A-Z]/.test(val), { message: 'Password must contain an uppercase letter' })
680
+ ```
681
+
682
+ #### `x-superRefine`
683
+
684
+ ```yaml
685
+ normalizedEmail:
686
+ type: string
687
+ format: email
688
+ x-superRefine: '.superRefine((val, ctx) => { if (val.endsWith("@blocked.example")) ctx.addIssue({ code: "custom", message: "Blocked domain" }) })'
689
+ ```
690
+
691
+ ```ts
692
+ z.email().superRefine((val, ctx) => {
693
+ if (val.endsWith('@blocked.example')) {
694
+ ctx.addIssue({ code: 'custom', message: 'Blocked domain' })
695
+ }
696
+ })
697
+ ```
698
+
699
+ ### Transform & Pipe
700
+
701
+ #### `x-transform`
702
+
703
+ ```yaml
704
+ code:
705
+ type: string
706
+ x-transform: 'z.string().transform((val) => val.toUpperCase())'
707
+ ```
708
+
709
+ ```ts
710
+ z.string().transform((val) => val.toUpperCase())
711
+ ```
712
+
713
+ #### `x-pipe`
714
+
715
+ ```yaml
716
+ port:
717
+ type: string
718
+ x-pipe: 'z.string().pipe(z.number().int().positive())'
719
+ ```
720
+
721
+ ```ts
722
+ z.string().pipe(z.number().int().positive())
723
+ ```
724
+
725
+ ### Default & Fallback Values
726
+
727
+ #### `x-prefault`
728
+
729
+ ```yaml
730
+ greeting:
731
+ type: string
732
+ x-prefault: 'hello'
733
+ ```
734
+
735
+ ```ts
736
+ z.string().prefault('hello')
737
+ ```
738
+
739
+ #### `x-catch`
740
+
741
+ ```yaml
742
+ retries:
743
+ type: integer
744
+ x-catch: 0
745
+ ```
746
+
747
+ ```ts
748
+ z.int().catch(0)
749
+ ```
750
+
751
+ ### Immutability
752
+
753
+ #### `x-freeze`
754
+
755
+ ```yaml
756
+ config:
757
+ type: object
758
+ properties:
759
+ name:
760
+ type: string
761
+ x-freeze: true
762
+ ```
763
+
764
+ ```ts
765
+ z.object({ name: z.string() }).readonly()
766
+ ```
767
+
768
+ ### String Content Checks
769
+
770
+ #### `x-startsWith` / `x-endsWith` / `x-includes`
771
+
772
+ ```yaml
773
+ url:
774
+ type: string
775
+ x-startsWith: 'https://'
776
+ x-endsWith: '.com'
777
+ path:
778
+ type: string
779
+ x-includes: '/api/'
780
+ ```
781
+
782
+ ```ts
783
+ z.string().startsWith('https://').endsWith('.com')
784
+ z.string().includes('/api/')
785
+ ```
786
+
787
+ ### Format-Specific Options
788
+
789
+ ```yaml
790
+ htmlEmail:
791
+ type: string
792
+ format: email
793
+ x-emailPattern: 'html5' # email pattern preset
794
+ uuidV7:
795
+ type: string
796
+ format: uuid
797
+ x-uuidVersion: v7 # uuid version
798
+ httpsUrl:
799
+ type: string
800
+ format: uri
801
+ x-urlProtocol: '^https$' # url protocol regex
802
+ x-urlNormalize: true
803
+ preciseDatetime:
804
+ type: string
805
+ format: date-time
806
+ x-isoPrecision: 3 # iso datetime precision / offset / local
807
+ x-isoOffset: true
808
+ ```
809
+
810
+ | Extension | Maps to | Values |
811
+ | ---------------- | ------------------------------- | -------------------------------- |
812
+ | `x-emailPattern` | `z.email({ pattern })` | `html5` / `browser` / `unicode` |
813
+ | `x-emailRegex` | `z.email({ pattern: /.../ })` | custom regex string |
814
+ | `x-uuidVersion` | `z.uuid({ version })` | `v1` / `v4` / `v6` / `v7` / `v8` |
815
+ | `x-urlProtocol` | `z.url({ protocol: /.../ })` | regex string |
816
+ | `x-urlHostname` | `z.url({ hostname: /.../ })` | regex string |
817
+ | `x-urlNormalize` | `z.url({ normalize })` | `true` / `false` |
818
+ | `x-isoPrecision` | `z.iso.datetime({ precision })` | fractional second digits |
819
+ | `x-isoOffset` | `z.iso.datetime({ offset })` | `true` / `false` |
820
+ | `x-isoLocal` | `z.iso.datetime({ local })` | `true` / `false` |
821
+ | `x-macDelimiter` | `z.mac({ delimiter })` | `:` / `-` / `.` |
822
+ | `x-jwtAlg` | `z.jwt({ alg })` | `HS256` etc. |
823
+ | `x-hashAlg` | `z.hash(alg, ...)` | `sha256` etc. |
824
+ | `x-hashEnc` | `z.hash(alg, { enc })` | `hex` / `base64` / `base64url` |
825
+
826
+ ## Branded Types
827
+
828
+ Use the `x-brand` vendor extension to generate [Zod branded types](https://zod.dev/api?id=branded-types), creating nominal types that are structurally identical but semantically distinct:
829
+
830
+ ```yaml
831
+ components:
832
+ schemas:
833
+ Cat:
834
+ type: object
835
+ properties:
836
+ name:
837
+ type: string
838
+ required:
839
+ - name
840
+ x-brand: Cat
841
+ Dog:
842
+ type: object
843
+ properties:
844
+ name:
845
+ type: string
846
+ required:
847
+ - name
848
+ x-brand: Dog
849
+ ```
850
+
851
+ ```ts
852
+ // Generated output
853
+ const CatSchema = z.object({ name: z.string() }).brand<'Cat'>().openapi('Cat')
854
+
855
+ const DogSchema = z.object({ name: z.string() }).brand<'Dog'>().openapi('Dog')
856
+ ```
857
+
858
+ ## Projects Using Hono Takibi
859
+
860
+ - **[resend-local](https://github.com/y-hiraoka/resend-local)** — A local emulator for the Resend email API.
594
861
 
595
862
  ## Contributing
596
863