mppx 0.4.8 → 0.4.10

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 (267) hide show
  1. package/CHANGELOG.md +26 -3
  2. package/README.md +13 -13
  3. package/dist/BodyDigest.d.ts.map +1 -1
  4. package/dist/BodyDigest.js.map +1 -1
  5. package/dist/Challenge.d.ts.map +1 -1
  6. package/dist/Challenge.js.map +1 -1
  7. package/dist/Credential.d.ts.map +1 -1
  8. package/dist/Credential.js.map +1 -1
  9. package/dist/Errors.js +64 -67
  10. package/dist/Errors.js.map +1 -1
  11. package/dist/PaymentRequest.d.ts.map +1 -1
  12. package/dist/PaymentRequest.js.map +1 -1
  13. package/dist/Receipt.d.ts.map +1 -1
  14. package/dist/Receipt.js.map +1 -1
  15. package/dist/Store.d.ts +9 -0
  16. package/dist/Store.d.ts.map +1 -1
  17. package/dist/Store.js +17 -0
  18. package/dist/Store.js.map +1 -1
  19. package/dist/cli/account.d.ts.map +1 -1
  20. package/dist/cli/account.js +40 -5
  21. package/dist/cli/account.js.map +1 -1
  22. package/dist/cli/cli.d.ts.map +1 -1
  23. package/dist/cli/cli.js +157 -1
  24. package/dist/cli/cli.js.map +1 -1
  25. package/dist/cli/internal.d.ts.map +1 -1
  26. package/dist/cli/internal.js.map +1 -1
  27. package/dist/cli/plugins/stripe.d.ts.map +1 -1
  28. package/dist/cli/plugins/stripe.js.map +1 -1
  29. package/dist/cli/plugins/tempo.d.ts.map +1 -1
  30. package/dist/cli/plugins/tempo.js +2 -1
  31. package/dist/cli/plugins/tempo.js.map +1 -1
  32. package/dist/cli/utils.d.ts.map +1 -1
  33. package/dist/cli/utils.js.map +1 -1
  34. package/dist/client/internal/Fetch.d.ts +2 -0
  35. package/dist/client/internal/Fetch.d.ts.map +1 -1
  36. package/dist/client/internal/Fetch.js +1 -1
  37. package/dist/client/internal/Fetch.js.map +1 -1
  38. package/dist/discovery/Discovery.d.ts +146 -0
  39. package/dist/discovery/Discovery.d.ts.map +1 -0
  40. package/dist/discovery/Discovery.js +60 -0
  41. package/dist/discovery/Discovery.js.map +1 -0
  42. package/dist/discovery/OpenApi.d.ts +61 -0
  43. package/dist/discovery/OpenApi.d.ts.map +1 -0
  44. package/dist/discovery/OpenApi.js +139 -0
  45. package/dist/discovery/OpenApi.js.map +1 -0
  46. package/dist/discovery/Validate.d.ts +10 -0
  47. package/dist/discovery/Validate.d.ts.map +1 -0
  48. package/dist/discovery/Validate.js +63 -0
  49. package/dist/discovery/Validate.js.map +1 -0
  50. package/dist/discovery/index.d.ts +4 -0
  51. package/dist/discovery/index.d.ts.map +1 -0
  52. package/dist/discovery/index.js +4 -0
  53. package/dist/discovery/index.js.map +1 -0
  54. package/dist/internal/types.d.ts.map +1 -1
  55. package/dist/mcp-sdk/client/McpClient.d.ts.map +1 -1
  56. package/dist/mcp-sdk/client/McpClient.js +1 -1
  57. package/dist/mcp-sdk/client/McpClient.js.map +1 -1
  58. package/dist/mcp-sdk/server/Transport.d.ts.map +1 -1
  59. package/dist/mcp-sdk/server/Transport.js.map +1 -1
  60. package/dist/middlewares/elysia.d.ts +52 -1
  61. package/dist/middlewares/elysia.d.ts.map +1 -1
  62. package/dist/middlewares/elysia.js +17 -0
  63. package/dist/middlewares/elysia.js.map +1 -1
  64. package/dist/middlewares/express.d.ts +13 -1
  65. package/dist/middlewares/express.d.ts.map +1 -1
  66. package/dist/middlewares/express.js +23 -2
  67. package/dist/middlewares/express.js.map +1 -1
  68. package/dist/middlewares/hono.d.ts +19 -1
  69. package/dist/middlewares/hono.d.ts.map +1 -1
  70. package/dist/middlewares/hono.js +51 -0
  71. package/dist/middlewares/hono.js.map +1 -1
  72. package/dist/middlewares/internal/mppx.d.ts +4 -2
  73. package/dist/middlewares/internal/mppx.d.ts.map +1 -1
  74. package/dist/middlewares/internal/mppx.js +10 -3
  75. package/dist/middlewares/internal/mppx.js.map +1 -1
  76. package/dist/middlewares/nextjs.d.ts +11 -0
  77. package/dist/middlewares/nextjs.d.ts.map +1 -1
  78. package/dist/middlewares/nextjs.js +15 -0
  79. package/dist/middlewares/nextjs.js.map +1 -1
  80. package/dist/proxy/Proxy.d.ts +6 -0
  81. package/dist/proxy/Proxy.d.ts.map +1 -1
  82. package/dist/proxy/Proxy.js +56 -80
  83. package/dist/proxy/Proxy.js.map +1 -1
  84. package/dist/proxy/Service.d.ts +16 -23
  85. package/dist/proxy/Service.d.ts.map +1 -1
  86. package/dist/proxy/Service.js +20 -84
  87. package/dist/proxy/Service.js.map +1 -1
  88. package/dist/proxy/internal/Route.js +1 -1
  89. package/dist/proxy/internal/Route.js.map +1 -1
  90. package/dist/proxy/services/anthropic.d.ts.map +1 -1
  91. package/dist/proxy/services/anthropic.js +5 -0
  92. package/dist/proxy/services/anthropic.js.map +1 -1
  93. package/dist/proxy/services/openai.d.ts.map +1 -1
  94. package/dist/proxy/services/openai.js +6 -3
  95. package/dist/proxy/services/openai.js.map +1 -1
  96. package/dist/proxy/services/stripe.d.ts.map +1 -1
  97. package/dist/proxy/services/stripe.js +6 -3
  98. package/dist/proxy/services/stripe.js.map +1 -1
  99. package/dist/server/Mppx.d.ts.map +1 -1
  100. package/dist/server/Mppx.js +35 -17
  101. package/dist/server/Mppx.js.map +1 -1
  102. package/dist/server/Request.d.ts.map +1 -1
  103. package/dist/server/Request.js.map +1 -1
  104. package/dist/stripe/Methods.d.ts.map +1 -1
  105. package/dist/stripe/Methods.js.map +1 -1
  106. package/dist/tempo/Methods.d.ts.map +1 -1
  107. package/dist/tempo/Methods.js.map +1 -1
  108. package/dist/tempo/client/ChannelOps.d.ts.map +1 -1
  109. package/dist/tempo/client/ChannelOps.js.map +1 -1
  110. package/dist/tempo/client/Charge.d.ts.map +1 -1
  111. package/dist/tempo/client/Charge.js.map +1 -1
  112. package/dist/tempo/client/Session.d.ts.map +1 -1
  113. package/dist/tempo/client/Session.js.map +1 -1
  114. package/dist/tempo/client/SessionManager.d.ts.map +1 -1
  115. package/dist/tempo/client/SessionManager.js +1 -1
  116. package/dist/tempo/client/SessionManager.js.map +1 -1
  117. package/dist/tempo/internal/auto-swap.d.ts.map +1 -1
  118. package/dist/tempo/internal/auto-swap.js +1 -1
  119. package/dist/tempo/internal/auto-swap.js.map +1 -1
  120. package/dist/tempo/internal/fee-payer.d.ts.map +1 -1
  121. package/dist/tempo/internal/fee-payer.js +1 -1
  122. package/dist/tempo/internal/fee-payer.js.map +1 -1
  123. package/dist/tempo/server/Charge.d.ts.map +1 -1
  124. package/dist/tempo/server/Charge.js +1 -1
  125. package/dist/tempo/server/Charge.js.map +1 -1
  126. package/dist/tempo/server/Session.d.ts.map +1 -1
  127. package/dist/tempo/server/Session.js +18 -5
  128. package/dist/tempo/server/Session.js.map +1 -1
  129. package/dist/tempo/server/internal/transport.d.ts.map +1 -1
  130. package/dist/tempo/server/internal/transport.js +8 -0
  131. package/dist/tempo/server/internal/transport.js.map +1 -1
  132. package/dist/tempo/session/Chain.d.ts.map +1 -1
  133. package/dist/tempo/session/Chain.js +1 -1
  134. package/dist/tempo/session/Chain.js.map +1 -1
  135. package/dist/tempo/session/ChannelStore.d.ts.map +1 -1
  136. package/dist/tempo/session/ChannelStore.js.map +1 -1
  137. package/dist/tempo/session/Receipt.d.ts.map +1 -1
  138. package/dist/tempo/session/Receipt.js.map +1 -1
  139. package/dist/tempo/session/Sse.d.ts.map +1 -1
  140. package/dist/tempo/session/Sse.js.map +1 -1
  141. package/dist/tempo/session/Voucher.d.ts.map +1 -1
  142. package/dist/tempo/session/Voucher.js.map +1 -1
  143. package/dist/viem/Client.d.ts.map +1 -1
  144. package/dist/viem/Client.js.map +1 -1
  145. package/package.json +6 -1
  146. package/src/BodyDigest.test.ts +1 -1
  147. package/src/BodyDigest.ts +1 -0
  148. package/src/Challenge.fuzz.test.ts +121 -0
  149. package/src/Challenge.test-d.ts +2 -1
  150. package/src/Challenge.test.ts +1 -1
  151. package/src/Challenge.ts +1 -0
  152. package/src/Credential.fuzz.test.ts +62 -0
  153. package/src/Credential.test.ts +1 -1
  154. package/src/Credential.ts +1 -0
  155. package/src/Errors.test.ts +28 -40
  156. package/src/Expires.test.ts +2 -1
  157. package/src/Method.test.ts +1 -1
  158. package/src/PaymentRequest.test.ts +1 -1
  159. package/src/PaymentRequest.ts +1 -0
  160. package/src/Receipt.test.ts +1 -1
  161. package/src/Receipt.ts +1 -0
  162. package/src/Store.test-d.ts +2 -1
  163. package/src/Store.test.ts +57 -7
  164. package/src/Store.ts +25 -0
  165. package/src/cli/account.ts +65 -30
  166. package/src/cli/cli.test.ts +215 -2
  167. package/src/cli/cli.ts +166 -1
  168. package/src/cli/config.test.ts +1 -0
  169. package/src/cli/internal.ts +1 -0
  170. package/src/cli/plugins/stripe.ts +1 -0
  171. package/src/cli/plugins/tempo.ts +4 -1
  172. package/src/cli/utils.ts +1 -0
  173. package/src/client/Mppx.test-d.ts +2 -1
  174. package/src/client/Mppx.test.ts +1 -1
  175. package/src/client/Transport.test.ts +1 -1
  176. package/src/client/internal/Fetch.browser.test.ts +2 -1
  177. package/src/client/internal/Fetch.test-d.ts +2 -1
  178. package/src/client/internal/Fetch.test.ts +3 -1
  179. package/src/client/internal/Fetch.ts +1 -1
  180. package/src/discovery/Discovery.test.ts +152 -0
  181. package/src/discovery/Discovery.ts +72 -0
  182. package/src/discovery/OpenApi.test.ts +425 -0
  183. package/src/discovery/OpenApi.ts +224 -0
  184. package/src/discovery/Validate.test.ts +188 -0
  185. package/src/discovery/Validate.ts +76 -0
  186. package/src/discovery/index.ts +3 -0
  187. package/src/internal/constantTimeEqual.test.ts +2 -1
  188. package/src/internal/types.ts +1 -3
  189. package/src/mcp-sdk/client/McpClient.test-d.ts +2 -1
  190. package/src/mcp-sdk/client/McpClient.test.ts +2 -1
  191. package/src/mcp-sdk/client/McpClient.ts +2 -0
  192. package/src/mcp-sdk/server/Transport.test.ts +2 -1
  193. package/src/mcp-sdk/server/Transport.ts +1 -0
  194. package/src/middlewares/elysia.test.ts +28 -2
  195. package/src/middlewares/elysia.ts +36 -1
  196. package/src/middlewares/express.test.ts +95 -7
  197. package/src/middlewares/express.ts +40 -2
  198. package/src/middlewares/hono.test.ts +28 -6
  199. package/src/middlewares/hono.ts +74 -1
  200. package/src/middlewares/internal/mppx.test.ts +2 -1
  201. package/src/middlewares/internal/mppx.ts +14 -6
  202. package/src/middlewares/nextjs.test.ts +32 -6
  203. package/src/middlewares/nextjs.ts +28 -0
  204. package/src/proxy/Proxy.test.ts +55 -270
  205. package/src/proxy/Proxy.ts +73 -93
  206. package/src/proxy/Service.test.ts +24 -1
  207. package/src/proxy/Service.ts +48 -88
  208. package/src/proxy/internal/Headers.test.ts +2 -1
  209. package/src/proxy/internal/Route.test.ts +9 -1
  210. package/src/proxy/internal/Route.ts +1 -1
  211. package/src/proxy/services/anthropic.test.ts +132 -0
  212. package/src/proxy/services/anthropic.ts +5 -0
  213. package/src/proxy/services/openai.test.ts +2 -1
  214. package/src/proxy/services/openai.ts +6 -4
  215. package/src/proxy/services/stripe.test.ts +132 -0
  216. package/src/proxy/services/stripe.ts +6 -4
  217. package/src/server/Mppx.test-d.ts +1 -1
  218. package/src/server/Mppx.test.ts +194 -1
  219. package/src/server/Mppx.ts +38 -19
  220. package/src/server/NodeListener.test.ts +1 -1
  221. package/src/server/Request.test.ts +2 -1
  222. package/src/server/Request.ts +1 -0
  223. package/src/server/Response.test.ts +2 -1
  224. package/src/server/Transport.test.ts +2 -1
  225. package/src/stripe/Charge.integration.test.ts +1 -1
  226. package/src/stripe/Methods.test.ts +1 -1
  227. package/src/stripe/Methods.ts +1 -0
  228. package/src/stripe/client/Charge.test.ts +2 -1
  229. package/src/stripe/server/Charge.test.ts +2 -1
  230. package/src/tempo/Attribution.test.ts +2 -1
  231. package/src/tempo/Methods.test.ts +1 -1
  232. package/src/tempo/Methods.ts +1 -0
  233. package/src/tempo/client/ChannelOps.test.ts +7 -3
  234. package/src/tempo/client/ChannelOps.ts +1 -0
  235. package/src/tempo/client/Charge.ts +1 -0
  236. package/src/tempo/client/Session.test.ts +6 -2
  237. package/src/tempo/client/Session.ts +1 -0
  238. package/src/tempo/client/SessionManager.test.ts +29 -1
  239. package/src/tempo/client/SessionManager.ts +2 -1
  240. package/src/tempo/internal/auto-swap.test.ts +2 -1
  241. package/src/tempo/internal/auto-swap.ts +1 -0
  242. package/src/tempo/internal/defaults.test.ts +2 -1
  243. package/src/tempo/internal/fee-payer.test.ts +2 -1
  244. package/src/tempo/internal/fee-payer.ts +1 -0
  245. package/src/tempo/server/Charge.test.ts +2 -1
  246. package/src/tempo/server/Charge.ts +1 -0
  247. package/src/tempo/server/Session.test.ts +88 -37
  248. package/src/tempo/server/Session.ts +26 -8
  249. package/src/tempo/server/Sse.test.ts +2 -1
  250. package/src/tempo/server/internal/transport.test.ts +25 -1
  251. package/src/tempo/server/internal/transport.ts +11 -0
  252. package/src/tempo/session/Chain.test.ts +6 -2
  253. package/src/tempo/session/Chain.ts +2 -1
  254. package/src/tempo/session/Channel.test.ts +2 -1
  255. package/src/tempo/session/ChannelStore.test.ts +2 -1
  256. package/src/tempo/session/ChannelStore.ts +1 -0
  257. package/src/tempo/session/Receipt.test.ts +2 -1
  258. package/src/tempo/session/Receipt.ts +1 -0
  259. package/src/tempo/session/Sse.fuzz.test.ts +138 -0
  260. package/src/tempo/session/Sse.test.ts +2 -1
  261. package/src/tempo/session/Sse.ts +1 -0
  262. package/src/tempo/session/Voucher.test.ts +2 -1
  263. package/src/tempo/session/Voucher.ts +1 -0
  264. package/src/viem/Account.test.ts +2 -1
  265. package/src/viem/Client.test.ts +2 -1
  266. package/src/viem/Client.ts +1 -0
  267. package/src/zod.test.ts +147 -0
@@ -1,7 +1,8 @@
1
1
  import { createClient, http } from 'viem'
2
2
  import { privateKeyToAccount } from 'viem/accounts'
3
3
  import { mainnet } from 'viem/chains'
4
- import { describe, expect, test } from 'vitest'
4
+ import { describe, expect, test } from 'vp/test'
5
+
5
6
  import * as Account from './Account.js'
6
7
 
7
8
  const account = privateKeyToAccount(
@@ -3,7 +3,8 @@ import { privateKeyToAccount } from 'viem/accounts'
3
3
  import { signTransaction } from 'viem/actions'
4
4
  import { tempoLocalnet } from 'viem/chains'
5
5
  import { Transaction } from 'viem/tempo'
6
- import { describe, expect, test } from 'vitest'
6
+ import { describe, expect, test } from 'vp/test'
7
+
7
8
  import * as Client from './Client.js'
8
9
 
9
10
  const rpcUrl = { 42: 'https://rpc.example.com', 99: 'https://rpc2.example.com' } as const
@@ -1,5 +1,6 @@
1
1
  import { type Chain, type Client, createClient, http } from 'viem'
2
2
  import { withFeePayer } from 'viem/tempo'
3
+
3
4
  import type { MaybePromise } from '../internal/types.js'
4
5
 
5
6
  export function getResolver(
@@ -0,0 +1,147 @@
1
+ import { describe, expect, test } from 'vp/test'
2
+
3
+ import { address, amount, datetime, hash, period, signature, unwrapOptional, z } from './zod.js'
4
+
5
+ describe('amount', () => {
6
+ test.each([
7
+ { input: '1', expected: true, desc: 'integer' },
8
+ { input: '1000000', expected: true, desc: 'large integer' },
9
+ { input: '1.5', expected: true, desc: 'decimal' },
10
+ { input: '0', expected: true, desc: 'zero' },
11
+ { input: '007', expected: true, desc: 'leading zeros' },
12
+ { input: '-1', expected: false, desc: 'negative number' },
13
+ { input: '', expected: false, desc: 'empty string' },
14
+ { input: 'abc', expected: false, desc: 'alphabetic string' },
15
+ { input: '1.', expected: false, desc: 'trailing decimal point' },
16
+ { input: 123 as unknown as string, expected: false, desc: 'non-string type' },
17
+ ])('$desc ($input) → $expected', ({ input, expected }) => {
18
+ expect(amount().safeParse(input).success).toBe(expected)
19
+ })
20
+ })
21
+
22
+ describe('datetime', () => {
23
+ test.each([
24
+ { input: '2025-01-06T12:00:00Z', expected: true, desc: 'UTC with Z suffix' },
25
+ { input: '2025-01-06T12:00:00.123Z', expected: true, desc: 'fractional seconds' },
26
+ { input: '2025-01-06T12:00:00+05:30', expected: true, desc: 'positive UTC offset' },
27
+ { input: '2025-01-06T12:00:00-08:00', expected: true, desc: 'negative UTC offset' },
28
+ { input: '2025-01-06T12:00:00', expected: false, desc: 'missing timezone' },
29
+ { input: '2025-01-06', expected: false, desc: 'date only, no time' },
30
+ { input: '', expected: false, desc: 'empty string' },
31
+ { input: 'not-a-date', expected: false, desc: 'non-date string' },
32
+ ])('$desc ($input) → $expected', ({ input, expected }) => {
33
+ expect(datetime().safeParse(input).success).toBe(expected)
34
+ })
35
+ })
36
+
37
+ describe('address', () => {
38
+ test.each([
39
+ { input: '0x1234567890abcdef1234567890abcdef12345678', expected: true, desc: 'lowercase hex' },
40
+ { input: '0x1234567890ABCDEF1234567890ABCDEF12345678', expected: true, desc: 'uppercase hex' },
41
+ { input: '0xAbCdEf0123456789AbCdEf0123456789AbCdEf01', expected: true, desc: 'mixed case hex' },
42
+ { input: '0x1234', expected: false, desc: 'too short' },
43
+ {
44
+ input: '0x1234567890abcdef1234567890abcdef1234567890',
45
+ expected: false,
46
+ desc: 'too long (42 hex chars)',
47
+ },
48
+ {
49
+ input: '1234567890abcdef1234567890abcdef12345678',
50
+ expected: false,
51
+ desc: 'missing 0x prefix',
52
+ },
53
+ {
54
+ input: '0xGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG',
55
+ expected: false,
56
+ desc: 'non-hex characters',
57
+ },
58
+ { input: '', expected: false, desc: 'empty string' },
59
+ ])('$desc → $expected', ({ input, expected }) => {
60
+ expect(address().safeParse(input).success).toBe(expected)
61
+ })
62
+ })
63
+
64
+ describe('hash', () => {
65
+ test.each([
66
+ {
67
+ input: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef',
68
+ expected: true,
69
+ desc: 'valid 64 hex chars',
70
+ },
71
+ {
72
+ input: '0xABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890',
73
+ expected: true,
74
+ desc: 'uppercase hex',
75
+ },
76
+ {
77
+ input: '0x1234567890abcdef1234567890abcdef12345678',
78
+ expected: false,
79
+ desc: 'too short (address length)',
80
+ },
81
+ {
82
+ input: '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef00',
83
+ expected: false,
84
+ desc: 'too long (66 hex chars)',
85
+ },
86
+ {
87
+ input: '1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef',
88
+ expected: false,
89
+ desc: 'missing 0x prefix',
90
+ },
91
+ { input: '', expected: false, desc: 'empty string' },
92
+ ])('$desc → $expected', ({ input, expected }) => {
93
+ expect(hash().safeParse(input).success).toBe(expected)
94
+ })
95
+ })
96
+
97
+ describe('period', () => {
98
+ test.each([
99
+ { input: 'day', expected: true, desc: 'day keyword' },
100
+ { input: 'week', expected: true, desc: 'week keyword' },
101
+ { input: 'month', expected: true, desc: 'month keyword' },
102
+ { input: 'year', expected: true, desc: 'year keyword' },
103
+ { input: '3600', expected: true, desc: 'numeric seconds' },
104
+ { input: '', expected: false, desc: 'empty string' },
105
+ { input: 'hourly', expected: false, desc: 'unsupported keyword' },
106
+ { input: 'day1', expected: false, desc: 'keyword with trailing digits' },
107
+ ])('$desc ($input) → $expected', ({ input, expected }) => {
108
+ expect(period().safeParse(input).success).toBe(expected)
109
+ })
110
+ })
111
+
112
+ describe('signature', () => {
113
+ test.each([
114
+ { input: '0xabcdef', expected: true, desc: 'short hex' },
115
+ {
116
+ input:
117
+ '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1b',
118
+ expected: true,
119
+ desc: 'full 65-byte secp256k1 signature',
120
+ },
121
+ { input: '0x', expected: false, desc: 'bare 0x prefix with no data' },
122
+ { input: 'abcdef', expected: false, desc: 'missing 0x prefix' },
123
+ { input: '0xZZZZ', expected: false, desc: 'non-hex characters after 0x' },
124
+ { input: '', expected: false, desc: 'empty string' },
125
+ ])('$desc → $expected', ({ input, expected }) => {
126
+ expect(signature().safeParse(input).success).toBe(expected)
127
+ })
128
+ })
129
+
130
+ describe('unwrapOptional', () => {
131
+ test('unwraps optional string schema to inner type', () => {
132
+ const inner = z.string()
133
+ const result = unwrapOptional(z.optional(inner))
134
+ expect(result).toBe(inner)
135
+ })
136
+
137
+ test('returns non-optional schema unchanged', () => {
138
+ const schema = z.string()
139
+ expect(unwrapOptional(schema)).toBe(schema)
140
+ })
141
+
142
+ test('unwraps optional number schema to inner type', () => {
143
+ const inner = z.number()
144
+ const result = unwrapOptional(z.optional(inner))
145
+ expect(result).toBe(inner)
146
+ })
147
+ })